- This project implements a custom LLVM pass designed to modify Linux kernel source code during compilation.
- This guide details the integration into the LLVM source tree, the build process using Ninja, and the configuration required to compile the Linux kernel with this custom toolchain.
- Testing was done with version 6.18.0-rc6 for linux, and 22.0.0 for LLVM.
Ensure the source code is placed in the following directory:
llvm/lib/Transforms/Backdoor/
You must link the new folder in the build system.
Add the following line at the end of the file to include your new folder:
add_subdirectory(Backdoor)To make the pass visible to the Pass Manager, modify llvm/lib/Passes/PassRegistry.def.
Find the section for MODULE_PASS and add your pass:
MODULE_PASS("backdoor", BackdoorPass())Note: Ensure the header file for your pass is included in llvm/lib/Passes/PassBuilder.cpp if strictly required for your version of LLVM, though PassRegistry.def is the primary registry point. For this build, there's a header file at "llvm/include/llvm/Transforms/Utils/Backdoor.h"
Use ninja to build the modified Clang compiler.
-
Navigate to your build directory (e.g.,
llvm-project/build). -
Configure the build (if not already done):
cmake -G Ninja ../llvm- Build Clang:
ninjaBefore building the kernel, you must configure the environment to use the custom Clang and modify the kernel configuration to avoid build errors.
Export the PATH so the kernel build system uses your custom compiled Clang and LLVM tools:
export PATH=/path/to/your/llvm-project/build/bin:$PATHThe kernel doesn't compile with Netfilter for whatever reason, so let's disable it.
- Run the configuration menu:
make LLVM=1 menuconfig-
Navigate through Networking Support -> Networking Options -> Netfilter, and disable it.
-
Save and Exit.
Build the kernel using the custom LLVM toolchain.
make LLVM=1 -j$(nproc)Once built, it can be used in a QEMU virtual machine, where you need to manually create the attacker and their GID in the init file.
This project didn't implement a user-modifiable value for the magic number for the backdoor, but also has some other drawbacks to be aware of. The following are potential upgrades:
- To not hardcode the offset for finding the GID from the credential struct, as this isn't consistent between kernel versions.
- There may be other functions that are better to attack that aren't "cap_capable()", for example, "cap_task_prctl()". It should be possible to leverage this function to directly modify the credential structure.