Next Previous Contents

2. Protect File System

The most important job LIDS do is to protect the file system. It is impletementated in the VFS( virtual File System) layer in the kernel.For that reason, we can protect any kind of filesystem, such as EXT2, FAT.

2.1 Protect important files.

In the LIDS, the protected files are devided into catelog shown below,

2.2 How LIDS protect files in kernel.

In this section, we will view some kernel source let you understand how LIDS protect files.

Linux Filesystem data struct and routines.

Firstly, we must understand the virtual filesytem in linux.

Every file in the linux, whatever the filesytem he reside on, has an inode number, the files system provide the following data struct.



in the /usr/src/linux/include/linux/fs.h

struct inode {  
        struct list_head        i_hash; 
        struct list_head        i_list; 
        struct list_head        i_dentry;

        unsigned long           i_ino; ----> inode number.
        unsigned int            i_count;
        kdev_t                  i_dev; ----> device number.
        umode_t                 i_mode;
        nlink_t                 i_nlink;
        uid_t                   i_uid;
        ......
}

Note: <i_ino ,i_dev> used to be a identification of an inode.That means that you can use the pair <i_ino,i_dev> to get a unique inode from the system.


in the /usr/src/linux/include/linux/dcache.h 

struct dentry {
        int d_count;   
        unsigned int d_flags;
        struct inode  * d_inode;        /* Where the name belongs to - NULL is negative */
        struct dentry * d_parent;       /* parent directory */
        struct dentry * d_mounts;       /* mount information */
        struct dentry * d_covers;
        struct list_head d_hash;        /* lookup hash list */
        struct list_head d_lru;         /* d_count = 0 LRU list */
        struct list_head d_child;       /* child of parent list */
        struct list_head d_subdirs;     /* our
        ......
}

The dentry is a entry of a file in diretory. Using the dentry, we can easily trave through the file's parent diretory.

For example, if a file's inode is (struct inode *)file_inode, you can use file_inode->d_entry to get its diretory entry and then use file_inode->d_entry->d_parent to get its parent diretory's entry.

LIDS Data Struct for protection.

After the above analyzing of the linux file system, let's have a look at how LIDS uses the VFS to protect files and diretories.



/* in /usr/src/linux/fs/lids.c */

struct secure_ino {
        unsigned long int ino;          /* the inode number */
        kdev_t  dev;                    /* the dev number */
        int     type;                   /* the file type */
};

The above struct is used to store the protected file or directorie's inode with the pair <ino,dev>."type" is used to indentify which type the protected inode(file).

LIDS has 4 type,



/* in /usr/src/linux/incluce/linux/fs.h */

#define LIDS_APPEND     1       /* APPEND ONLY FILE */
#define LIDS_READONLY   2       /* Read Only File */
#define LIDS_DEVICE     3       /* Protect MBR Writing to device */
#define LIDS_IGNORE     4       /* Ignore the protection */

With the secure_ino struct, we can easily initial the protected files or diretories into the kernel with the flollowing functions,



/* in /usr/src/linux/fs/lids.c */

int lids_add_inode(unsigned long int inode ,kdev_t dev , int type)
{

        if ( last_secure == (LIDS_MAX_INODE-1))
                return 0;

        secure[last_secure].ino = inode;
        secure[last_secure].dev = dev;
        secure[last_secure].type = type;

        secure[++last_secure].ino = 0;

#ifdef VFS_SECURITY_DEBUG
        printk("lids_add_inode : return %d\n",last_secure);
#endif
        return last_secure;
}

As you can see from the above code, it is very easy to add a given inode into the secure_ino. Protected inodes are initialized during the system boot. The initial routine is init_vfs_security() in /usr/src/linux/fs/lids.c.

And now, let's have a look at how the LIDS check whether an inode is being protected,


/* /usr/src/linux/fs/open.c */

int do_truncate(struct dentry *dentry, unsigned long length)
{
        struct inode *inode = dentry->d_inode;
        int error;
        struct iattr newattrs;

        /* Not pretty: "inode->i_size" shouldn't really be "off_t". But it is. */
        if ((off_t) length < 0)
                return -EINVAL;

#ifdef CONFIG_LIDS
        if (lids_load && lids_local_load) {
                error = lids_check_base(dentry,LIDS_READONLY);
                if (error) {
                        lids_security_alert("Try to truncate a protected file (dev %d %d,inode %ld)",
                                            MAJOR(dentry->d_inode->i_dev),
                                            MINOR(dentry->d_inode->i_dev),
                                            dentry->d_inode->i_ino);
        .....................

This is an example that LIDS add checking in kernel. You can see that the function lids_check_base() is one of core functions for the lids protection method.

You can see lids_check_base() in many place where LIDS want to protect, especially in fs subdiretory of linux kernel.


/* in /usr/src/linux/fs/lids.c */

int lids_check_base(struct dentry *base, int flag)
{
        ..................
        inode  = base->d_inode;         /* get the inode number */
        parent = base->d_parent;        /* get the parent diretory */

        .................
---->   do {
                if ( inode == parent->d_inode)
                        break;
                if ((retval = lids_search_inode(inode))) {
                        if ( retval == LIDS_IGNORE ||
                                (retval == LIDS_DEVICE && flag != LIDS_DEVICE))
                                break;
                        if ( flag == LIDS_READONLY ||
                                ( flag == LIDS_APPEND && retval >flag ) ||
                                ( flag == LIDS_DEVICE && flag == retval )) {
                                return -EROFS;
                        }
                        break;
                }
                inode = parent->d_inode;
        } while( ((parent = parent->d_parent ) != NULL) );

        return 0;
}

lids_check_base() check if the given dentry of a file and it's parent diretories have been protected.

Note: If the its parent diretory is protected, the file is also protected.

For example, if "/etc/" has been protected, the "/etc/passwd" is also protected.

Protected system call in the kernel.

In order to protect the filesystem, LIDS insert a checking in the begin of some critical system call. Therefore, we can protect the system call and restrict user using the filesystem.

Here we list some example,


Next Previous Contents