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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
|
# FreeBSD
This page contains instructions to set up syzkaller to run on a FreeBSD or Linux host and fuzz an amd64 FreeBSD kernel running in a virtual machine.
Currently, syzkaller can fuzz FreeBSD running under bhyve, QEMU or GCE (Google Compute Engine). Regardless of the mode of operation, some common steps must be followed.
## Setting up a host
`syz-manager` is the component of syzkaller that manages target VMs. It runs on a host system and automatically creates, runs and destroys VMs which share a user-specified image file.
### Setting up a FreeBSD host
To build syzkaller out of the box, a recent version of FreeBSD 13.0-CURRENT must be used for the host. Older versions of FreeBSD can be used but will require manual tweaking.
The required dependencies can be installed by running:
```console
# pkg install bash gcc git gmake go golangci-lint llvm
```
When using bhyve as the VM backend, a DHCP server must also be installed:
```console
# pkg install dnsmasq
```
To checkout the syzkaller sources, run:
```console
$ git clone https://github.com/google/syzkaller
```
and the binaries can be built by running:
```console
$ cd syzkaller
$ gmake
```
Once this completes, a `syz-manager` executable should be available under `bin/`.
### Setting up a Linux host
To build Go binaries do:
```
make manager fuzzer execprog TARGETOS=freebsd
```
To build C `syz-executor` binary, copy `executor/*` files to a FreeBSD machine and build there with:
```
c++ executor/executor.cc -o syz-executor -O1 -lpthread -DGOOS_freebsd=1 -DGOARCH_amd64=1 -DGIT_REVISION=\"CURRENT_GIT_REVISION\"
```
Then, copy out the binary back to host into `bin/freebsd_amd64` dir.
## Setting up the FreeBSD VM
It is easiest to start with a [snapshot image](https://ftp.freebsd.org/pub/FreeBSD/snapshots/VM-IMAGES/14.0-CURRENT/amd64/Latest/) of FreeBSD. Fetch a QCOW2 disk image for QEMU or a raw image for GCE or bhyve.
Fetch a copy of the FreeBSD kernel sources and place them in `/usr/src`. You will likely need to expand the disk of the VM. Before booting the VM, run:
```console
# truncate -s 15G $IMAGEFILE
```
To enable KCOV on FreeBSD, a custom kernel must be compiled. It is easiest to do this on the host.<br>
Before booting the VM, compile a custom kernel on the host and install it on the VM. On the host:
```console
# mdconfig -a -f $IMAGEFILE
# mount /dev/md0p4 /mnt
```
This will create a memory device for the VM file and allow host to install the custom kernel source on the VM. <br>
To get a copy of the current development sources:
```console
# pkg install git
# git clone --depth=1 --branch=main https://github.com/freebsd/freebsd-src /usr/src
```
To create a custom kernel configuration file for syzkaller and build a new kernel, run:
```console
# cd /usr/src/sys/amd64/conf
# cat <<__EOF__ > SYZKALLER
include "./GENERIC"
ident SYZKALLER
options COVERAGE
options KCOV
__EOF__
# cd /usr/src
# make -j $(sysctl -n hw.ncpu) KERNCONF=SYZKALLER buildkernel
# make KERNCONF=SYZKALLER installkernel DESTDIR=/mnt
```
Before booting the VM, make sure to run:
```console
# umount /mnt
```
The md device will linger and you can use it again later if you want. Otherwise destroy it:
```console
# mdconfig -d -u 0
```
Use QEMU to start a VM using the downloaded image:
```console
$ qemu-system-x86_64 -hda $IMAGEFILE -nographic -net user,host=10.0.2.10,hostfwd=tcp::10022-:22 -net nic,model=e1000
```
When the boot loader menu is printed, escape to the loader prompt and enter the commands `set console="comconsole"` and `boot`. Once you reach a login prompt, log in as root and add a couple of configuration parameters to `/boot/loader.conf`:
```console
# cat <<__EOF__ >>/boot/loader.conf
autoboot_delay="-1"
console="comconsole"
__EOF__
```
After VM is booted, /etc/rc.d/growfs should haven grown its file system automatically. Otherwise run:
```console
# /etc/rc.d/growfs onestart
```
Verify that `uname -i` prints `SYZKALLER` to confirm that your newly built kernel is running.
Then, to permit remote access to the VM, you must configure DHCP and enable `sshd`:
```console
# sysrc sshd_enable=YES
# sysrc ifconfig_DEFAULT=DHCP
```
If you plan to run the syscall executor as root, ensure that root SSH logins are permitted by adding `PermitRootLogin without-password` to `/etc/ssh/sshd_config`. Otherwise, create a new user with `adduser`. Install an ssh key for the user and verify that you can SSH into the VM from the host. Note that bhyve requires the use of the root user for the time being.
### Running Under bhyve
Some additional steps are required on the host in order to use bhyve. First, ensure that the host system is at r346550 or later. Second, since bhyve currently does not support disk image snapshots, ZFS must be used to provide equivalent functionality. Create a ZFS data set and copy the VM image there. The data set can also be used to store the syzkaller workdir. For example, with a zpool named `data` mounted at `/data`, write:
```console
# zfs create data/syzkaller
# cp FreeBSD-13.0-CURRENT-amd64.raw /data/syzkaller
```
Third, configure networking and DHCP for the VM instances:
```console
# ifconfig bridge create
bridge0
# ifconfig bridge0 inet 169.254.0.1
# echo 'dhcp-range=169.254.0.2,169.254.0.254,255.255.255.0' > /usr/local/etc/dnsmasq.conf
# echo 'interface=bridge0' >> /usr/local/etc/dnsmasq.conf
# sysrc dnsmasq_enable=YES
# service dnsmasq start
# echo 'net.link.tap.up_on_open=1' >> /etc/sysctl.conf
# sysctl net.link.tap.up_on_open=1
```
To enable automatic configuration of bridged network every time the system boots, add the following to /etc/rc.conf:
```console
# cloned_interfaces="bridge0 tap0"
# ifconfig_bridge0="inet 169.254.0.1 addm tap0 up"
# ifconfig_tap0="up"
```
Finally, ensure that the bhyve kernel module is loaded:
```console
# kldload vmm
```
### Putting It All Together
If all of the above worked, create a `freebsd.cfg` configuration file with the following contents (alter paths as necessary):
```
{
"name": "freebsd",
"target": "freebsd/amd64",
"http": ":10000",
"workdir": "/workdir",
"syzkaller": "/gopath/src/github.com/google/syzkaller",
"sshkey": "/freebsd_id_rsa",
"sandbox": "none",
"procs": 8,
}
```
If running the fuzzer under QEMU, add:
```
"image": "/FreeBSD-13.0-CURRENT-amd64.qcow2",
"type": "qemu",
"vm": {
"count": 10,
"cpu": 4,
"mem": 2048
}
```
For GCE, add the following instead (alter the storage bucket path as necessary):
```
"image": "/FreeBSD-13.0-CURRENT-amd64.raw",
"type": "gce",
"vm": {
"count": 10,
"instance_type": "n1-standard-4",
"gcs_path": "syzkaller"
}
```
For bhyve, we need to specify the VM image snapshot name and networking info (alter the dataset name and paths as necessary):
```
"image": "/data/syzkaller/FreeBSD-13.0-CURRENT-amd64.raw",
"type": "bhyve",
"vm": {
"count": 10,
"bridge": "bridge0",
"hostip": "169.254.0.1",
"dataset": "data/syzkaller"
}
```
Then, start `syz-manager` with:
```console
$ bin/syz-manager -config freebsd.cfg
```
It should start printing output along the lines of:
```
booting test machines...
wait for the connection from test machine...
machine check: 253 calls enabled, kcov=true, kleakcheck=false, faultinjection=false, comps=false
executed 3622, cover 1219, crashes 0, repro 0
executed 7921, cover 1239, crashes 0, repro 0
executed 32807, cover 1244, crashes 0, repro 0
executed 35803, cover 1248, crashes 0, repro 0
```
If something does not work, try adding the `-debug` flag to `syz-manager`.
## Missing things
- System call descriptions. The initial list of FreeBSD system calls was a copy-and-paste of Linux's, and while they have been cleaned up over time they should be audited more carefully. We are also still missing many system call descriptions.
- We should support fuzzing the Linux compatibility subsystem.
- We should provide instructions for fuzzing a FreeBSD system on ZFS
- `pkg/host` needs to be taught how to detect supported syscalls/devices.
- KASAN and KCSAN for FreeBSD would be useful.
- On Linux we have emission of exernal networking/USB traffic into kernel using tun/gadgetfs. Implementing these for FreeBSD could uncover a number of high-profile bugs.
|