syzkaller 使用记录
-
下载
go 环境
wget https://dl.google.com/go/go1.17.6.linux-amd64.tar.gz tar -xf go1.17.6.linux-amd64.tar.gz # 后面这两条命令建议设置到~/.bashrc文件中置 export GOROOT=`pwd`/goroot export PATH=$GOROOT/bin:$PATH
syzkaller 下载
git clone https://github.com/google/syzkaller cd syzkaller make (内存开大点)
-
配置 kernel
拉一个 kernel 的源码
git clone --branch v5.11 git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
生成配置文件
cd linux make defconfig make kvm_guest.config
修改 .config 文件(打开一些必要的配置)
# Coverage collection. CONFIG_KCOV=y # must # Debug info for symbolization. CONFIG_DEBUG_INFO=y # Memory bug detector CONFIG_KASAN=y CONFIG_KASAN_INLINE=y # Code coverage works better when KASLR Is disabled # CONFIG_RANDOMIZE_BASE is not set # 可选 CONFIG_KCOV_INSTRUMENT_ALL=y CONFIG_KCOV_ENABLE_COMPARISONS=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_KMEMLEAK=y # 后面 fuzz 启动的时候出现了文件系统的挂载错误,所以加上这个 CONFIG_CONFIGFS_FS=y CONFIG_SECURITYFS=y
重新生成配置并编译
make oldfconfig make -j4
用debootstrap 构建 linux 镜像
sudo apt-get install debootstrap 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
启动 qemu
sudo qemu-system-x86_64 -m 2G -smp 2 -kernel /home/abc/kernel/linux-5.11/arch/x86/boot/bzImage -append "console=ttyS0 root=/dev/sda earlyprintk=serial net.ifnames=0" -drive file=/home/abc/kernel/image/stretch.img,format=raw -net user,hostfwd=tcp:127.0.0.1:10021-:22 -net nic,model=e1000 -enable-kvm -nographic -pidfile vm.pid 2>&1 | tee vm.log
宿主机链接 ssh
ssh -i /home/abc/kernel/image/stretch.id_rsa -p 10021 -o "StrictHostKeyChecking no" root@localhost
连不上的话需要在 /etc/hosts.allow中 加上一句
sshd: ALL
关闭虚拟机
kill $(cat vm.pid)
-
启动 syzkaller
新建 cfg 文件
{ "target": "linux/amd64", "http": "127.0.0.1:56741", "workdir": "/home/abc/fuzz/syzkaller/workdir", "kernel_obj": "/home/abc/kernel/linux-5.11", "image": "/home/abc/kernel/image/stretch.img", "sshkey": "/home/abc/kernel/image/stretch.id_rsa", "syzkaller": "/home/abc/fuzz/syzkaller", "procs": 8, "type": "qemu", "vm": { "count": 4, "kernel": "/home/abc/kernel/linux-5.11/arch/x86/boot/bzImage", "cpu": 2, "mem": 2048, "qemu_args":"-enable-kvm" } }
启动 fuzz
sudo ./bin/syz-manager -config=fuzz.cfg
但这种方法寄掉了,所以只能先启动 qemu,再用 isolated 模式连过去
{ "target": "linux/amd64", "http": "127.0.0.1:56741", "rpc": "127.0.0.1:0", "sshkey" : "/home/abc/kernel/image/stretch.id_rsa", "workdir": "/home/abc/fuzz/syzkaller/workdir", "kernel_obj": "/home/abc/kernel/linux-5.11", "syzkaller": "/home/abc/fuzz/syzkaller", "sandbox": "setuid", "type": "isolated", "vm": { "targets" : [ "127.0.0.1:10021" ], "pstore": false, "target_dir" : "/home/fuzzdir", "target_reboot" : false } }
其中各字段的含义:
target指定待测试设备的操作系统内核及cpu架构 vm.targets指定待fuzz设备的ip地址及ssh端口(默认是22) enbale_syscalls:测试特定的几个系统调用 disable_syscalls:不调用某几个系统调用
-
提高 fuzz 效率
通过定制 syscall description 文件(syzkaller 自定义的语法),实现对部分驱动的针对性 fuzz。
直接编译进内核
1.在 kernel_src/drivers/char 下新建 test.c
#include <linux/init.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/uaccess.h> #include <linux/slab.h> static int proc_open (struct inode *proc_inode, struct file *proc_file) { printk(":into open!\n"); return 0; } static ssize_t proc_read (struct file *proc_file, char __user *proc_user, size_t n, loff_t *loff) { printk(":into read"); return 0; } static ssize_t proc_write (struct file *proc_file, const char __user *proc_user, size_t n, loff_t *loff) { char *c = kmalloc(512, GFP_KERNEL); copy_from_user(c, proc_user, 4096); printk(":into write!\n"); return 0; } static struct proc_ops test_op = { .proc_open = proc_open, .proc_read = proc_read, .proc_write = proc_write, }; static int __init mod_init(void) { proc_create("test1", S_IRUGO|S_IWUGO, NULL, &test_op); printk(":proc init over!\n"); return 0; } module_init(mod_init);
2.在 char/ 下的 Kconfig 文件中添加:
config TEST_MODULE tristate "heap overflow test" default y help This file is to test a buffer overflow
3.在 char/ 目录下的 Makefile 文件中添加:
obj-$(CONFIG_TEST_MODULE) += test.o
4.重新编译内核
make clean make menuconfig make -j8
这时已经能看到加载的模块了
验证是否成功:
ls /proc/test1
5.定制 txt 系统调用描述文件
在 syzkaller 中的 sys/linux/ 下新建 proc_test.txt
include <linux/fs.h> open$proc(file ptr[in, string["/proc/test1"]], flags flags[proc_open_flags], mode flags[proc_open_mode]) fd read$proc(fd fd, buf buffer[out], count len[buf]) write$proc(fd fd, buf buffer[in], count len[buf]) close$proc(fd fd) proc_open_flags = O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, FASYNC, O_CLOEXEC, O_CREAT, O_DIRECT, O_DIRECTORY, O_EXCL, O_LARGEFILE, O_NOATIME, O_NOCTTY, O_NOFOLLOW, O_NONBLOCK, O_PATH, O_SYNC, O_TRUNC, __O_TMPFILE proc_open_mode = S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH
6.用 syz-extract 生成 const 文件
用之前需要先编译:
make bin/syz-extract
bin/syz-extract -os linux -arch amd64 -sourcedir "/home/abc/kernel/linux-5.11" proc_test.txt
然后用 syzgen 生成 const 文件
bin/syz-sysgen
7.重新编译 syzkaller
make clean make all
8.创建新的 cfg 文件
{ "target": "linux/amd64", "http": "127.0.0.1:56741", "rpc": "127.0.0.1:0", "sshkey" : "/home/abc/kernel/image/stretch.id_rsa", "workdir": "/home/abc/fuzz/syzkaller/workdir", "kernel_obj": "/home/abc/kernel/linux-5.11", "syzkaller": "/home/abc/fuzz/syzkaller", "sandbox": "setuid", "type": "isolated", "enable_syscalls":[ "open$proc", "read$proc", "write$proc", "close$proc" ], "vm": { "targets" : [ "127.0.0.1:10021" ], "pstore": false, "target_dir" : "/home/fuzzdir", "target_reboot" : false } }
跑起来,过一会就有结果了
sudo ./bin/syz-manager -config=./cfg/fuzz-test.cfg
-
参考文献