syzkaller入门

syzkaller 入门

简介

用户通过 syscall 来访问操作系统提供的功能和资源,syzkaller 专门用来测试那些内核系统调用实现(简称syscall)中的bug。

Fuzzing 是一种自动化的方法,它将随机值作为输入提供给一个软件,希望能够发现开发者未曾尝试过的有问题的输入组合导致的错误。

syzkaller 不会盲目地生成测试输入,我们通过描述 syscall 的参数期望被如何使用来限制我们的集合。通过这样做,我们可以利用可用资源在更大的调用集上提供随机测试。

用到的另一个 fuzzing 优化技术被叫做代码覆盖率引导的 fuzzing。这项技术测量每个输入所实现的代码覆盖率,尝试让输入的代码覆盖率最大。每个增加代码覆盖率的输入都会被变异,以便增加测试的总体范围(即访问更多函数,分支)。对于一个 fuzz 目标的输入集被称为语料库(即原始的测试用例)。

Syzkaller是一个无监督的内核 fuzzer ,它使用上述两种技术fuzz Syscalls。

在这篇文章中,我将分享我的一些使用经验。

项目地址:google/syzkaller: syzkaller is an unsupervised coverage-guided kernel fuzzer (github.com)

安装

安装主要参照 syzkaller 官方文档:syzkaller/setup.md at master · google/syzkaller (github.com)

环境:

  • vmware虚拟机:Ubuntu 20.04
  • 请确保有足够的空间(40 G 空间可以,但是不要放在机械硬盘里面,虚拟机会很慢)

使用 syzkaller 需要以下组件:

  • Go compiler and syzkaller itself
  • C compiler with coverage support
  • Linux kernel with coverage additions
  • Virtual machine or a physical device

Ubuntu host 需要的依赖

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

Go

syzkaller 基于 Go 语言编写,为了编译它我们需要 Go 环境

1
2
3
4
5
6
7
8
wget https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz
tar -xf go1.14.2.linux-amd64.tar.gz
mv go goroot
mkdir gopath
export GOPATH=`pwd`/gopath
export GOROOT=`pwd`/goroot
export PATH=$GOPATH/bin:$PATH
export PATH=$GOROOT/bin:$PATH

编译 syzkaller

1
2
3
go get -u -d github.com/google/syzkaller/prog
cd gopath/src/github.com/google/syzkaller/
make

编译 kernel

Linux Kernel 源码下载($KERNEL 替换为你想要的目录)

1
git clone --branch v5.14 git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git $KERNEL

这里我们采用官方文档提供的 git 方式下载 5.14版本的内核,这种方式下载会比较慢,好处是获取不同版本的内核也很方便,方便管理

1
2
3
make kernelversion  # 查看内核版本
git tag # 查看tag(是一个固化的分支)
git checkout v4.17 # 切换到4.17版本的内核源码

生成默认配置

1
2
3
cd $KERNEL
make defconfig # 生成默认配置文件.config
make kvm_guest.config # kvm配置

开启必要的内核配置选项以启动syzkaller,在.config文件末尾添加如下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 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

编译内核,这个过程会比较漫长

1
2
make olddefconfig    # 将当前内核源码的新特性加入.config中去
make -j`nproc` # 开始编译

