
本仓库包含所有源代码,包括设置脚本。 现在拥有一个出色的UI,可查看警告以及对应的源文件。
Ubuntu >= 14.04.5 LTS
2018年2月16日:
请参考 Docker 使用 文档,了解如何在预构建的Docker容器中使用DR.CHECKER。
我们的实现基于LLVM,具体是LLVM 3.8。还需要像 c2xml 这样的工具来解析头文件。
首先,确保已安装 cmake(由设置/构建脚本使用)和 libxml(c2xml 所需):
sudo apt-get install cmake libxml2-dev
接下来,我们创建了一个单一的脚本,用于下载和构建所有必要的工具。
cd helper_scripts
python setup_drchecker.py --help
usage: setup_drchecker.py [-h] [-b TARGET_BRANCH] [-o OUTPUT_FOLDER]
optional arguments:
-h, --help 显示此帮助信息并退出
-b TARGET_BRANCH 要设置的LLVM分支(即版本)。默认值:release_38 例如:release_38
-o OUTPUT_FOLDER 所有内容需要设置的文件夹。
示例:
python setup_drchecker.py -o drchecker_deps
要完成设置,还需对本地 PATH 环境变量进行修改。设置脚本会给出您需要做的具体更改。
这取决于 设置 的成功完成。 我们有一个单一的脚本来构建所有内容,您无需操心。
cd llvm_analysis
./build.sh
这取决于 构建 的成功完成。 要运行DR.CHECKER分析内核驱动程序,首先需要将它们转换为LLVM位码。
首先,我们需要一个可构建的内核。这意味着您应该能够使用常规构建设置(即 make)来编译内核。
我们首先捕获 make 命令的输出,从中提取确切的编译命令。
make 的输出(或 makeout.txt)只需传递 V=1 并将输出重定向到文件。
示例:
make V=1 O=out ARCH=arm64 > makeout.txt 2>&1
注意:不要使用多处理器(即 -j)。多处理模式会搞乱输出文件,因为多个进程会尝试写入输出文件。
就这样。剩下的由DR.CHECKER处理。
运行DR.CHECKER分析需要几个步骤,所有这些步骤都封装在单个脚本 helper_scripts/runner_scripts/run_all.py 中。
如何运行:
python run_all.py --help
usage: run_all.py [-h] [-l LLVM_BC_OUT] [-a CHIPSET_NUM] [-m MAKEOUT] [-g COMPILER_NAME] [-n ARCH_NUM] [-o OUT] [-k KERNEL_SRC_DIR] [-skb] [-skl] [-skp] [-ske] [-ski] [-f SOUNDY_ANALYSIS_OUT]
optional arguments:
-h, --help 显示此帮助信息并退出
-l LLVM_BC_OUT 目标目录,用于存储所有生成的位码文件。
-a CHIPSET_NUM 芯片组编号。有效的芯片组编号为:
1(mediatek)|2(qualcomm)|3(huawei)|4(samsung)
-m MAKEOUT makeout.txt 文件的路径。
-g COMPILER_NAME makeout.txt 中使用的编译器名称,用于过滤编译命令。例如:aarch64-linux-android-gcc
-n ARCH_NUM 目标架构,32位(1)或64位(2)。
-o OUT out文件夹的路径。此文件夹在编译某些内核时可用作输出目录。(注意:并非所有内核都需要单独的out文件夹)
-k KERNEL_SRC_DIR 内核源代码的基础目录。
-skb 跳过LLVM构建(默认:不跳过)。
-skl 跳过Dr Linker(默认:不跳过)。
-skp 跳过解析头文件(默认:不跳过)。
-ske 跳过入口点识别(默认:不跳过)。
-ski 跳过稳健分析(默认:不跳过)。
-f SOUNDY_ANALYSIS_OUT 用于存储稳健分析输出的输出文件夹路径。
该脚本构建、链接并在所有驱动上运行DR.CHECKER,因此可能需要 相当长的时间(45分钟-90分钟)。如果希望手动对单个驱动运行DR.CHECKER,请参考 独立运行
上述脚本在多处理器模式下执行以下任务,以充分利用所有CPU核心:
生成的所有位码文件将放置在参数 -l 提供的文件夹中。
此步骤耗时较长,具体取决于您的核心数量。
因此,如果您已经完成了此步骤,可以通过传递 -skb 跳过。
此步骤执行链接,遍历所有位码文件,识别需要链接的相关位码文件,并将它们(使用 llvm-link)链接成一个合并的位码文件(该文件将与相应的位码文件存储在一起)。
与上一步类似,您可以通过传递 -skl 跳过此步骤。
此步骤查找头文件中的入口点声明,并将其配置存储在 LLVM 构建目录下的 hdr_file_config.txt 文件中。
要跳过:-skp
此步骤识别所有驱动合并位码文件中的入口点。
输出将存储在 LLVM 构建目录下的 entry_point_out.txt 文件中。
entry_point_out.txt 文件内容示例:
FileRead:hidraw_read:/home/drchecker/33.2.A.3.123/llvm_bc_out/drivers/hid/llvm_link_final/final_to_check.bc
FileWrite:hidraw_write:/home/drchecker/33.2.A.3.123/llvm_bc_out/drivers/hid/llvm_link_final/final_to_check.bc
IOCTL:hidraw_ioctl:/home/drchecker/33.2.A.3.123/llvm_bc_out/drivers/hid/llvm_link_final/final_to_check.bc
要跳过:-ske
此步骤将对 entry_point_out.txt 文件中的所有入口点运行DR.CHECKER。每个入口点的输出将存储在选项 -f 提供的文件夹中。
要跳过:-ski
现在,我们将展示一个从拥有内核源代码到获取漏洞警告的示例。
我们上传了一个联发科内核 33.2.A.3.123.tar.bz2。 首先下载并解压上述文件。
假设您将上述文件解压到名为 ~/mediatek_kernel 的文件夹中。
cd ~/mediatek_kernel
source ./env.sh
cd kernel-3.18
# 以下步骤可能不需要,取决于内核
mkdir out
make O=out ARCH=arm64 tubads_defconfig
# 以下命令将所有编译命令复制到 makeout.txt
make V=1 -j8 O=out ARCH=arm64 > makeout.txt 2>&1
cd <repo_path>/helper_scripts/runner_scripts
python run_all.py -l ~/mediatek_kernel/llvm_bitcode_out -a 1 -m ~/mediatek_kernel/kernel-3.18/makeout.txt -g aarch64-linux-android-gcc -n 2 -o ~/mediatek_kernel/kernel-3.18/out -k ~/mediatek_kernel/kernel-3.18 -f ~/mediatek_kernel/dr_checker_out
上述命令需要 一些时间(30分钟 - 1小时)。
首先,所有分析结果将位于文件夹 ~/mediatek_kernel/dr_checker_out(参数 -f 的值) 中,每个入口点会创建一个 .json 文件,其中包含所有警告(JSON 格式)。这些 json 文件按上下文组织警告。
其次,文件夹 ~/mediatek_kernel/dr_checker_out/instr_warnings(相对于参数 -f 的值) 包含按指令位置组织的警告。
这些警告可以使用我们的 可视化器 进行分析。
最后,每个入口点按类型组织的所有警告摘要将写入输出 CSV 文件:~/mediatek_kernel/dr_checker_out/warnings_stats.csv(相对于参数 -f 的值)。
-g 的值要提供选项 -g 的值,您需要知道用于编译内核的 *-gcc 二进制文件的名称。
一种简单的方法是 grep makeout.txt 中的 gcc,您会看到编译器命令,从中可以知道 *-gcc 二进制文件的名称。
对于上面的示例,如果您对示例构建执行 grep gcc makeout.txt,您会看到很多类似的行:
aarch64-linux-android-gcc -Wp,-MD,fs/jbd2/.transaction.o.d -nostdinc -isystem ...
因此,-g 的值应为 aarch64-linux-android-gcc。
如果要构建的内核是32位的,则二进制文件很可能是 arm-eabi-gcc
-a 的值根据芯片组类型,您需要提供相应的编号。
-o 的值这是在内核构建期间提供给 make 命令的 O= 选项的文件夹路径。
并非所有内核都需要单独的 out 路径。您可能在不提供选项 O 的情况下构建内核,在这种情况下,运行 run_all.py 时不应为该选项提供值。
我们提供了一个基于Web的UI来查看所有警告。请参考 可视化。
您可以通过取消注释 BugDetectorDriver.cpp 中对应的 #define DISABLE_* 行来禁用一个或多个漏洞检查器。
为了您的方便,我们还提供了一个脚本来后处理结果。 查看详情。
祝您使用愉快!!