Skip to content
 编辑

Setup: Ubuntu host, QEMU vm, x86-64 kernel

环境配置:Ubuntu 主机,QEMU 虚拟机,x86-64 内核

本文档介绍了在主机为 Ubuntn 系统、QEMU 实例为 Debian Bullseye 系统的环境中,使用 QEMU 对 x86-64 内核进行模糊测试的步骤。

以下内容使用 $VAR 的形式 (例如 $GCC, $KERNEL 等) 来表示目录路径。这些目录是在执行指令时创建的 (例如,解压 GCC 归档文件时自动创建的目录), 或是你事先自行创建的。请手动将这些变量替换为实际路径。

依赖安装

命令:

sudo apt update
sudo apt install make gcc flex bison libncurses-dev libelf-dev libssl-dev

GCC 配置

如果你的发行版自带的 GCC 版本较旧,推荐从 这里 获取最新的 GCC 版本。将安装包下载并解压到 $GCC 目录下。确保你可以在 $GCC/bin/ 目录下找到对应的 GCC 文件。

Ubuntu 20.04 LTS: 如果你使用的是该版本的 Ubuntu 系统,可以忽略这一步骤,因为该版本中的 GCC 已经是最新的版本了。

如果你想要确认 GCC 是否符合要求,可以执行以下命令:

ls $GCC/bin/
# 正确的输出结果示例:
# cpp     gcc-ranlib  x86_64-pc-linux-gnu-gcc        x86_64-pc-linux-gnu-gcc-ranlib
# gcc     gcov        x86_64-pc-linux-gnu-gcc-9.0.0
# gcc-ar  gcov-dump   x86_64-pc-linux-gnu-gcc-ar
# gcc-nm  gcov-tool   x86_64-pc-linux-gnu-gcc-nm

内核配置

克隆 Linux 内核源代码

执行命令:

git clone --branch v6.2 git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git $KERNEL

我们建议从最新的稳定版本开始。这里的 v6.2 只是一个示例,实际操作时替换成对应的最新版本。

生成默认配置

命令:

cd $KERNEL
make defconfig
make kvm_guest.config

如果你想要指定编译器,可以按以下方法操作。

命令:

cd $KERNEL
make CC="$GCC/bin/gcc" defconfig
make CC="$GCC/bin/gcc" kvm_guest.config

启用必需内核选项

启用 syzkaller 所需的内核配置选项,具体信息参考 这里 。 不是所有选项都是必需的,但是至少确保启用以下选项:

# 覆盖率收集
CONFIG_KCOV=y

# 用于符号化的调试信息
CONFIG_DEBUG_INFO_DWARF4=y

# 内存错误检测器
CONFIG_KASAN=y
CONFIG_KASAN_INLINE=y

# Debian Stretch 及更高版本所必需的选项
CONFIG_CONFIGFS_FS=y
CONFIG_SECURITYFS=y

编辑并启用 .config 文件 (你也可以通过 make menuconfig 完成这一步骤)。

因为启用这些选项会产生更多可选的子选项,所以我们需要重新生成配置:

命令:

make olddefconfig

如果你想指定编译器,执行以下命令

命令:

make CC="$GCC/bin/gcc" olddefconfig

如果你愿意,还可以在 syzkaller 配置中禁用可预测的网络接口名称机制(详情参见 这里)或者通过更新以下内核配置参数来实现禁用:

CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE="net.ifnames=0"

编译内核

命令:

make -j`nproc`

你同样可以通过以下命令继续指定编译器。

命令:

make CC="$GCC/bin/gcc" -j`nproc`

完成以上步骤后,你应该可以找到 vmlinux(内核二进制文件)和 bzImage (压缩的内核镜像),通过以下步骤检查这两个文件是否存在。

命令:

ls $KERNEL/vmlinux
# 输出示例 - $KERNEL/vmlinux
ls $KERNEL/arch/x86/boot/bzImage
# 输出示例 - $KERNEL/arch/x86/boot/bzImage

