Check out the new USENIX Web site. next up previous
Next: Taking Measurements Up: Implementation Previous: Implementation

Inserting Measurement Points

In Section 4.2, we outlined the approach to measurement, including measurement in the kernel and also by user-level programs. Here we describe the implementation.

We implemented kernel measurements based on the Linux kernel LSM interface. Using the file_mmap LSM hook, we induce a measurement on any file before it is mapped executable into virtual memory.

Using the sysfs file system, we allow user-space applications to issue measure requests by writing requests to /sys/security/measure, including the file descriptor of the file to measure. Using the kernel load_module routine, we induce a measure call on the memory area of a loading module before it is relocated.

In Section 4.2, we outline the approach to measurement, where measured executable code itself (e.g., shell) can induce additional measurements on loaded file contents its behavior depends on (e.g., shell command files). If that executable code is not of high integrity, it will be detected (because it is already in the measurement list). If it is of high-integrity, then it may be trusted to measure its loaded data.

We describe below how we measure dynamic run-time loads and how we protect measured files throughout their use.

User-level Executables: User-level executables are loaded through the user-level loader. When a binary executable is invoked via the system call execve, the kernel calls the binary handler routine, which then interprets the binary and locates the appropriate loader for the executable. The kernel then maps the loader into memory and sets up the environment such that when the execve call returns, execution resumes with the loader. The loader in turn performs further loading operations and finally passes control to the main function of the target executable. In the case of a statically linked binary, the only file being loaded is the target binary itself, which we measure in the file_mmap LSM hook, called by the kernel before mapping it.

Dynamically Loadable Libraries: A dynamically linked binary typically requires loading of additional libraries that it depends on. This process is done by the user-level loader and is transparent to the kernel. However, the linker maps shared libraries (flagged executable) into virtual memory by using the mmap system call, which always invokes the file_mmap LSM hook. Thus, the mediation provided by the file_mmap LSM hook instrumentation yields measurements of all statically and dynamically linked executables including shared libraries.

Kernel Modules: Kernel modules are extensions to the kernel that can be dynamically loaded after the system is booted. Module loading can be explicit (via insmod or modprobe) or implicit if automatic module loading is enabled. In the latter case, when the kernel detects that a module is needed, it automatically finds and loads the appropriate module by invoking modprobe in the context of a user process. With a 2.6 kernel, both programs load kernel modules into memory and then call the sys_init_module system call to inform the kernel about the new module that is then copied into kernel memory and relocated. Thus, kernel modules can either be measured by insmod or modprobe on user level when they are loaded from the file system, or they can be measured in the kernel when they reside in kernel memory and before they are relocated. We implemented both versions. However, we prefer the latter version because it prevents exploits of (possibly unknown) vulnerabilities in the kernel loader applications insmod or modprobe from tampering the measurement of kernel level code. Because there is no suitable LSM hook available, we added a measure call into the load_module routine that is called by the init_module system call to relocate a module that is in memory.

Scripts: Script interpreters are loaded and measured as binary executables. However, interpreters load additional code that determines their behavior, so we would prefer that the script interpreters also be capable of measuring their integrity-relevant input. At present, we have instrumented the bash shell to measure any interpreted script and configuration files before loading and interpreting them. This includes all service startup scripts into the measurement list. We observe about 60-70 measurements of bash scripts and source files in our experiments booting Redhat 9.0 Linux and running a Gnome Desktop system. Instrumenting other programs (Perl, Java) is straightforward, but we anticipate the need for more support from application programmers.

next up previous
Next: Taking Measurements Up: Implementation Previous: Implementation
sailer 2004-05-18