Next Previous Contents

5. Sealing the Kernel.

We need do some necessary operation when system booting up, but also we need to provent the operation when system is running.

For example, we need to insert the needed modules into the kernel, but we dont want any module to be inserted when the system is running because it is very dangerous. How to sulute this problem? here comes the seal idea. we can do what we want to do during the system booting, and then we seal the kernel. After that, we can not do the same thing as what we can do before sealing. With the sealing ideas, we can solute the problem with modules, we can insert the needed modules into kernel before sealing and don't sallow any modules inserted and deleleted after sealing.

5.1 Sealing kernel with the LIDS.

In order to seal the kernel, in LIDS , we use the command

#lidsadm -I -- -CAP_xxx...  
It can be put in the script which can be run by init when system booting up. The detials about capability is in LIDS HOWTO written by biodi. What the lidsadm do is to communicate with kernel via the file /proc/sys/lids/locks.

When you seal the kernel, the lidsadm call lids_init() in lidsadm.c.


/* in lidsadm.c */

#define LIDS_LOCKS      "/proc/sys/lids/locks"
......
void lids_init(int optind, int argc, char *argv[])
{
......
        if ((fd=open(LIDS_LOCKS,O_RDWR)) == -1) {
                perror("open");
                exit_error (2, "can't open " LIDS_LOCKS);
        }
        if (read(fd,&locks,sizeof(lids_locks_t))==-1) {
                perror("read");
                exit_error (2, "can't read " LIDS_LOCKS);
        }

        lids_set_caps(optind,argc,argv,&locks);

        locks.magic1=LIDS_MAGIC_1;
        .........

        if (write(fd,&locks,sizeof(lids_locks_t))==-1) {
                perror("write");
                exit_error (2, "can't write " LIDS_LOCKS);
        }
.....
}

The system call write the new variant locks to the LIDS_LOCKS, the kernel will read it via the function lids_proc_locks_sysctl(). The lids_proc_locks_sysctl will do some sanity check and read the locks from user space and perform the capability changed and then change the value of the sealing variant -- lids_first_time to 0.

Let's have a look at lids_proc_locks_sysctl(). This function is called by kernel when someone read/write the /proc/sys/lids/locks.


int lids_proc_locks_sysctl(ctl_table *table, int write, struct file *filp,
                            void *buffer, size_t *lenp, int conv, int op)
{
...........


        /* first: check the terminal and the program which access the sysctl */

#ifndef CONFIG_LIDS_REMOTE_SWITCH
        if (current->tty && (current->tty->driver.type != 2) ) {
                lids_security_alert("Try to %s locks sysctl (unauthorized terminal)",
                                    write ? "write" : "read");
                return -EPERM;
        }
#endif
........
       /* second: check wether it is not a timeout period after two many failed attempts */

.......
  if (write) {
                /* Third : check what is submitted (size, magics, passwd) */
                if (*lenp != sizeof(lids_locks_t)) {
                        lids_security_alert("Try to feed locks sysctl with garbage");
                        return -EINVAL;
                }
                if (copy_from_user(&locks,buffer,sizeof(lids_locks_t)))
                        return -EFAULT;
        .......
                if ((lids_first_time) && (!locks.passwd[0])) {
                        .........
                        number_failed=0;
                        if (lids_process_flags(locks.flags)) {
                                cap_bset=locks.cap_bset;
                                lids_security_alert("Changed: cap_bset=0x%x lids_flags=0x%x",cap_t(cap_bset),lids_flags);
                        }
 Change flag here ..-->  lids_first_time=0;
                        .....
                }

The function above is to do the real job when sealing the kernel or change the kernel security level. The variant lids_first_time is a flag indicating that the current state is before-sealing or after-sealing. After change the requried capability bit, the flag change to 1 indicating that the current state is after-sealing.

Sealing kernel has two tasks, firstly, change the capability bit with the requried parameter, secondly, change the lids_first_time flag to 1. After the sealing, the system will not allow change the capability without using lidsadm and a password.

Protect program before sealing the kernel.

Since the state before sealing is dangerous, we should know that the program running before sealing is protected by LIDS. Why ? because we must gurantee that the on-going program can not be changed after sealing. If the files is not protected, someone may change the program and then after reboot, the program can also do harm to the system. Let's look at the code about the warning about the unprotected program running before sealing.


int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
{
        ..........

#ifdef CONFIG_LIDS_SA_EXEC_UP
        if (lids_first_time && lids_load) {
                if (!lids_check_base(dentry,LIDS_READONLY))
#ifdef CONFIG_LIDS_NO_EXEC_UP
                        lids_security_alert("Try to exec unprotected program %s before sealing LIDS",filename);
                        if (dentry)
                                dput(dentry);
                        return -EPERM;
#else
                        lids_security_alert("Exec'ed unprotected program %s before sealing LIDS",filename);
#endif
                }
        }
#endif
......
}

You can see that when LIDS protected system is on ( lids_load == 1) and the current system is no sealed( lids_firest_time is 1 ), kernel will check if the current program is under protected by LIDS by lids_check_base(). If it is not protected, it will raised warning message.


Next Previous Contents