Linux Kernel Runtime Guard (LKRG) is a loadable kernel module that performs runtime integrity checking of the Linux kernel and detection of security vulnerability exploits against the kernel. As controversial as this concept is, LKRG attempts to post-detect and hopefully promptly respond to unauthorized modifications to the running Linux kernel (integrity checking) or to credentials (such as user IDs) of the running processes (exploit detection). For process credentials, LKRG attempts to detect the exploit and take action before the kernel would grant the process access (such as open a file) based on the unauthorized credentials.
While LKRG defeats many pre-existing exploits of Linux kernel vulnerabilities, and will likely defeat many future exploits (including of yet unknown vulnerabilities) that do not specifically attempt to bypass LKRG, it is bypassable by design (albeit sometimes at the expense of more complicated and/or less reliable exploits). Thus, it can be said that LKRG provides security through diversity, much like running an uncommon OS kernel would, yet without the usability drawbacks of actually running an uncommon OS. As free LKRG becomes somewhat popular and maybe a target of some exploits, we might introduce paid LKRG Pro as a means to fund the project and provide further diversity (with Pro’s smaller userbase being beneficial), extra and specialized functionality (e.g., detection of container escapes), and maybe distro-specific binary builds.
Like any software, LKRG may contain bugs and some of those might even be new security vulnerabilities. You need to weigh the benefits vs. risks of using LKRG, considering that LKRG is most useful for systems that realistically, despite of this being a best practice for security, won’t be promptly rebooted into new kernels (nor live-patched) whenever a new kernel vulnerability is discovered.
Being a kernel module (not a kernel patch), LKRG can be built for and loaded on top of a wide range of mainline and distros’ kernels, without needing to patch those. We currently support kernel versions ranging from RHEL7 (and some of its clones/revisions, including even the heavily modified OpenVZ/Virtuozzo 7, albeit not trying to detect container escapes yet) and Ubuntu 16.04 to latest mainline.
LKRG is currently in an early experimental stage. We expect occasional false positives (integrity violations and/or exploits detected when there aren’t ones). LKRG’s current response to kernel integrity violations is merely reporting those in kernel messages (which obviously doesn’t mitigate attacks when those are for real) and its current response to unauthorized process credentials is killing the process (which does defeat many exploits, but is a rather mild response nevertheless). This will likely change as LKRG becomes more mature.
To illustrate LKRG’s exploit detection capabilities, in our testing on vulnerable distro kernels LKRG successfully detected certain pre-existing exploits of CVE-2014-9322 (BadIRET), CVE-2017-5123 (waitid(2) missing access_ok), CVE-2017-6074 (use-after-free in DCCP protocol). However, it wouldn’t be expected to detect exploits of CVE-2016-5195 (Dirty COW) since those directly target the userspace even if via the kernel. While in case of Dirty COW the LKRG “bypass” happened due to the nature of the bug and this being the way to exploit it, it’s also a way for future exploits to bypass LKRG by similarly directly targeting userspace. It remains to be seen whether such exploits become common (unlikely unless LKRG or similar become popular?) and what (negative?) effect on their reliability this will have (for kernel vulnerabilities where directly targeting the userspace isn’t essential and possibly not straightforward).
LKRG Conference: https://www.youtube.com/watch?v=tOiPM692DOM
LKRG Wiki: https://openwall.info/wiki/p_lkrg/Main
[root@proton ~]# git clone https://bitbucket.org/Adam_pi3/lkrg-main.git
Cloning into 'lkrg-main'...
remote: Counting objects: 1424, done.
remote: Compressing objects: 100% (1324/1324), done.
remote: Total 1424 (delta 780), reused 176 (delta 83)
Receiving objects: 100% (1424/1424), 252.92 KiB | 0 bytes/s, done.
Resolving deltas: 100% (780/780), done.
[root@proton ~]# make -j8
[root@proton ~]# cd lkrg-main/
# We need to use newer version of gcc then centos has by default.
[root@proton ~]# yum install centos-release-scl -y
[root@proton ~]# yum install -y devtoolset-8 devtoolset-8-binutils-devel devtoolset-8-elfutils-libelf-devel devtoolset-8-gcc devtoolset-8-gcc-c++ devtoolset-8-gcc-gdb-plugin devtoolset-8-gcc-plugin-devel
[root@proton ~]# scl enable devtoolset-8 bash
[root@proton lkrg-main]# make -j8
[root@proton lkrg-main]# make install
[root@proton lkrg-main]# systemctl start lkrg
[root@proton lkrg-main]# systemcl enable lkrg
[root@proton lkrg-main]# dmesg
Enjoy the next kernel protection against exploits 😀