The kernel data structures were studied to identify the structures used internally for mounted file systems (struct super_block), active files and directories (struct inode), and file descriptions (struct file). All three of these structures are defined in include/linux/fs.h. Since these structures are private to the kernel and have no specific size requirements, a SID field was added to each structure. Since a struct inode object is used to represent all types of files, an object class field was also added to the structure.
Two other private kernel data structures also required the addition of SID fields. The inode attributes structure (struct iattr) is used for changing the attributes of a file, so a SID field was added to this structure, and a corresponding flag (ATTR_SID) was defined to indicate that the SID is being changed. The file description owner structure (struct fown_struct) is used to store the identity of the process that set the owner on a file description, so a SID field was added to this structure.
The implementation of the persistent labeling table was partitioned into a component that is independent of the file system type (fs/psid.c) and a set of components that are specific to each file system type. Most of the implementation resides in the filesystem-independent component; hence, persistent labeling support for additional file system types may be easily added. The filesystem-independent component implements the mapping between each PSID and its security context using regular files in a fixed subdirectory of the root directory of each file system. Two PSIDs are reserved: PSID 0 represents the default label to assign to unlabeled objects in the file system, and PSID 1 represents the label of the file system itself. The subdirectory and its files are always treated as being labeled with a fixed security context so that the security policy may control access to the mapping. Synchronous writes are used to update the mapping files and the writes are ordered to ensure that there are no dangling references.
The interface to the filesystem-independent component is defined in include/linux/flask/psid.h. The file system calls the fs/psid.c:psid_init function to initialize the mapping between PSIDs and security contexts when the file system is mounted (fs/super.c:mount_root, fs/super.c:do_mount). If the file system is unlabeled, then this function obtains the SIDs for the unlabeled file system from the security server. If the file system is unlabeled and it is being mounted read-write, then this function creates a new PSID mapping on the file system. If an unlabeled file system is mounted read-only initially and is subsequently remounted read-write, then the fs/psid.c:psid_remount function creates a new PSID mapping on it when it is called by fs/ext2/super.c:ext2_remount. The file system calls the fs/psid.c:psid_release function to free any memory and release any files used for the PSID mapping when the file system is unmounted (fs/super.c:do_umount).
The filesystem-specific components implement the mapping between each file and its PSID. Currently, the filesystem-specific component has only been implemented for the native Linux file system type, ext2. The ext2-specific component stores the PSID for each file in a formerly unused field of the on-disk inode structure (struct ext2_inode). Since the PSID is readily available in the on-disk inode, no extra overhead is incurred either to obtain the PSID when a file is accessed or to set the PSID when a file is created.
The ext2fs code calls the fs/psid.c:psid_to_sid function to obtain the SID of an existing inode based on its PSID when the inode is read from the disk (fs/ext2/inode.c:ext2_read_inode). The fs/psid.c:sid_to_psid function is called to obtain a PSID for an inode based on its SID when an inode is allocated (fs/ext2/ialloc.c:ext2_new_inode) or when the SID of an inode is changed (fs/ext2/inode.c:ext2_notify_change).