The Guardian Kernel Module (GKM) Louis Brooks and Sarah Diesburg Introduction: Our project involves adapting/upgrading select kernel security functionality from an older kernel module known as St. Michael [http://freshmeat.net/projects/stmichael_lkm/]. Our kernel module, which we call the Guardian Kernel Module (GKM), will be built for the 2.6 series of Linux kernels in a time period of two weeks and will include many of the security functionalities of St. Michael through a different implementation to accommodate the 2.6 kernels. Objectives: Monitor loading and unloading of kernel modules to discover modules that cloak themselves. If a module is cloaking itself, or making itself invisible to the system and lsmod, it is most likely malicious. When discovered, cloaked modules will be unloaded. Monitor system call mappings to detect if system calls are being remapped. If system calls are being remapped, most likely something malicious is going on. If an incorrectly mapped system call is discovered, its original mappings will be restored. Monitor integrity of GKM, system calls, modules, and kernel itself through md5 summing. If any of the above change while the system is booted, malicious activity is most likely happening. Check to be sure there are no system calls registered that should not be. Extra system calls might indicate malicious behavior. Logging: New module loads and unloads. System call mappings. GKM Actions Discovering of improper system call mapping and restoration. Discovering of cloaked modules and their demise. Discovering of compromised integrity through md5 sums. Discovering of extraneous system calls. Logging format will be: Month DD HH:MM:SS GKM:message Logging will be sent to syslog. GKM will be cloaked (cannot be seen by system). GKM will not unload. Monitoring Loading and Unloading of Kernel Modules: We will create wrapper functions to remap all kernel loading and unloading to our control. When a module is loaded, we will add it to an internal linked list. When a module is unloaded, we will delete it from our linked list. At regular intervals, with the help of a kernel timer, we will compare the list of loaded kernel modules reported by the kernel to our own linked list. If there is a discrepancy, then we have discovered a cloaked module. We will attempt to unload the module first. We will also log the problem. Monitoring System Call Mappings: On module load we will create a list of pointers to each monitored system call. We will then periodically check, through a kernel timer, that our list of system call pointers matches the list of system call pointers exported by the kernel. If the two lists do not match, we will attempt to restore the kernel's list with our original system call pointer list and log the problem. Monitor Integrity of GKM, System Calls, Modules, and Kernel: On system boot, md5 sums are taken of important functions of the GKM module, monitored system calls, and the kernel through /dev/ksyms (or equivallent in 2.6). On module loads, md5 sums are taken of the observed modules. Periodically, though the use of a kernel timer, we will re-obtain md5 sums of the above specified items and compare them with the original md5 sums. If any of the sums do not match, we will log the problem and possibly take action. Check for Extraneous System Calls On load, we can check for extraneous system calls by comparing system calls listed in the system call table to the actual kernel text. If the two don't match, we will log the problem. Other Interesting Problems in Upgrading/Adapting the St. Michael LKM Code: The sys_call_table is not exported in the 2.6 kernels. This leaves us with two options. We can either patch and recompile the kernel to actually export that symbol, or we can work around it by finding the sys_call_table through reading /dev/kmem. System calls have probably changed since the 2.2 and 2.4 kernels, and we must come up with a new list of calls to monitor. Module initializations may have changed since 2.2 and 2.4 kernels, and we will have to make changes accordingly. There is no /proc/ksyms in the 2.6 kernels. We think we can use the /proc/kallsyms instead, but this will take some investigation. We need to use newer spinlocks in our code. The St. Michael module used the kernel_lock() and kernel_unlock() functions, also known as the “Big Kernel Lock”. This lock would lock all processors but one when invoked. The St. Michael code is long and complicated with few comments. We have had no luck in contacting the developer. The actual St. Michael code contains more functionality than we listed above, but much of it is possibly destructive to the system (such as replacing the running image of the kernel with a backup). Kernel Programming Techniques and Mechanisms Locking Mechanisms: No semaphores will be needed because we are neither accessing our module from user space, nor will we be running multiple instances of our module. We will need to use new kernel spinlocks throughout our code. Time Management We will be using kernel timers to: Periodically check the integrity of our module, monitored system calls, kernel, and other modules as they load and unload through the use of md5 sums. Periodically check system call mappings. Periodically check the list of loaded modules. Use external variable that may be passed in a load time to determine the timer intervals. We will also have a suitable default value. Virtual to Physical Memory Mapping Does not apply. Memory Management Responsible use of kmalloc and free statements to create our data structures. Interrupt Management We will employ software interrupts through the use of kernel timers. Hardware Interfacing Does not apply. Device Driver Internal Abstractions Since we are not a device driver and will not have any interaction from user space, we will not employ any device abstraction. In fact, we will cloak ourselves. Cloak on! We will define our module through the use of a "struct module".