镜像

安装 debootstrap

命令:

sudo apt install debootstrap

创建 Debian Bullseye Linux 镜像

创建一个包含必需软件包的最简 Debian Bullseye 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/bullseye.img 磁盘镜像。

或者创建不同版本的 Debian Linux 镜像

要创建不同版本的 Debian 镜像(例如 buster, stretch, sid),请指定 --distribution 选项。

命令:

./create-image.sh --distribution buster

安装扩展工具

有时在 VM 中安装一些额外的工具也是有用的, 尽管这些工具不是运行 syzkaller 所必需的。你可以通过以下命令安装一些你认为会有帮助的工具 (允许自定义脚本中要安装的工具列表)。

命令:

./create-image.sh --feature full

安装 perf 请执行以下命令(这个选项不是运行 syzkaller 必需的;安装 perf 需要 $KERNEL 指向内核源代码)。

命令:

./create-image.sh --add-perf

关于 create-image.sh 的更多选项, 使用 ./create-image.sh -h 了解详细信息。

QEMU

安装 QEMU

命令:

sudo apt install qemu-system-x86

验证是否成功安装

确保内核可以启动并且 sshd 服务能够正常启用。

命令:

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/bullseye.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
early console in setup code
early console in extract_kernel
input_data: 0x0000000005d9e276
input_len: 0x0000000001da5af3
output: 0x0000000001000000
output_len: 0x00000000058799f8
kernel_total_size: 0x0000000006b63000

Decompressing Linux... Parsing ELF... done.
Booting the kernel.
[    0.000000] Linux version 4.12.0-rc3+ ...
[    0.000000] Command line: console=ttyS0 root=/dev/sda debug earlyprintk=serial
...
[ ok ] Starting enhanced syslogd: rsyslogd.
[ ok ] Starting periodic command scheduler: cron.
[ ok ] Starting OpenBSD Secure Shell server: sshd.

完成这些之后,你应该可以在另一个终端中通过 ssh 连接到 QEMU 实例。

命令:

ssh -i $IMAGE/bullseye.id_rsa -p 10021 -o "StrictHostKeyChecking no" root@localhost

故障排除

如果连接失败并提示 “too many tries”, 可能是因为 ssh 在显式传递的密钥 (通过 -i 指定)之前传递了默认密钥。可以通过添加选项 -o "IdentitiesOnly yes" 解决这个问题。

终止 QEMU 实例请按 Ctrl+A 然后按 X 或者运行以下命令。

命令:

kill $(cat vm.pid)

如果 QEMU 工作正常,内核能够正常启动并且 ssh 连接成功,你可以尝试关闭 QEMU 实例并运行 syzkaller。

syzkaller

按照 这里 的描述编译安装 syzkaller 。 然后创建一个如下所示的管理器配置文件,将环境变量 $GOPATH, $KERNEL$IMAGE 替换为实际值。

{
	"target": "linux/amd64",
	"http": "127.0.0.1:56741",
	"workdir": "$GOPATH/src/github.com/google/syzkaller/workdir",
	"kernel_obj": "$KERNEL",
	"image": "$IMAGE/bullseye.img",
	"sshkey": "$IMAGE/bullseye.id_rsa",
	"syzkaller": "$GOPATH/src/github.com/google/syzkaller",
	"procs": 8,
	"type": "qemu",
	"vm": {
		"count": 4,
		"kernel": "$KERNEL/arch/x86/boot/bzImage",
		"cpu": 2,
		"mem": 2048
	}
}

运行 syzkaller 管理器:

mkdir workdir
./bin/syz-manager -config=my.cfg

现在 syzkaller 应该已经运行起来了,你可以通过 Web 浏览器在 127.0.0.1:56741 查看管理器状态。

如果在 syz-manager 启动后遇到问题,可以考虑使用 -debug 标志运行它。 另请参阅 这一页 获取故障排除提示。