Healer的安装和初步使用
简介
Healer 是受 Syzkaller 启发的内核模糊测试器。
与 Syzkaller 类似,Healer 使用 Syzlang 描述提供的 syscall 信息生成确认参数结构约束和部分语义约束的系统调用序列,并通过不断执行生成的调用序列导致内核崩溃,从而发现内核错误。
与 Syzkaller 不同,Healer 不使用经验选择表,而是通过动态移除最小化调用序列中的调用并观察覆盖变化,来检测系统调用之间的影响关系,并利用影响关系来指导调用序列的生成和变异。 此外,Healer 还使用了与 Syzkaller 不同的架构设计。
构建Healer
-
除了一些修补代码之外,Healer 是用纯rust编写的。 因此,首先应安装 rust 工具链。
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustc --version # check install
检查安装结果:
-
为了使用 Syzlang 描述,Healer 的构建脚本会自动下载 Syzkaller 并在源代码中添加补丁并构建 Syzkaller,这可能会增加构建时间。 因此,需要安装Syzkaller 所需的构建工具,例如:GO111MODULE开启的golang 编译器,GCC 6.1.0 或更高版本。
-
GO111MODULE的开启命令:
go env -w GO111MODULE="on" go env #check
-
-
一旦安装了所有必需的工具,就可以使用以下命令轻松构建 Healer:
cargo build --release
-
最后,可以在
target/release
目录中找到 Healer 本身和打补丁的 Syzkaller 二进制文件 (syz-bin
)。
使用 Healer 对 Linux 内核进行模糊测试
总的来说,使用 Healer 对 Linux 内核进行模糊测试需要三个步骤:(1) 准备磁盘映像,(2) 编译内核, (3) 启动 Healer。
Healer 使用 qumu 来引导内核,所以需要准备磁盘镜像和内核镜像。启动后的 qemu 需要能够通过 ssh 密钥登录,内核至少需要具备 kcov 功能。(可以参照Syzkaller文档的详细介绍)
先决条件
sudo apt update
sudo apt install make gcc flex bison libncurses-dev libelf-dev libssl-dev
准备磁盘映像
安装 debootstrap
sudo apt install debootstrap
创建 Debian Stretch Linux 映像
mkdir $IMAGE
cd $IMAGE/ wget https://raw.githubusercontent.com/google/syzkaller/master/tools/create-image.sh -O create-image.sh
chmod +x create-image.sh
./create-image.sh
- 注意将
$IMAGE
替换为自己的路径。
附加工具
./create-image.sh --feature full
./create-image.sh --add-perf
编译内核
获取内核源码
git clone --branch v5.14 git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git $KERNEL
- 建议从最新的稳定版本开始。V5.14是一个示例。
- 在虚拟机中
git clone
运行时间较长。在较好的网络环境下,可以选择在物理机中前往https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/
下载内核源码的压缩包,然后拖入虚拟机解压
生成默认配置
cd $KERNEL
make defconfig
make kvm_guest.config
- 同样注意将
$IMAGE
替换为自己的路径。
启用所需的配置选项
- 手动编辑
.config
文件来启用它们:
# Coverage collection.
CONFIG_KCOV=y
# Debug info for symbolization.
CONFIG_DEBUG_INFO=y
# Memory bug detector
CONFIG_KASAN=y
CONFIG_KASAN_INLINE=y
# Required for Debian Stretch
CONFIG_CONFIGFS_FS=y
CONFIG_SECURITYFS=y
-
重新生成配置:
make olddefconfig
编译内核命令
make -j`nproc`
-
检查:
ls $KERNEL/vmlinux # sample output - $KERNEL/vmlinux ls $KERNEL/arch/x86/boot/bzImage # sample output - $KERNEL/arch/x86/boot/bzImage
安装QEMU
命令
sudo apt install qemu-system-x86
核查
-
先确定虚拟机的处理器开启
虚拟化引擎
-虚拟化Intel VT-x/EPT或AMD-V/RVI
(我使用的是VMware Workstation) -
确认
sshd
开启ps -e |grep ssh
-
如果没有出现
sshd
,则输入命令:/etc/init.d/ssh start
-
-
正式启动QEMU:
qemu-system-x86_64 \ -m 2G \ -smp 2 \ -kernel $KERNEL/arch/x86/boot/bzImage \ -append "console=ttyS0 root=/dev/sda earlyprintk=serial net.ifnames=0" \ -drive file=$IMAGE/stretch.img,format=raw \ -net user,host=10.0.2.10,hostfwd=tcp:127.0.0.1:10021-:22 \ -net nic,model=e1000 \ -enable-kvm \ -nographic \ -pidfile vm.pid \ 2>&1 | tee vm.log
- 同样注意路径替换
- 输入root即可登录
-
此后,可以在另一终端中测试ssh能否工作
ssh -i $IMAGE/stretch.id_rsa -p 10021 -o "StrictHostKeyChecking no" root@localhost
运行Healer
-
一旦
stretch.img
($IMAGE/stretch.img
)、ssh-stretch.id_rsa
($IMAGE/ssh-stretch.id_rsa
)、bzImage
($KERNEL/linux-5.14/arch/x86/boot/bzImage
准备就绪,建议是创建一个工作目录workdir
。 然后,在workdir
中创建一个bin
目录,并将修补后的Syzkaller
二进制文件和修复程序二进制文件复制到该目录中(healer-main/target/release/syz-bin
),注意不要更改syz-bin
目录结构。 最终的工作目录需要有以下文件。cd path/to/workdir && ls bin bzImage stretch.id_rsa stretch.img ls ./bin healer linux_amd64 syz-repro syz-symbolize syz-sysgen
-
最后,在
workdir
执行以下命令开始模糊测试,其中 -d 指定磁盘映像的路径,-k 指定内核映像的路径,–ssh-key 指定 ssh 密钥的路径。sudo ./bin/healer -d stretch.img --ssh-key stretch.id_rsa -k bzImage
-
若正常运行,界面如下:
遇到的错误
1
$ sudo ./bin/healer -d stretch.img --ssh-key stretch.id_rsa -k bzImage
___ ___ ______ ________ __ ______ ______
/__/\ /__/\ /_____/\ /_______/\ /_/\ /_____/\ /_____/\
\::\ \\ \ \\::::_\/_\::: _ \ \\:\ \ \::::_\/_\:::_ \ \
\::\/_\ .\ \\:\/___/\\::(_) \ \\:\ \ \:\/___/\\:(_) ) )_
\:: ___::\ \\::___\/_\:: __ \ \\:\ \____\::___\/_\: __ `\ \
\: \ \\::\ \\:\____/\\:.\ \ \ \\:\/___/\\:\____/\\ \ `\ \ \
\__\/ \::\/ \_____\/ \__\/\__\/ \_____\/ \_____\/ \_\/ \_\/
[2021-11-28T05:20:10Z INFO healer_fuzzer] loading target linux/amd64...
[2021-11-28T05:20:15Z INFO healer_fuzzer] pre-booting one vm...
Error: failed to boot qemu
Caused by:
boot: failed to boot in 0s: "qemu-system-x86_64" "-display" "none" "-serial" "stdio" "-no-reboot" "-snapshot" "-device" "virtio-rng-pci" "-enable-kvm" "-cpu" "host,migratable=off" "-m" "4096" "-smp" "2" "-device" "e1000,netdev=net0" "-netdev" "user,id=net0,host=10.0.2.10,hostfwd=tcp::1025-:22" "-drive" "file=/home/yuhan/workdir/stretch.img,index=0,media=disk" "-kernel" "/home/yuhan/workdir/bzImage" "-append" "root=/dev/sda console=ttyS0 kvm-intel.nested=1 kvm-intel.unrestricted_guest=1 kvm-intel.vmm_exclusive=1 kvm-intel.fasteoi=1 kvm-intel.ept=1 kvm-intel.flexpriority=1 kvm-intel.vpid=1 kvm-intel.emulate_invalid_guest_state=1 kvm-intel.eptad=1 kvm-intel.enable_shadow_vmcs=1 kvm-intel.pml=1 kvm-intel.enable_apicv=1 earlyprintk=serial oops=panic nmi_watchdog=panic panic_on_warn=1 panic=1 ftrace_dump_on_oops=orig_cpu vsyscall=native net.ifnames=0 biosdevname=0" "-device" "ivshmem-plain,memdev=hostmem0" "-object" "memory-backend-file,size=4194304,share,mem-path=/dev/shm/healer-in_shm-0-35410,id=hostmem0" "-device" "ivshmem-plain,memdev=hostmem1" "-object" "memory-backend-file,size=16777216,share,mem-path=/dev/shm/healer-out_shm_0-35410,id=hostmem1"
stderr:
failed to boot, qemu exited with: signal: 6 (core dumped)
cmdline: "qemu-system-x86_64" "-display" "none" "-serial" "stdio" "-no-reboot" "-snapshot" "-device" "virtio-rng-pci" "-enable-kvm" "-cpu" "host,migratable=off" "-m" "4096" "-smp" "2" "-device" "e1000,netdev=net0" "-netdev" "user,id=net0,host=10.0.2.10,hostfwd=tcp::1025-:22" "-drive" "file=/home/yuhan/workdir/stretch.img,index=0,media=disk" "-kernel" "/home/yuhan/workdir/bzImage" "-append" "root=/dev/sda console=ttyS0 kvm-intel.nested=1 kvm-intel.unrestricted_guest=1 kvm-intel.vmm_exclusive=1 kvm-intel.fasteoi=1 kvm-intel.ept=1 kvm-intel.flexpriority=1 kvm-intel.vpid=1 kvm-intel.emulate_invalid_guest_state=1 kvm-intel.eptad=1 kvm-intel.enable_shadow_vmcs=1 kvm-intel.pml=1 kvm-intel.enable_apicv=1 earlyprintk=serial oops=panic nmi_watchdog=panic panic_on_warn=1 panic=1 ftrace_dump_on_oops=orig_cpu vsyscall=native net.ifnames=0 biosdevname=0" "-device" "ivshmem-plain,memdev=hostmem0" "-object" "memory-backend-file,size=4194304,share,mem-path=/dev/shm/healer-in_shm-0-35410,id=hostmem0" "-device" "ivshmem-plain,memdev=hostmem1" "-object" "memory-backend-file,size=16777216,share,mem-path=/dev/shm/healer-out_shm_0-35410,id=hostmem1"
STDERR:
qemu-system-x86_64: error: failed to set MSR 0x48f to 0x7fffff00036dfb
qemu-system-x86_64: /build/qemu-A1914X/qemu-4.2/target/i386/kvm.c:2691: kvm_buf_set_msrs: Assertion `ret == cpu->kvm_msr_buf->nmsrs' failed.
解决方案
找到healer-main/healer_utils/healer_vm/src/qemu.rs
,这是healer中关于qemu的配置文件。将“linux/amd64”
的对应参数args
改为:"-enable-kvm"
(下图中的第487行)。
:2691: kvm_buf_set_msrs: Assertion `ret == cpu->kvm_msr_buf->nmsrs’ failed.
参考链接
- https://github.com/SunHao-0/healer