The quiter you become,the more you are able to hear!

syzkaller fuzz linux kernel环境搭建

Author: geneblue

Blog: https://geneblue.github.io/

安装

使用 syzkaller fuzz linux kernel,需要安装以下工具。

  • 支持 coverage 的 C 编译器
  • 支持 coverage 配置的 linux 内核
  • QEME 和 磁盘镜像或者真机
  • syzkaller

C 编译器

syzkaller 是个基于代码覆盖率的 fuzz工具,这要求内核需要支持代码覆盖,这就需要一个 支持代码覆盖的编译器来编译内核。gcc6 版本 231296 开始增加了对代码覆盖的支持,所以 我们可以使用 gcc6 来编译内核。

下载编译 gcc6:

1
2
3
4
5
6
7
8
9
10
11
svn checkout svn://gcc.gnu.org/svn/gcc/trunk gcc_src
cd gcc_src
svn ls -v ^/tags | grep gcc_8_2_0_release
svn up -r 262993
mkdir build
mkdir install
cd build/
sudo apt-get install flex bison libc6-dev libc6-dev-i386 linux-libc-dev linux-libc-dev:i386 libgmp3-dev libmpfr-dev libmpc-dev
../configure --enable-languages=c,c++ --disable-bootstrap --enable-checking=no --with-gnu-as --with-gnu-ld --with-ld=/usr/bin/ld.bfd --disable-multilib --prefix=gcc_src/install/
make -j16
make install

Linux 内核 和 gcc6 一样,内核本身也要增加对代码覆盖的支持。

  • build 内核时增加对代码覆盖的支持(CONFIG_KCOV)
  • 在系统调用 entry/exit 中增加额外的指令
  • 添加代码来跟踪报告每个任务的代码覆盖信息

KCOV 配置已经添加到了上游代码 linux4.6 中,对于较老的内核需要移植 commit 5c9a8750a6409c63a0f01d51a9024861022f6593,该commit 基本上就是在内核中添加对 KCOV 特性的支持。编译内核时推荐使用如下配置:

对代码覆盖的支持:

1
2
3
4
CONFIG_KCOV=y
CONFIG_KCOV_INSTRUMENT_ALL=y
CONFIG_KCOV_ENABLE_COMPARISONS=y
CONFIG_DEBUG_FS=y

在 web 接口显示代码覆盖:

1
CONFIG_DEBUG_INFO=y

内核符号信息:

1
2
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y

namespace 沙箱:

1
2
3
4
5
6
7
8
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
CONFIG_IPC_NS=y
CONFIG_PID_NS=y
CONFIG_NET_NS=y
CONFIG_CGROUP_PIDS=y
CONFIG_MEMCG=y
CONFIG_USER_NS=y

如果 kernel 运行在 VMs 中,在编译内核时可以使用 make kvmconfig

使用 Debian 文件镜像(由tools/create-image.sh生成)还需要:

1
2
CONFIG_CONFIGFS_FS=y
CONFIG_SECURITYFS=y

开启 KASAN 支持对 use-after-free 和 out-of-bounds 的检测:

1
2
CONFIG_KASAN=y
CONFIG_KASAN_INLINE=y

打开其他调试选项对 fuzz 的支持更好,如下是比较推荐的:

1
2
3
4
5
CONFIG_LOCKDEP=y
CONFIG_PROVE_LOCKING=y
CONFIG_DEBUG_ATOMIC_SLEEP=y
CONFIG_PROVE_RCU=y
CONFIG_DEBUG_VM=y

关闭下述配置:

1
# CONFIG_RANDOMIZE_BASE is not set

增加 RCU 时延:

1
CONFIG_RCU_CPU_STALL_TIMEOUT=60

编译 linux 内核:

1
2
3
4
5
6
7
8
9
10
git clone https://github.com/torvalds/linux.git $KERNEL
cd $KERNEL
make defconfig
make kvmconfig
# Edit .config to set CONFIG_KCOV=y
# Edit .config to set CONFIG_DEBUG_INFO=y
# Edit .config to set CONFIG_KASAN=y
make oldconfig
# Select KASAN_INLINE when prompted, leave other options default
make CC='$GCC/install/bin/gcc' -j64
编译时根据提示信息,其余配置选 N 即可。

QEMU 配置 syzkaller 在 QEMU 虚拟机中运行 fuzz 进程,所以这里还需要配置 QEMU,QEMU 的安装可以参考 QEMU 官网.

但以下几点需要注意: - fuzzing 进程需要和外面世界通信,所以 VM 镜像需要包含对 networking 的支持 - fuzzer 进程的程序文件需要通过 SSH 传入到 VM 中,所以 VM 镜像需要运行 SSH server - VM 的 SSH 配置应该被设置成允许 syz-manager 配置的 root 权限访问。还句话说,在执行 ssh -i $SSHID -p $PORT root@localhost 时没有任何提示,也不要求输入密码(SSHID 是 SSH 的凭证,PORT 表示 syz-manager 配置文件中指定的端口号) - 内核通过 debugfs 入口来导出 代码覆盖信息,所以 VM 镜像 需要 在 /sys/kernel/debug 处 mount debugfs 文件系统

create-image.sh 脚本用于创建一个 linux 镜像。

Syzkaller 也支持 kvmtools VMs,GCE VMs 或运行在真实的 Android 设备中。

Syzkaller syzkaller 是 go 语言编写而成,所以需要 go 编译器(>=1.9)来编译 syzkaller。

https://golang.org/dl/站点下载 go 包,将其解压到目录$HOME/go中,然后添加环境变量GOROOT=$HOME/go,PATH=$HOME/go/bin:$PATH,GOPATH=$HOME/gopath,运行命令go get -d github.com/google/syzkaller/... checkout 出 syzkaller 源码及其依赖,进入到 $GOPATH/src/github.com/google/syzkaller 目录,运行命令 make即可将 syzkaller 编译到 bin\ 目录下。

go 的站点被墙了,导致有些包下载不下来,可以到第三方站点上下载离线包,再手动解包。

1
2
3
wget https://dl.google.com/go/go1.10.linux-amd64.tar.gz
tar -zxvf go1.10.linux-amd64.tar.gz
mv go go-1.10

配置 go 环境变量

1
2
3
GOROOT=$HOME/go
PATH=$HOME/go/bin:$PATH
GOPATH=$HOME/gopath

使用 go 下载编译 syzkaller

1
2
3
go get -d github.com/google/syzkaller/...
cd $GOPATH/src/github.com/google/syzkaller
make

参考