Patrick Williams | 2390b1b | 2022-11-03 13:47:49 -0500 | [diff] [blame] | 1 | # |
| 2 | # SPDX-License-Identifier: MIT |
| 3 | # |
| 4 | |
| 5 | from oeqa.selftest.case import OESelftestTestCase |
| 6 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars |
| 7 | from oeqa.utils.network import get_free_port |
| 8 | |
| 9 | class TestSyzkaller(OESelftestTestCase): |
| 10 | def setUpSyzkallerConfig(self, os_arch, qemu_postfix): |
| 11 | syz_target_sysroot = get_bb_var('PKGD', 'syzkaller') |
| 12 | syz_target = os.path.join(syz_target_sysroot, 'usr') |
| 13 | |
| 14 | qemu_native_bin = os.path.join(self.syz_native_sysroot, 'usr/bin/qemu-system-' + qemu_postfix) |
| 15 | kernel_cmdline = "ip=dhcp rootfs=/dev/sda dummy_hcd.num=%s" % (self.dummy_hcd_num) |
| 16 | kernel_objdir = self.deploy_dir_image |
| 17 | port = get_free_port() |
| 18 | |
| 19 | if not os.path.exists(self.syz_workdir): |
| 20 | os.mkdir(self.syz_workdir) |
| 21 | |
| 22 | with open(self.syz_cfg, 'w') as f: |
| 23 | f.write( |
| 24 | """ |
| 25 | { |
| 26 | "target": "%s", |
| 27 | "http": "127.0.0.1:%s", |
| 28 | "workdir": "%s", |
| 29 | "kernel_obj": "%s", |
| 30 | "kernel_src": "%s", |
| 31 | "image": "%s", |
| 32 | "syzkaller": "%s", |
| 33 | "type": "qemu", |
| 34 | "reproduce" : false, |
| 35 | "sandbox": "none", |
| 36 | "vm": { |
| 37 | "count": %s, |
| 38 | "kernel": "%s", |
| 39 | "cmdline": "%s", |
| 40 | "cpu": %s, |
| 41 | "mem": %s, |
| 42 | "qemu": "%s", |
| 43 | "qemu_args": "-device virtio-scsi-pci,id=scsi -device scsi-hd,drive=rootfs -enable-kvm -cpu host,migratable=off", |
| 44 | "image_device": "drive index=0,id=rootfs,if=none,media=disk,file=" |
| 45 | } |
| 46 | } |
| 47 | """ |
| 48 | % (os_arch, port, self.syz_workdir, kernel_objdir, self.kernel_src, |
| 49 | self.rootfs, syz_target, self.syz_qemu_vms, self.kernel, kernel_cmdline, |
| 50 | self.syz_qemu_cpus, self.syz_qemu_mem, qemu_native_bin)) |
| 51 | |
| 52 | def test_syzkallerFuzzingQemux86_64(self): |
| 53 | self.image = 'core-image-minimal' |
| 54 | self.machine = 'qemux86-64' |
| 55 | self.fstype = "ext4" |
| 56 | |
| 57 | self.write_config( |
| 58 | """ |
| 59 | MACHINE = "%s" |
| 60 | IMAGE_FSTYPES = "%s" |
| 61 | KERNEL_IMAGETYPES += "vmlinux" |
| 62 | EXTRA_IMAGE_FEATURES += " ssh-server-openssh" |
| 63 | IMAGE_ROOTFS_EXTRA_SPACE = "512000" |
| 64 | KERNEL_EXTRA_FEATURES += " \ |
| 65 | cfg/debug/syzkaller/debug-syzkaller.scc \ |
| 66 | " |
| 67 | IMAGE_INSTALL:append = " syzkaller" |
| 68 | """ |
| 69 | % (self.machine, self.fstype)) |
| 70 | |
| 71 | build_vars = ['TOPDIR', 'DEPLOY_DIR_IMAGE', 'STAGING_KERNEL_DIR'] |
| 72 | syz_fuzz_vars = ['SYZ_WORKDIR', 'SYZ_FUZZTIME', 'SYZ_QEMU_MEM', 'SYZ_QEMU_CPUS', 'SYZ_QEMU_VM_COUNT'] |
| 73 | syz_aux_vars = ['SYZ_DUMMY_HCD_NUM'] |
| 74 | |
| 75 | needed_vars = build_vars + syz_fuzz_vars + syz_aux_vars |
| 76 | bb_vars = get_bb_vars(needed_vars) |
| 77 | |
| 78 | for var in syz_fuzz_vars: |
| 79 | if not bb_vars[var]: |
| 80 | self.skipTest( |
| 81 | """ |
| 82 | %s variable not set. |
| 83 | Please configure %s fuzzing parameters to run this test. |
| 84 | |
| 85 | Example local.conf config: |
| 86 | SYZ_WORKDIR="<path>" # syzkaller workdir location (must be persistent across os-selftest runs) |
| 87 | SYZ_FUZZTIME="30" # fuzzing time in minutes |
| 88 | SYZ_QEMU_VM_COUNT="1" # number of qemu VMs to be used for fuzzing |
| 89 | SYZ_QEMU_MEM="2048"' # memory used by each qemu VM |
| 90 | SYZ_QEMU_CPUS="2"' # number of cpus used by each qemu VM |
| 91 | """ |
| 92 | % (var, ', '.join(syz_fuzz_vars))) |
| 93 | |
| 94 | self.topdir = bb_vars['TOPDIR'] |
| 95 | self.deploy_dir_image = bb_vars['DEPLOY_DIR_IMAGE'] |
| 96 | self.kernel_src = bb_vars['STAGING_KERNEL_DIR'] |
| 97 | |
| 98 | """ |
| 99 | SYZ_WORKDIR must be set to an absolute path where syzkaller will store |
| 100 | the corpus database, config, runtime and crash data generated during |
| 101 | fuzzing. It must be persistent between oe-selftest runs, so the fuzzer |
| 102 | does not start over again on each run. |
| 103 | """ |
| 104 | self.syz_workdir = bb_vars['SYZ_WORKDIR'] |
| 105 | self.syz_fuzztime = int(bb_vars['SYZ_FUZZTIME']) * 60 |
| 106 | self.syz_qemu_mem = int(bb_vars['SYZ_QEMU_MEM']) |
| 107 | self.syz_qemu_cpus = int(bb_vars['SYZ_QEMU_CPUS']) |
| 108 | self.syz_qemu_vms = int(bb_vars['SYZ_QEMU_VM_COUNT']) |
| 109 | self.dummy_hcd_num = int(bb_vars['SYZ_DUMMY_HCD_NUM'] or 8) |
| 110 | |
| 111 | self.syz_cfg = os.path.join(self.syz_workdir, 'syzkaller.cfg') |
| 112 | self.kernel = os.path.join(self.deploy_dir_image, 'bzImage') |
| 113 | self.rootfs = os.path.join(self.deploy_dir_image, '%s-%s.%s' % (self.image, self.machine, self.fstype)) |
| 114 | |
| 115 | self.syz_native_sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'syzkaller-native') |
| 116 | |
| 117 | self.setUpSyzkallerConfig("linux/amd64", "x86_64") |
| 118 | |
| 119 | bitbake(self.image) |
| 120 | bitbake('syzkaller') |
| 121 | bitbake('syzkaller-native -c addto_recipe_sysroot') |
| 122 | |
| 123 | cmd = "syz-manager -config %s" % self.syz_cfg |
| 124 | runCmd(cmd, native_sysroot = self.syz_native_sysroot, timeout=self.syz_fuzztime, output_log=self.logger, ignore_status=True, shell=True) |