diff options
3 files changed, 264 insertions, 0 deletions
diff --git a/meta-oe/lib/oeqa/selftest/cases/syzkaller.py b/meta-oe/lib/oeqa/selftest/cases/syzkaller.py new file mode 100644 index 0000000000..64fc864bf8 --- /dev/null +++ b/meta-oe/lib/oeqa/selftest/cases/syzkaller.py | |||
| @@ -0,0 +1,124 @@ | |||
| 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) | ||
diff --git a/meta-oe/recipes-test/syzkaller/syzkaller/0001-sys-targets-targets.go-allow-users-to-override-hardc.patch b/meta-oe/recipes-test/syzkaller/syzkaller/0001-sys-targets-targets.go-allow-users-to-override-hardc.patch new file mode 100644 index 0000000000..d647b8d4a0 --- /dev/null +++ b/meta-oe/recipes-test/syzkaller/syzkaller/0001-sys-targets-targets.go-allow-users-to-override-hardc.patch | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | From aca1030d29f627314d13884ebc7b2c313d718df7 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Ovidiu Panait <ovidiu.panait@windriver.com> | ||
| 3 | Date: Wed, 13 Apr 2022 17:17:54 +0300 | ||
| 4 | Subject: [PATCH] sys/targets/targets.go: allow users to override hardcoded | ||
| 5 | cross-compilers | ||
| 6 | |||
| 7 | Currently, cross compiler names are hardcoded for each os/arch combo. However, | ||
| 8 | toolchain tuples differ, especially when using vendor provided toolchains. | ||
| 9 | Allow users to specify the cross compiler for an os/arch combo using | ||
| 10 | SYZ_CC_<os>_<arch> environment variables. | ||
| 11 | |||
| 12 | Also, remove hardcoded "-march=armv6" flag to fix compilation on arm. | ||
| 13 | |||
| 14 | Upstream-Status: Inappropriate [embedded specific] | ||
| 15 | |||
| 16 | Signed-off-by: Ovidiu Panait <ovidiu.panait@windriver.com> | ||
| 17 | --- | ||
| 18 | sys/targets/targets.go | 19 +++++++++++-------- | ||
| 19 | 1 file changed, 11 insertions(+), 8 deletions(-) | ||
| 20 | |||
| 21 | diff --git a/sys/targets/targets.go b/sys/targets/targets.go | ||
| 22 | index f3be708f3..19a8bb681 100644 | ||
| 23 | --- a/sys/targets/targets.go | ||
| 24 | +++ b/sys/targets/targets.go | ||
| 25 | @@ -258,7 +258,6 @@ var List = map[string]map[string]*Target{ | ||
| 26 | PtrSize: 4, | ||
| 27 | PageSize: 4 << 10, | ||
| 28 | LittleEndian: true, | ||
| 29 | - CFlags: []string{"-D__LINUX_ARM_ARCH__=6", "-march=armv6"}, | ||
| 30 | Triple: "arm-linux-gnueabi", | ||
| 31 | KernelArch: "arm", | ||
| 32 | KernelHeaderArch: "arm", | ||
| 33 | @@ -670,12 +669,16 @@ func initTarget(target *Target, OS, arch string) { | ||
| 34 | for i := range target.CFlags { | ||
| 35 | target.replaceSourceDir(&target.CFlags[i], sourceDir) | ||
| 36 | } | ||
| 37 | - if OS == Linux && arch == runtime.GOARCH { | ||
| 38 | - // Don't use cross-compiler for native compilation, there are cases when this does not work: | ||
| 39 | - // https://github.com/google/syzkaller/pull/619 | ||
| 40 | - // https://github.com/google/syzkaller/issues/387 | ||
| 41 | - // https://github.com/google/syzkaller/commit/06db3cec94c54e1cf720cdd5db72761514569d56 | ||
| 42 | - target.Triple = "" | ||
| 43 | + if OS == Linux { | ||
| 44 | + if cc := os.Getenv("SYZ_CC_" + OS + "_" + arch); cc != "" { | ||
| 45 | + target.CCompiler = cc | ||
| 46 | + } else if arch == runtime.GOARCH { | ||
| 47 | + // Don't use cross-compiler for native compilation, there are cases when this does not work: | ||
| 48 | + // https://github.com/google/syzkaller/pull/619 | ||
| 49 | + // https://github.com/google/syzkaller/issues/387 | ||
| 50 | + // https://github.com/google/syzkaller/commit/06db3cec94c54e1cf720cdd5db72761514569d56 | ||
| 51 | + target.Triple = "" | ||
| 52 | + } | ||
| 53 | } | ||
| 54 | if target.CCompiler == "" { | ||
| 55 | target.setCompiler(useClang) | ||
| 56 | @@ -803,7 +806,7 @@ func (target *Target) lazyInit() { | ||
| 57 | // On CI we want to fail loudly if cross-compilation breaks. | ||
| 58 | // Also fail if SOURCEDIR_GOOS is set b/c in that case user probably assumes it will work. | ||
| 59 | if (target.OS != runtime.GOOS || !runningOnCI) && os.Getenv("SOURCEDIR_"+strings.ToUpper(target.OS)) == "" { | ||
| 60 | - if _, err := exec.LookPath(target.CCompiler); err != nil { | ||
| 61 | + if _, err := exec.LookPath(strings.Fields(target.CCompiler)[0]); err != nil { | ||
| 62 | target.BrokenCompiler = fmt.Sprintf("%v is missing (%v)", target.CCompiler, err) | ||
| 63 | return | ||
| 64 | } | ||
| 65 | -- | ||
| 66 | 2.25.1 | ||
| 67 | |||
diff --git a/meta-oe/recipes-test/syzkaller/syzkaller_git.bb b/meta-oe/recipes-test/syzkaller/syzkaller_git.bb new file mode 100644 index 0000000000..f7c751f806 --- /dev/null +++ b/meta-oe/recipes-test/syzkaller/syzkaller_git.bb | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | DESCRIPTION = "syzkaller is an unsupervised coverage-guided kernel fuzzer" | ||
| 2 | LICENSE = "Apache-2.0" | ||
| 3 | LIC_FILES_CHKSUM = "file://src/${GO_IMPORT}/LICENSE;md5=5335066555b14d832335aa4660d6c376" | ||
| 4 | |||
| 5 | inherit go-mod | ||
| 6 | |||
| 7 | GO_IMPORT = "github.com/google/syzkaller" | ||
| 8 | |||
| 9 | SRC_URI = "git://${GO_IMPORT};protocol=https;destsuffix=${BPN}-${PV}/src/${GO_IMPORT};branch=master \ | ||
| 10 | file://0001-sys-targets-targets.go-allow-users-to-override-hardc.patch;patchdir=src/${GO_IMPORT} \ | ||
| 11 | " | ||
| 12 | SRCREV = "67cb024cd1a3c95e311263a5c95e957f9abfd8ca" | ||
| 13 | |||
| 14 | COMPATIBLE_HOST = "(x86_64|i.86|arm|aarch64).*-linux" | ||
| 15 | |||
| 16 | B = "${S}/src/${GO_IMPORT}/bin" | ||
| 17 | |||
| 18 | GO_EXTRA_LDFLAGS += ' -X ${GO_IMPORT}/prog.GitRevision=${SRCREV}' | ||
| 19 | |||
| 20 | export GOHOSTFLAGS="${GO_LINKSHARED} ${GOBUILDFLAGS}" | ||
| 21 | export GOTARGETFLAGS="${GO_LINKSHARED} ${GOBUILDFLAGS}" | ||
| 22 | export TARGETOS = '${GOOS}' | ||
| 23 | export TARGETARCH = '${GOARCH}' | ||
| 24 | export TARGETVMARCH = '${GOARCH}' | ||
| 25 | |||
| 26 | CGO_ENABLED = "0" | ||
| 27 | |||
| 28 | DEPENDS:class-native += "qemu-system-native" | ||
| 29 | |||
| 30 | do_compile:class-native() { | ||
| 31 | export HOSTOS="${GOHOSTOS}" | ||
| 32 | export HOSTARCH="${GOHOSTARCH}" | ||
| 33 | |||
| 34 | oe_runmake HOSTGO="${GO}" host | ||
| 35 | } | ||
| 36 | |||
| 37 | do_compile:class-target() { | ||
| 38 | export HOSTOS="${GOOS}" | ||
| 39 | export HOSTARCH="${GOARCH}" | ||
| 40 | export SYZ_CC_${TARGETOS}_${TARGETARCH}="${CC}" | ||
| 41 | |||
| 42 | # Unset GOOS and GOARCH so that the correct syz-sysgen binary can be | ||
| 43 | # generated. Fixes: | ||
| 44 | # go install: cannot install cross-compiled binaries when GOBIN is set | ||
| 45 | unset GOOS | ||
| 46 | unset GOARCH | ||
| 47 | |||
| 48 | oe_runmake GO="${GO}" CC="${CXX}" CFLAGS="${CXXFLAGS} ${LDFLAGS}" REV=${SRCREV} target | ||
| 49 | } | ||
| 50 | |||
| 51 | do_install:class-native() { | ||
| 52 | SYZ_BINS_NATIVE="syz-manager syz-runtest syz-repro syz-mutate syz-prog2c \ | ||
| 53 | syz-db syz-upgrade" | ||
| 54 | |||
| 55 | install -d ${D}${bindir} | ||
| 56 | |||
| 57 | for i in ${SYZ_BINS_NATIVE}; do | ||
| 58 | install -m 0755 ${B}/${i} ${D}${bindir} | ||
| 59 | done | ||
| 60 | } | ||
| 61 | |||
| 62 | do_install:class-target() { | ||
| 63 | SYZ_TARGET_DIR="${TARGETOS}_${TARGETARCH}" | ||
| 64 | SYZ_BINS_TARGET="syz-fuzzer syz-execprog syz-stress syz-executor" | ||
| 65 | |||
| 66 | install -d ${D}${bindir}/${SYZ_TARGET_DIR} | ||
| 67 | |||
| 68 | for i in ${SYZ_BINS_TARGET}; do | ||
| 69 | install -m 0755 ${B}/${SYZ_TARGET_DIR}/${i} ${D}${bindir}/${SYZ_TARGET_DIR} | ||
| 70 | done | ||
| 71 | } | ||
| 72 | |||
| 73 | BBCLASSEXTEND += "native" | ||
