A "runtime guard" for the kernel
While updating kernels frequently is generally considered a security best practice, there are many installations that are unable to do so for a variety of reasons. That means running with some number of known vulnerabilities (along with an unknown number of unknown vulnerabilities, of course), so some way to detect and stop exploits for those flaws may be desired. That is exactly what the Linux Kernel Runtime Guard (LKRG) is meant to do.
LKRG comes out of the Openwall
project that is perhaps best known for its security-enhanced Linux
distribution. Alexander Peslyak, or "Solar Designer", who is Openwall's
founder and leader is prominent in
security circles as well. He announced
LKRG at the end of January as "our most controversial project
ever
". The 0.0 release that was announced was "quite
sloppy
", Peslyak said in a LKRG 0.1 release
announcement on February 9; principal developer Adam "pi3"
Zabrocki cleaned things up
and added some new features based on ten days of feedback.
At its core, LKRG is a loadable kernel module that tries to detect changes to the running kernel that would indicate that some kind of exploit is being used against it. Beyond that, it checks processes running on the system to look for unauthorized modifications to credentials of various sorts in order to prevent those changes from granting additional access—something that exploits will try to do. The initial LKRG announcement describes the goals this way:
As noted, LKRG can be bypassed, so it is really only another line of defense in a defense-in-depth strategy, rather than a panacea of any sort. In addition, it currently is in an experimental stage (as the version numbers might indicate), so it only logs any kernel modifications that it finds. The kernel is replete with various types of self-modifying code, from tracepoints and other debugging features to optimizations of various sorts, so protecting the integrity of the running kernel is not a straightforward task.
To track the running kernel, LKRG creates a database of hashes of various types of information about the system and the kernel running on it. It tracks the CPUs available and active in the system, along with the location and contents of their interrupt descriptor tables (IDTs) and model-specific registers (MSRs). Since the kernel may modify itself due to changes in the number of CPUs hotplugged into (or unplugged from) the system, LKRG must be ready to recalculate some of its hashes based on those events.
For the kernel, LKRG tracks the hashes of the .text section, the .rodata section (which should never change), and the exception table. Beyond that, each loaded module is tracked, including information like its struct module pointer, name, size and hash of its .text section, and some other module-specific information. The details of that are described on the LKRG wiki.
In order to detect modifications, the values stored need to be validated regularly. This is done via a number of mechanisms, starting with a timer that checks at regular intervals; the period can be set via the sysctl interface. It also runs the check whenever module-loading or CPU-hotplug activity is detected and can be triggered manually by way of another sysctl. Other events in the system (e.g. CPU idle, network activity, USB change, etc.) will trigger the validation, though only a certain percentage of the time to reduce the performance impact. For example, CPU idle will trigger validation 0.005% of the time while a USB change will do so 50% of time.
All of that is meant to protect the integrity of the running kernel itself, but exploits often target the processes running on the system in order to elevate privileges and the like; that information lives in the kernel's read-write memory. So LKRG also tracks a whole bunch of different attributes of each process and maintains its own task list that can be used to validate the kernel's list. If the two diverge, affected processes are killed; the intent is to do so before they can take advantage of the differences.
The tracking consists of task attributes like the address of the task_struct, process name and ID, the addresses of the cred and real_cred credential structures, the various user and group IDs associated with it, SELinux settings, and "secure computing" (seccomp) settings and configuration. Various other things are tracked currently (e.g. capabilities information) but not validated.
All of that information is validated every time certain system calls (e.g. setuid(), execve()) or other events happen in the system (e.g. when permissions are checked prior to opening a file). In addition, the process-list validation is done every time the kernel validation is run. All processes are validated each time, not just the one making the system call, and any discrepancy results in killing any process that has differences.
The wiki page shows tests of LKRG to detect exploits of some known kernel
vulnerabilities (e.g. CVE-2014-9322, CVE-2017-6074);
both of those were detected, as were a few others. The performance impact
has been
measured in a rudimentary way: a system running LKRG 0.0 was about 6.5%
slower building
Openwall's John the Ripper password cracker.
Performance optimizations have not been a focus yet, but: "We find
this performance impact significant (especially for a security measure
bypassable by design), and are likely to make adjustments to reduce
it.
"
There are certain kinds of kernel vulnerabilities that LKRG cannot detect. If the exploit functions entirely in user space (perhaps by exploiting a kernel race condition like Dirty COW), it won't modify the parts of the kernel that are being tracked, thus won't trigger LKRG. The home page describes it this way:
LKRG is available for x86 and x86-64 and, because it is a kernel module rather than a set of patches, it will build for a wide variety of kernel versions. It can be built for the RHEL 7 kernel, which is based on 3.10, and it will also build for the mainline (4.15). The project has a mailing list for questions and support, though it is rather quiet; there are only a few postings from January and February at this point.
It is clearly a niche project and one that may not really find many users. For some installations, it could provide another level of defense, but it means those users are probably not keeping up with their kernel updates. Given that LKRG can be bypassed and that it certainly can't detect all kinds of kernel exploits, it may provide a false sense of security. But for organizations that carefully consider the threat model for LKRG and their own needs, there is value to be found in LKRG. Whether there is enough value to sustain a project (and perhaps allow Openwall to provide a non-free "LKRG Pro" version) remains to be seen.
| Index entries for this article | |
|---|---|
| Kernel | Security/Kernel hardening |
| Security | Linux kernel/Hardening |
| Security | Linux Security Modules (LSM) |
