This subsection describes the implementation of the AVC. The include/linux/flask/avc.h header file contains the inline AVC functions that are called by the kernel object managers. The kernel/avc.c source file contains the rest of the implementation of the AVC.
The avc_init interface is implemented in avc.c. This function allocates memory for all of the cache entries using kmalloc and adds them to an internal free list. This function also allocates a page of memory using __get_free_page to use as a buffer for the fs/dcache.c:d_path function when creating pathnames for audit records.
Both avc_has_perm_ref_audit and avc_notify_perm_ref are implemented as inline functions in avc.h. Each of these two functions disables interrupts locally and takes a single global spin lock (avc_lock) on entry using spin_lock_irqsave, and each function uses spin_unlock_irqrestore before returning. The avc_lock is released before calling security_compute_av and reacquired upon the return from that call so that the AVC is not locked during the access vector computation by the security server. Similarly, the avc_lock is released before calling security_notify_perm. The two inline AVC functions call avc.c:avc_lookup to search the cache and avc.c:avc_insert to add a new entry to the cache. The avc_has_perm_ref_audit function calls avc.c:avc_audit to audit permission checks.
The avc.c:avc_audit function uses printk to log whether permission was granted or denied, the names of the requested permissions, the security contexts of the SID pair, and the name of the class. If the current process has a nonzero PID, then the PID and executable path of the current process are also logged. The executable path is determined by using the fs/dcache.c:d_path function on the executable's dentry.
If file system audit data is set, then the path, device number and inode number are logged. The path is likewise determined using d_path. If networking audit data is set, then information about each field that is set in the net structure is logged. If the socket field is set to an AF_INET socket, then the local and foreign addresses of the socket are logged. If the socket field is set to an AF_UNIX socket, then the path or abstract name is logged. If the abstract name space was used, then the initial NULL character is replaced with an ``@'' character. If the packet field is set to an IPv4 packet, then the source and destination addresses are logged. If the network interface field is set, then the name is logged.
The avc_ss_grant, avc_ss_try_revoke, avc_ss_revoke, avc_ss_set_auditallow, avc_ss_set_auditdeny and avc_ss_set_notify functions are implemented in avc.c. Each of these functions calls avc.c:avc_control with the corresponding event value. The avc_control function calls avc.c:avc_update_cache to update any matching entries in the cache, and avc_control calls each of the callbacks registered for the event with matching parameters. If the event is AVC_CALLBACK_TRY_REVOKE, then avc_update_cache is not called until after the callbacks have been called, since the function must obtain the set of retained permissions from the callbacks. The avc_update_cache function disables interrupts locally and takes the global spin lock (avc_lock) on entry, releasing the lock and enabling interrupts before returning. The avc_control function disables interrupts and takes the lock only to update the latest policy change sequence number.
The avc_ss_reset function is also implemented in avc.c. This function disables interrupts and takes the global spin lock to invalidate the cache. Then, after enabling interrupts and releasing the lock, this function calls each of the callbacks registered for the AVC_CALLBACK_RESET event. Finally, the avc_ss_reset function disables interrupts and takes the lock again to update the latest policy change sequence number.