Before security promises of the project can be made, Linux kernel itself must be evaluated from the attacker's point of view. LKRG may or may not be addressing the potential issues but they must be appropriately defined. From the high level point of view, the following main attacking scenarios (buckets) can be described:
Scenario 1. describes a group of attacks before the kernel fully initializes and LKRG starts to run. The entire boot chain can be attacked (e.g. attacks from MBR/BIOS/UEFI, initramfs, etc.). Currently, this type of attacks is completely out of scope. It might be considered for research in the future (long term perspective) but it's not on the priority list at the present time.
Scenario 2. describes initial attacks on the kernel via any kernel vulnerability and it involves a kernel memory write. Current version of the project might partially protect against a subset of such writes - namely, those involving machine code changes (or effectively equivalent changes), as well as any attack which involves overwriting any process;s credentials. For more information please read this chapter.
Most of the efforts have been made to limit scenario 3. It is impossible to fully protect from all possible persistence kernel modifications, but they can be significantly limited comparing to what is achievable nowadays. Linux kernel has never been designed to be protected from “wild” modifications / hooking or even limiting them. Moreover, Linux kernel is heavily self-modifying piece of software which heavily contradicts with the main idea of the project - “Preventing unsupported modifications of the Linux kernel”. As a result, the protection level and limitations must be strictly defined. This implies how much project rises the bar for the attacker in case of persistent kernel modifications. It was decided that acceptable level is to push all known attacks against the project to the booting/rebooting stage. To be able to achieve this level of protection, the following problems need to be solved:
For more details please take a look at the section LKRG validation routine.
By creating communication channel and user-mode client of the project, LKRG created new potential vectors of attack. These attacks can be summarized as follows:
To be able to solve that problems “Protected features” have been designed and implemented as part of LKRG.
Scenario 1. is addressed by creating a new subset of processes in the system - “protected process”. It guarantees that no one in user-mode (including root) won't be able to change the state of running process at any time. Also it guarantees that none of the secrets can be ever discovered by anyone in user-mode (including root). Only another “protected process” has rights to establish 3rd party communication (e.g. sending signals). For more details please take a look at the section Protected Process.
Scenario 2. is addressed by creating a new subset of files in the filesystem - “protected file”. It guarantees that no one in user-mode (including root) won't be able to change the content of the file at any time. File can still be normally executed and read if the owner of the file decides to give that rights to “other” users. For more details please take a look at the section Protected File.
Scenario 3. and 4. are a bit tricky. Many users believe that CAP_SYS_RAWIO capability controls raw memory and disk access - but that's incorrect. There is no way to block raw disk access through any capabilities. CAP_SYS_RAWIO limits mostly raw memory access (it has some other restriction not related to the discussion like ioports). Even without CAP_SYS_RAWIO an attacker with appropriate rights (any root process or any process with appropriate DAC rights) might open e.g. /dev/sda[0-x] device and overwrite this “slot” where victim's file is. To be able to limit raw disk access LKRG virtually extends CAP_SYS_RAWIO functionality in the system. This extension means that any process without CAP_SYS_RAWIO will not have raw access also to the disk. If “Protected features” are initialized by default, any process in the system will be enforced to drop CAP_SYS_RAWIO capability (excluding “Protected process”). The same technique which is used by LKRG project, spender and pipacs use in grsecurity/PaX project to block raw disk access.
Scenario 5. is mitigated by compiling user-mode client of the project as static binary which never relies on any 3rd party code. Another way of solving this problem is to make any dependent libraries to be “protected file” as well. User can define any file (even configuration files) to be “protected file”.
If LKRG detects any inconsistency in the kernel, it generates appropriate log message from the kernel (in the future LKRG might be configurable to crash the kernel). These logs might be forwarded to the remote server or locally consumed in user-mode and written to the appropriate file. An attacker might be changing the kernel state and clean the logs to be able to hide his own activity. To be able to avoid that situation, LKRG created another subset of files in the filesystem which essentially works like “append” files. LKRG enforces that no one in file system (including root) can ever change the content of the file which was already written. The new data can still be written to the same file, but old data can't be modified. For more details please take a look at the section Protected Logs.
To be able to interact with LKRG, a user must be an administrator of the machine (typically 'root' account). This implies that any new attack surface introduced by the 'core' of LKRG will be limited to the scenario of leveraging existing administrator privileges (e.g. 'root') to the kernel level access.
“Protected Features” and future “Exploit Detection” are different, because they intercept some of the functionality directly exposed to the user (e.g. syscalls). If these features are used (PF and/or ED), there is a potential problem in case of any hooking routine is incorrectly written. In that scenario user can have an extra kernel surface to attack. In reality, LKRG interceptions are pretty simple (most of the time just checking registers value during the entrance to function/syscall) and shouldn't be problematic.