A simple LLVM Pass for tracing hardware input propagation within Linux drivers.
To evaluate whether Linux driver can be fuzzing from a hardware input perspective for coverage improvement, a simple pass was built to perform static analysis on Linux kernel.
The insight is that if a hardware input can affect the branch/jmp operation during driver code, it may help for increasing fuzzing coverage.
- LLVM (The pass was implemented based on llvm-9.0.0)
- Clang (Same version as LLVM)
- CMake
- Linux Kernel
-
Download and build llvm-9.0.0, and one may build clang as well.
// After downloading and extracting llvm-9.0.0 & clang-9.0.0 (cfe-9.0.0) // Build with clang mv cfe-9.0.0.src llvm-9.0.0.src/tools/clang mkdir build cd build cmake ../llvm-9.0.0.src -DLLVM_TARGETS_TO_BUILD=X86 -DCMAKE_BUILD_TYPE=Release make -j4When finished, one can find the executable llvm & clang under
build/bin. (One may usemake installto install it.)See more details from the official documentation.
-
Copy the
ValuePropagateinto llvm source code directory (llvm-9.0.0.src/lib/Transforms), as the following structure:llvm_9.0.0 ├── build (3) ├── llvm-9.0.0.src/lib/Transforms │ ├── ValuePropagate │ │ ├── ValuePropagate.cpp │ │ └── CMakeLists.txt (1) │ ├── Arm64ValuePropagate │ │ ├── Arm64ValuePropagate.cpp │ │ └── CMakeLists.txt │ ├── CMakeLists.txt (2) ... -
Add the following contents in the
CMakeLists.txt(2):add_subdirectory(ValuePropagate) add_subdirectory(Arm64ValuePropagate) -
Back to your llvm compile directory (For me which is
llvm_9.0.0/build(3)), it should be in the same catalogue asllvm-9.0.0.src) -
Compile the pass with llvm.
make -j4
The ValuePropagate Pass takes the Linux driver llvm bitcode as input, it could used by opt to perform static analysis, and finally gives a simple tree structure output.
-
ValuePropagatefor x86 arch Linux Kernel. -
Arm64ValuePropagatefor AArch64 arch Linux Kernel.
One can obtain the input bitcode file from the following methods:
- To perform analysis on single hardware driver source file:
- Complie the driver source file using
clangwith-emit-llvmflag to get the bitcode file. example/rtc.cis the rtc driver source file in x86 Linux Kernel(arch/x86/kernel/rtc.c), one can use clang to get its bitcode file.clang -S --emit-llvm example/rtc.c -o example/rtc.ll- One may find nothing with only a single driver file cause the hardware input not happened here.
- Complie the driver source file using
- To perform analysis on each driver module:
- One may use difuze to obtain a series of driver modules. (difuze use
llvm-linkto link each driver module into a single bitcode file.)
- One may use difuze to obtain a series of driver modules. (difuze use
- To perform analysis on the whole Linux kernel:
- Compile the Linux kernel into a single bitcode file, one may use wllvm to compile it.
- The analysis process on the whole kernel may be very slow.
Use opt to perform the static analysis on Linux driver bitcode file.
opt -load ./llvm_9.0.0/build/lib/LLVMValuePropagate.so -ValuePropagate -analyze example/rtc.ll | tee output.log
Check the dummy output file.
Each hardware input start from a function which use an input assembly instruction (in/mov in X86, ldr in ARM64) to obtain a hardware input from an external device (via driver code), then follow with a variable use-chain where the input value propagate on, and finally end at a br/ret instruction.
There are still some unhandled situation during static analysis, but it seems that the hardware input does not affect the branch/jmp operation during driver code too much.. so yes, this may just a failed exploration.