出现Kernel: arch/x86/boot/bzImage is ready (#3)标志已经完成。

也可以以下命令查看是否成功:

1
2
3
4
ls $KERNEL/vmlinux
# sample output - $KERNEL/vmlinux
ls $KERNEL/arch/x86/boot/bzImage
# sample output - $KERNEL/arch/x86/boot/bzImage

创建镜像

安装debootstrap工具,可以用来构建最基本的系统。

1
sudo apt-get install debootstrap

创建 Debian Stretch Linux 镜像,$IMAGE 替换为你想要的目录,执行以下命令

1
2
3
4
5
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/stretch.img 这个文件就是构建好的磁盘镜像文件

或者创建 Debian Buster Linux 镜像,执行以下命令

1
./create-image.sh --distribution buster

安装额外的工具,一些在VM中有用的包和工具

1
2
./create-image.sh --feature full  # 要安装一组我们认为有用的工具,请执行(请随意编辑脚本中的工具列表) 
./create-image.sh --add-perf # 要安装perf(不需要运行syzkaller;需要$kernel指向内核源):

问题:我在这一步因为空间不够导致报错

如果想要去删除这个镜像,重新安装,在$IMAGE目录下面不能成功删除chroot/,需要在/mnt/目录下面删除。

安装 QEMU

使用以下命令安装

1
sudo apt install qemu-system-x86

在 VMware 上使用 Linux 则应当在设置中把 虚拟化 Intel VT-x/EPT 或 AMD-V/RVI(V) 打开

如果安装过 windows docker 或者 wsl2 的需要关闭hype-v,这会导致 docker 和 wsl 2 不能正常工作:

1
bcdedit /set hypervisorlaunchtype off  # 以管理员身份运行命令提示符执行命令,彻底关闭hype-v

验证内核是否能够启动(注意$KERNELIMAGE的路径):

1
2
3
4
5
6
7
8
9
10
11
12
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 账户登录,没有密码

image-20211205114827224

在另一个 shell 中验证是否能 ssh 连接虚拟机:

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

关闭正在运行中的QWMU实例:

  1. 按下Ctrl + A然后x
  2. 或者使用命令:kill $(cat vm.pid)

验证QEMU工作,内核启动并且ssh也可以连接之后,我们可以关闭QEMU然后尝试去运行syzkaller了

配置 syzkaller 并尝试运行

我们需要为 syzkaller 编写额外的配置文件my.cfg,这里需要注意替换环境变量为你自己的路径:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"target": "linux/amd64",
"http": "127.0.0.1:56741",
"workdir": "$GOPATH/src/github.com/google/syzkaller/workdir",
"kernel_obj": "$KERNEL",
"image": "$IMAGE/stretch.img",
"sshkey": "$IMAGE/stretch.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
}
}

$GOPATH/src/github.com/google/syzkaller/目录下,运行 syzkaller manage:

1
2
mkdir workdir                      # workdir 是配置文件里面填的工作目录
./bin/syz-manager -config=my.cfg # my.cfg 是额外的配置文件的名字

启动成功后,我们可以通过访问 localhost:56741 来获取 syzkaller 的状态

image-20211205125050369

问题:qemu崩溃,报错如下:

1
2
qemu-system-x86_64: error: failed to set MSR 0x48b to 0x159ff00000000
qemu-system-x86_64: /build/qemu-EmNSP4/qemu-4.2/target/i386/kvm.c:2947: kvm_put_msrs: Assertion `ret == cpu->kvm_msr_buf->nmsrs' failed.

最简单的解决方法是在 syz-manager 配置文件中将qemu_args设置为-enable-kvm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"target": "linux/amd64",
"http": "127.0.0.1:56741",
"workdir": "$GOPATH/src/github.com/google/syzkaller/workdir",
"kernel_obj": "$KERNEL",
"image": "$IMAGE/stretch.img",
"sshkey": "$IMAGE/stretch.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,
"qemu_args": "-enable-kvm"
}
}

syzkaller 如何工作

syzkaller系统的流程结构如下图所示,红色标签表示相应的配置选项。

Process structure for syzkaller

  • syz-manager :控制整个 syzkaller 模糊测试系统
    • 启动、监视并且重启多个虚拟机,并在这些虚拟机里面通过sshd调用syz-fuzzer
    • 使用RPC与虚拟机中的syz-fuzzer交流实现的覆盖率和fuzzing过程中的任何跟踪信息,比如crash和corpus.。
    • 将得到的信息存储在本地workdir目录下
    • 通过设置http公开一个基于web的界面,在这个界面可以浏览存储的信息
  • syz-fuzzer :负责引导整个 fuzz 的过程:
    • 输入的生成,变异,语料最小化等。
    • 启动 syz-executor 进程进行 fuzz
    • 从被 fuzz 的 kernel 的 /sys/kernel/debug/kcov 获得覆盖的相关信息
    • 通过RPC将触发新代码覆盖的输入发送回syz-manager
  • syz-executor:负责执行单个输入(一系列 syscalls)
    • syz-fuzzer接收程序并执行,然后返回结果
    • 它被设计为尽可能简单(为了不干扰 fuzzing 进程),用C++编写,编译为静态二进制,并使用共享内存进行通信。

描述 syscalls

syz-fuzzer进程根据描述的 syscalls 生成由syz-executor执行的程序。

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2021 Sung
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信