本文记录了我的syzkaller安装和使用的踩坑记录 。
syzkaller是2015年Google提出的一款主要用Go编写的基于覆盖率的内核fuzzer。 2017年它的持续性fuzzing平台syzbot部署上线,迄今为止已经挖掘并报告了超过4000个内核漏洞。
强烈不建议在虚拟机中安装syzkaller并进行内核fuzz,有条件尽量在配置较好的服务器上进行(亲测orz
配置代理的一个大坑,保证http_proxy等代理对sudo生效(不论当前用户是否为root,都需要加以下内容)
1 2 Defaults env_keep += "http_proxy https_proxy ftp_proxy"
1 安装依赖
1 2 3 4 5 6 sudo apt updatesudo apt install -y debootstrap qemu qemu-kvmsudo apt install -y git make build-essential openssh-serversudo apt install -y libssl-dev libelf-devsudo apt install -y flex bison libc6-dev libc6-dev-i386 linux-libc-dev libgmp3-dev libmpfr-dev libmpc-devsudo apt install -y bc
1 2 3 4 5 6 7 8 9 cd ~ wget https://go.dev/dl/go1.19.7.linux-amd64.tar.gz tar -zxvf go1.19.7.linux-amd64.tar.gz export GOPATH=~/goexport GOROOT=~/goexport PATH=$GOPATH /bin:$PATH go env
2 安装syzkaller
1 2 3 4 5 6 git clone https://github.com/google/syzkaller.gitcd syzkaller make
3 编译内核
在 https://mirrors.edge.kernel.org/pub/linux/kernel/ 选择想要测试的内核版本(拉最新的吧)
1 2 wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.12.tar.xz tar xvJf linux-6.1.12.tar.xz
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 cd linux-6.1.12 make CC="/usr/bin/gcc" defconfig make CC="/usr/bin/gcc" kvm_guest.config CONFIG_KCOV=y CONFIG_DEBUG_INFO=y CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y CONFIG_KASAN=y CONFIG_KASAN_INLINE=y CONFIG_KCOV_INSTRUMENT_ALL=y CONFIG_KCOV_ENABLE_COMPARISONS=y CONFIG_CONFIGFS_FS=y CONFIG_SECURITYFS=y CONFIG_DEBUG_KMEMLEAK=y CONFIG_STACKTRACE=y CONFIG_UBSAN=y CONFIG_UBSAN_SANITIZE_ALL=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="net.ifnames=0" CONFIG_FAULT_INJECTION=y CONFIG_FAULT_INJECTION_DEBUG_FS=y CONFIG_FAULT_INJECTION_USERCOPY=y CONFIG_FAILSLAB=y CONFIG_FAIL_PAGE_ALLOC=y CONFIG_FAIL_MAKE_REQUEST=y CONFIG_FAIL_IO_TIMEOUT=y CONFIG_FAIL_FUTEX=y 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 CONFIG_LOCKDEP=y CONFIG_PROVE_LOCKING=y CONFIG_DEBUG_ATOMIC_SLEEP=y CONFIG_PROVE_RCU=y CONFIG_DEBUG_VM=y CONFIG_REFCOUNT_FULL=y CONFIG_FORTIFY_SOURCE=y CONFIG_HARDENED_USERCOPY=y CONFIG_LOCKUP_DETECTOR=y CONFIG_SOFTLOCKUP_DETECTOR=y CONFIG_HARDLOCKUP_DETECTOR=y CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y CONFIG_DETECT_HUNG_TASK=y CONFIG_WQ_WATCHDOG=y CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=140 CONFIG_RCU_CPU_STALL_TIMEOUT=100 make CC="/usr/bin/gcc" olddefconfig make CC="/usr/bin/gcc" -j8
以下是(较早以前,不具参考价值) 一次运行日志的开头部分,所提示not enabled的几个config已经包含在上述配置里。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2022/12/30 03:01:42 code coverage : enabled 2022/12/30 03:01:42 comparison tracing : CONFIG_KCOV_ENABLE_COMPARISONS is not enabled 2022/12/30 03:01:42 extra coverage : enabled 2022/12/30 03:01:42 delay kcov mmap : enabled 2022/12/30 03:01:42 setuid sandbox : enabled 2022/12/30 03:01:42 namespace sandbox : /proc/self/ns/user does not exist 2022/12/30 03:01:42 Android sandbox : enabled 2022/12/30 03:01:42 fault injection : CONFIG_FAULT_INJECTION is not enabled 2022/12/30 03:01:42 leak checking : CONFIG_DEBUG_KMEMLEAK is not enabled 2022/12/30 03:01:42 net packet injection : /dev/net/tun does not exist 2022/12/30 03:01:42 net device setup : enabled 2022/12/30 03:01:42 concurrency sanitizer : /sys/kernel/debug/kcsan does not exist 2022/12/30 03:01:42 devlink PCI setup : PCI device 0000:00:10.0 is not available 2022/12/30 03:01:42 NIC VF setup : PCI device 0000:00:11.0 is not available 2022/12/30 03:01:42 USB emulation : /dev/raw-gadget does not exist 2022/12/30 03:01:42 hci packet injection : /dev/vhci does not exist 2022/12/30 03:01:42 wifi device emulation : /sys/class/mac80211_hwsim/ does not exist 2022/12/30 03:01:42 802.15.4 emulation : /sys/bus/platform/devices/mac802154_hwsim does not exist 2022/12/30 03:01:42 corpus : 0 (deleted 0 broken) 2022/12/30 03:01:44 seeds : 165/685
4 创建虚拟机
创建image(注意 ,自2023-04-12 syzkaller的d4d447c commit之后,create-image.sh中的默认release由stretch变更为了bullseye )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 mkdir image && cd imagecp ../syzkaller/tools/create-image.sh ./chmod u+x create-image.sh sed -i 's/http:\/\/deb.debian.org\/debian-ports/https:\/\/mirrors.tuna.tsinghua.edu.cn\/debian\//g' create-image.sh ./create-image.shsudo apt install -y debian-archive-keyringchroot create-image.sh stretch.id_rsa stretch.id_rsa.pub stretch.imgchroot create-image.sh bullseye.id_rsa bullseye.id_rsa.pub bullseye.img
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 qemu-system-x86_64 \ -kernel ../kernels/linux-6.1.12/arch/x86/boot/bzImage \ -append "console=ttyS0 root=/dev/sda debug earlyprintk=serial slub_debug=QUZ" \ -hda ./bullseye.img \ -net user,hostfwd=tcp::16112-:22 -net nic \ -enable-kvm \ -nographic \ -m 2560M \ -smp 2 \ -pidfile vm.pid \ 2>&1 | tee vm.log chmod u+x boot.sh ./boot.sh ssh -i bullseye.id_rsa -p 16112 -o "StrictHostKeyChecking no" root@localhost
5 运行syzkaller
注意:为了避免出现[FAILED] Failed to start Raise network interfaces.的错误,要在下述配置文件加入”cmdline”: “net.ifnames=0”或者在.config中追加CMDLINE相关的两条配置项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 cd syzkallermkdir workdir { "target" : "linux/amd64" , "http" : "127.0.0.1:56741" , "workdir" : "/home/zzy/kernel-fuzz/syzkaller/workdir" , "kernel_obj" : "/home/zzy/kernel-fuzz/kernels/linux-6.1.12" , "image" : "/home/zzy/kernel-fuzz/image/bullseye.img" , "sshkey" : "/home/zzy/kernel-fuzz/image/bullseye.id_rsa" , "syzkaller" : "/home/zzy/kernel-fuzz/syzkaller" , "procs" : 8, "type" : "qemu" , "vm" : { "count" : 8, "kernel" : "/home/zzy/kernel-fuzz/kernels/linux-6.1.12/arch/x86/boot/bzImage" , "mem" : 2048 } }
1 2 3 4 5 ./bin/syz-manager -config my.cfg -bench bench.log
在 http://localhost:56741/ 查看fuzz的进度和结果。关于web ui界面中coverage的数据P1%(P2%) of N1(N2)的含义,我通过分析源码pkg/cover/html.go理解了它们的含义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 ... {{define "dir" }} {{range $dir := .Dirs}} <li> <span id="path/{{$dir.Path}}" class="caret hover" > {{$dir.Name}} <span class="cover hover" > {{if $dir.Covered}}{{$dir.Percent}}%({{$dir.PercentInCoveredFunc}}%){{else }}---{{end}} <span class="cover-right" >of {{$dir.Total}}({{$dir.TotalInCoveredFunc}})</span> </span> </span> <ul class="nested" > {{template "dir" $dir}} </ul> </li> {{end}} {{range $file := .Files}} <li><span class="hover" > {{if $file.Covered}} <a href="#{{$file.Path}}" id="path/{{$file.Path}}" onclick="onFileClick({{$file.Index}})" > {{$file.Name}} </a> <span class="cover hover" > <a href="#{{$file.Path}}" id="path/{{$file.Path}}" onclick="{{if .HasFunctions}}onPercentClick{{else}}onFileClick{{end}}({{$file.Index}})" > {{$file.Percent}}%({{$file.PercentInCoveredFunc}}%) </a> <span class="cover-right" >of {{$file.Total}}({{$file.TotalInCoveredFunc}})</span> </span> {{else }} {{$file.Name}}<span class="cover hover" >---<span class="cover-right" > of {{$file.Total}}</span></span> {{end}} </span></li> {{end}} {{end}} ...
由此可知,P1%的含义是file.Percent大概是PC覆盖占比 ,对应N1为file.TotalPC覆盖总数 。P2%的含义是file.PercentInCoveredFunc函数覆盖占比 ,对应N2为file.TotalInCoveredFunc函数覆盖总数
上面这段划掉,我还没搞清楚…
6 调试内核 参见内核Fuzz技巧与备忘: qemu+gdb调试内核
7 参考 [1] Setup: Ubuntu host, QEMU vm, x86-64 kernel
[2] 零基础syzkaller挖掘Linux内核漏洞
[3] Syzkaller安装 Fuzz Qemu amd64 Kernel
[4] syzkaller官方troubleshooting
[5] syzkaller官方kernel_configs