# # SPDX-License-Identifier: MIT # from oeqa.selftest.case import OESelftestTestCase from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars from oeqa.utils.network import get_free_port class TestSyzkaller(OESelftestTestCase): def setUpSyzkallerConfig(self, os_arch, qemu_postfix): syz_target_sysroot = get_bb_var('PKGD', 'syzkaller') syz_target = os.path.join(syz_target_sysroot, 'usr') qemu_native_bin = os.path.join(self.syz_native_sysroot, 'usr/bin/qemu-system-' + qemu_postfix) kernel_cmdline = "ip=dhcp rootfs=/dev/sda dummy_hcd.num=%s" % (self.dummy_hcd_num) kernel_objdir = self.deploy_dir_image port = get_free_port() if not os.path.exists(self.syz_workdir): os.mkdir(self.syz_workdir) with open(self.syz_cfg, 'w') as f: f.write( """ { "target": "%s", "http": "127.0.0.1:%s", "workdir": "%s", "kernel_obj": "%s", "kernel_src": "%s", "image": "%s", "syzkaller": "%s", "type": "qemu", "reproduce" : false, "sandbox": "none", "vm": { "count": %s, "kernel": "%s", "cmdline": "%s", "cpu": %s, "mem": %s, "qemu": "%s", "qemu_args": "-device virtio-scsi-pci,id=scsi -device scsi-hd,drive=rootfs -enable-kvm -cpu host,migratable=off", "image_device": "drive index=0,id=rootfs,if=none,media=disk,file=" } } """ % (os_arch, port, self.syz_workdir, kernel_objdir, self.kernel_src, self.rootfs, syz_target, self.syz_qemu_vms, self.kernel, kernel_cmdline, self.syz_qemu_cpus, self.syz_qemu_mem, qemu_native_bin)) def test_syzkallerFuzzingQemux86_64(self): self.image = 'core-image-minimal' self.machine = 'qemux86-64' self.fstype = "ext4" self.write_config( """ MACHINE = "%s" IMAGE_FSTYPES = "%s" KERNEL_IMAGETYPES += "vmlinux" EXTRA_IMAGE_FEATURES += " ssh-server-openssh" IMAGE_ROOTFS_EXTRA_SPACE = "512000" KERNEL_EXTRA_FEATURES += " \ cfg/debug/syzkaller/debug-syzkaller.scc \ " IMAGE_INSTALL:append = " syzkaller" """ % (self.machine, self.fstype)) build_vars = ['TOPDIR', 'DEPLOY_DIR_IMAGE', 'STAGING_KERNEL_DIR'] syz_fuzz_vars = ['SYZ_WORKDIR', 'SYZ_FUZZTIME', 'SYZ_QEMU_MEM', 'SYZ_QEMU_CPUS', 'SYZ_QEMU_VM_COUNT'] syz_aux_vars = ['SYZ_DUMMY_HCD_NUM'] needed_vars = build_vars + syz_fuzz_vars + syz_aux_vars bb_vars = get_bb_vars(needed_vars) for var in syz_fuzz_vars: if not bb_vars[var]: self.skipTest( """ %s variable not set. Please configure %s fuzzing parameters to run this test. Example local.conf config: SYZ_WORKDIR="" # syzkaller workdir location (must be persistent across os-selftest runs) SYZ_FUZZTIME="30" # fuzzing time in minutes SYZ_QEMU_VM_COUNT="1" # number of qemu VMs to be used for fuzzing SYZ_QEMU_MEM="2048"' # memory used by each qemu VM SYZ_QEMU_CPUS="2"' # number of cpus used by each qemu VM """ % (var, ', '.join(syz_fuzz_vars))) self.topdir = bb_vars['TOPDIR'] self.deploy_dir_image = bb_vars['DEPLOY_DIR_IMAGE'] self.kernel_src = bb_vars['STAGING_KERNEL_DIR'] """ SYZ_WORKDIR must be set to an absolute path where syzkaller will store the corpus database, config, runtime and crash data generated during fuzzing. It must be persistent between oe-selftest runs, so the fuzzer does not start over again on each run. """ self.syz_workdir = bb_vars['SYZ_WORKDIR'] self.syz_fuzztime = int(bb_vars['SYZ_FUZZTIME']) * 60 self.syz_qemu_mem = int(bb_vars['SYZ_QEMU_MEM']) self.syz_qemu_cpus = int(bb_vars['SYZ_QEMU_CPUS']) self.syz_qemu_vms = int(bb_vars['SYZ_QEMU_VM_COUNT']) self.dummy_hcd_num = int(bb_vars['SYZ_DUMMY_HCD_NUM'] or 8) self.syz_cfg = os.path.join(self.syz_workdir, 'syzkaller.cfg') self.kernel = os.path.join(self.deploy_dir_image, 'bzImage') self.rootfs = os.path.join(self.deploy_dir_image, '%s-%s.%s' % (self.image, self.machine, self.fstype)) self.syz_native_sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'syzkaller-native') self.setUpSyzkallerConfig("linux/amd64", "x86_64") bitbake(self.image) bitbake('syzkaller') bitbake('syzkaller-native -c addto_recipe_sysroot') cmd = "syz-manager -config %s" % self.syz_cfg runCmd(cmd, native_sysroot = self.syz_native_sysroot, timeout=self.syz_fuzztime, output_log=self.logger, ignore_status=True, shell=True)