diff --git a/lava-job-template/qemu/qemu-syzkaller.yaml b/lava-job-template/qemu/qemu-syzkaller.yaml new file mode 100644 index 0000000..66c14be --- /dev/null +++ b/lava-job-template/qemu/qemu-syzkaller.yaml @@ -0,0 +1,103 @@ +# Your first LAVA JOB definition for an riscv_64 QEMU +device_type: qemu +job_name: ${job_name} +timeouts: + job: + minutes: 10150 + action: + minutes: 10140 + connection: + minutes: 10 +priority: medium +visibility: public +# context allows specific values to be overridden or included +context: + # tell the qemu template which architecture is being tested + # the template uses that to ensure that qemu-system-riscv64 is executed. + arch: riscv64 + machine: virt + guestfs_interface: virtio + extra_options: + - -machine virt + - -nographic + - -smp 8 + - -m 8G + - -device virtio-blk-device,drive=hd0 + - -device virtio-blk-device,drive=hd1 + - -append "root=/dev/vda rw console=ttyS0 selinux=0" + - -device virtio-net-device,netdev=usernet + - -netdev user,id=usernet,hostfwd=tcp::10001-:22 +metadata: + # please change these fields when modifying this job for your own tests. + format: Lava-Test Test Definition 1.0 + name: qemu-riscv64-test + description: "test for riscv64 qemu" + version: "1.0" +# ACTION_BLOCK +actions: +# DEPLOY_BLOCK +- deploy: + timeout: + minutes: 20 + to: tmpfs + images: + kernel: + image_arg: -kernel {kernel} + url: ${kernel_image_url} + rootfs: + image_arg: -drive file={rootfs},format=raw,id=hd0,if=none + url: ${rootfs_image_url} + compression: zstd + data_disk: + image_arg: -drive file={data_disk},format=raw,id=hd1,if=none + url: ${data_disk_url} + compression: zstd + +# BOOT_BLOCK +- boot: + timeout: + minutes: 20 + method: qemu + media: tmpfs + prompts: ["root@riscv64"] + auto_login: + login_prompt: "riscv64 login:" + username: root + password_prompt: "Password:" + password: openEuler12#$ + +# TEST_BLOCK: 准备kexec切换所需的内核及软件包 +- test: + timeout: + minutes: 10100 + definitions: + - from: git + name: ${testitem_name} + path: ${testcase_path} + repository: ${testcase_repo} + +# SECOND_BOOT_BLOCK: 热启动切换新内核 +- boot: + timeout: + minutes: 60 + method: kexec + boot_message: "Bye..." + kernel: /build/linux-build/arch/riscv/boot/Image # 虚拟机内编译的内核地址 + prompts: ["root@riscv64"] + auto_login: + login_prompt: "riscv64 login:" + username: root + password_prompt: "Password:" + password: openEuler12#$ + +# HEARTBEAT_BLOCK: 在新内核中运行心跳监控 +- test: + timeout: + minutes: 10010 + definitions: + - from: git + name: ${testitem_name} + path: ${testcase_path} + repository: ${testcase_repo} + parameters: + HOURS: "24" # fuzzing时长 diff --git a/lava-testcases/security-test/syzkaller/README.md b/lava-testcases/security-test/syzkaller/README.md new file mode 100644 index 0000000..e12d17e --- /dev/null +++ b/lava-testcases/security-test/syzkaller/README.md @@ -0,0 +1,4 @@ +使用 syzkaller 对 Linux 内核进行模糊测试时,需启用 CONFIG_KCOV=y(覆盖率收集)和 CONFIG_KASAN=y(内存错误检测)等必要配置。 + +当前测试流程为:先在虚拟机中编译目标内核,再直接加载并切换至新内核进行测试。 +然而,目前 OERV 的 kernel+rootfs 通过kexec加载并切换至新内核仅支持 QEMU 环境,在其他真实硬件上执行内核切换均会失败,详见https://github.com/RVCK-Project/lavaci/pull/42。 \ No newline at end of file diff --git a/lava-testcases/security-test/syzkaller/make_kernel.sh b/lava-testcases/security-test/syzkaller/make_kernel.sh new file mode 100644 index 0000000..5b85f95 --- /dev/null +++ b/lava-testcases/security-test/syzkaller/make_kernel.sh @@ -0,0 +1,122 @@ +# 加载数据盘 +load_disk(){ + DISK=/dev/vdb + PART=${DISK}1 + MNT=/build + + # 1. 分区并格式化 + parted -s $DISK mklabel gpt + parted -s $DISK mkpart primary ext4 0% 100% + mkfs.ext4 -F $PART + + # 2. 挂载并写入fstab(重启生效) + mkdir -p $MNT + UUID=$(blkid -s UUID -o value $PART) + echo "UUID=$UUID $MNT ext4 defaults,noatime 0 2" >> /etc/fstab + mount -a + + # 3. 验证 + df -h $MNT +} + +KERNEL_SRC=/usr/src/linux-$(uname -r) +KERNEL_DEST=/build/linux-build + + +#编译内核 +make_kernel(){ + mkdir -p $KERNEL_DEST + dnf install -y kernel-source + dnf install -y gcc make flex bison openssl-devel elfutils-libelf-devel \ + perl python3 bc dwarves cpio gzip tar xz util-linux + cd $KERNEL_SRC + make ARCH=riscv -C $KERNEL_SRC mrproper + # 生成默认配置 + zcat /proc/config.gz > $KERNEL_DEST/.config + FILE="$KERNEL_SRC/drivers/acpi/pci_mcfg.c" + + sed -i \ + -e 's/^#ifdef CONFIG_RISCV$/#ifdef CONFIG_PCIE_DW_SOPHGO/' \ + -e 's|^#endif /\* RISCV \*/$|#endif /* CONFIG_PCIE_DW_SOPHGO */|' \ + "$FILE" + + # 进行内存fuzzing测试需要开启的配置项 + # === 基础与覆盖率(Syzkaller 核心依赖)=== + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --disable KVM + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable KCOV + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable DEBUG_INFO + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable DEBUG_INFO_DWARF4 + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable KALLSYMS + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable KALLSYMS_ALL + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable DEBUG_FS # KCOV/故障注入运行时接口 + + # === 命名空间隔离(Syzkaller 沙箱必需)=== + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable NAMESPACES + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable USER_NS + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable NET_NS + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable PID_NS + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable UTS_NS + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable IPC_NS + + # === 沙箱文件系统依赖(必须全部内置=y)=== + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable BINFMT_MISC # 解决 mount(binfmt_misc) failed + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable TMPFS # 沙箱临时文件系统 + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable TMPFS_XATTR # 沙箱文件属性隔离必需 + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable DEVTMPFS # /dev 设备节点自动创建 + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable PROC_FS # /proc 进程信息 + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable SYSFS # /sys 内核对象 + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable CGROUPS # 资源限制隔离 + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable MEMCG # 内存cgroup,防OOM拖垮宿主机 + + # === 内存安全检测 === + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable KASAN + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable KASAN_INLINE + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable UBSAN + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --disable UBSAN_ALIGNMENT #rv下开启UBSAN,THP(Transparent Huge Pages)与 UBSAN 冲突 + + # === 栈回溯与内嵌配置 === + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable IKCONFIG + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable IKCONFIG_PROC + + # === eBPF 测试支持 === + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable BPF_SYSCALL + $KERNEL_SRC/scripts/config --file $KERNEL_DEST/.config --enable BPF_JIT + + # 修改完成后更新配置 + make ARCH=riscv -C $KERNEL_SRC O=$KERNEL_DEST olddefconfig + # 编译 + KBUILD_BUILD_USER=builder KBUILD_BUILD_HOST=openEuler make ARCH=riscv -C $KERNEL_SRC O=$KERNEL_DEST -j$(nproc) Image modules + ls $KERNEL_DEST/arch/riscv/boot/Image $KERNEL_DEST/vmlinux + #dnf install -y sshpass + #sshpass -p 'openEuler12#$' scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $KERNEL_DEST/arch/riscv/boot/Image 10.20.237.128:/opt + #sshpass -p 'openEuler12#$' scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $KERNEL_DEST/vmlinux 10.20.237.128:/opt +} + +#准备kexec启动 +kexec_prep(){ + #dnf install -y kexec-tools + cd /build + dnf install -y git gcc make autoconf automake libtool zlib-devel xz-devel bison flex git pkgconfig + git clone https://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git + cd kexec-tools + ./bootstrap + ./configure --host=riscv64-linux-gnu + make -j$(nproc) + # 替换系统自带的 kexec + cp /build/kexec-tools/build/sbin/kexec /sbin/kexec + kexec --version + #查看系统资源 + df -h + free -h +} + +echo "qemu下挂载数据盘" +if [ "$(systemd-detect-virt)" == "qemu" ]; then + load_disk +fi + +echo "编译内核" +make_kernel + +echo "下载kexec-tools软件包" +kexec_prep \ No newline at end of file diff --git a/lava-testcases/security-test/syzkaller/make_kernel.yaml b/lava-testcases/security-test/syzkaller/make_kernel.yaml new file mode 100644 index 0000000..dafb588 --- /dev/null +++ b/lava-testcases/security-test/syzkaller/make_kernel.yaml @@ -0,0 +1,18 @@ +metadata: + name: make_kernel + format: "Lava-Test Test Definition 1.0" + description: "Run fio on RISC-V device" + maintainer: + - zhangju@iscas.ac.cn + os: + - openEuler-riscv64 + scope: + - security + devices: + - qemu +run: + steps: + - cd lava-testcases/security-test/syzkaller + - bash make_kernel.sh + - chmod +x ../../utils/send-to-lava.sh + - ../../utils/send-to-lava.sh ./output/result.txt diff --git a/lava-testcases/security-test/syzkaller/syzkaller.sh b/lava-testcases/security-test/syzkaller/syzkaller.sh new file mode 100644 index 0000000..ea44fac --- /dev/null +++ b/lava-testcases/security-test/syzkaller/syzkaller.sh @@ -0,0 +1,215 @@ +#!/bin/bash + +set -x + + +OUTPUT="$(pwd)/output" +mkdir -p "$OUTPUT" +RESULT_FILE="${OUTPUT}/result.txt" +LAVA_WORKDIR="$(pwd)" + +KERNEL_SRC=/usr/src/linux-$(uname -r) +KERNEL_DEST=/build/linux-build +SYZ_WORKDIR="/build/syzkaller" +CRASH_DIR="$SYZ_WORKDIR/workdir" +FUZZ_HOURS="${1:-1}" # $1 是第一个参数,如果未设置默认为1 +FUZZ_SEC=$((FUZZ_HOURS * 3600)) + + +kasan_test(){ + #准备编译环境 + dnf install -y gcc make flex bison openssl-devel elfutils-libelf-devel \ + perl python3 bc dwarves cpio gzip tar xz util-linux + + # ========== 测试1:KASAN 编译启用 ========== + if zcat /proc/config.gz 2>/dev/null | grep -q "^CONFIG_KASAN=y"; then + echo "KASAN_COMPILE pass" + else + echo "KASAN_COMPILE fail" + fi + # ========== 测试2:KASAN 运行时初始化 ========== + if dmesg | grep -q "kasan :"; then + echo "KASAN_RUNTIME pass" + else + echo "KASAN_RUNTIME fail" + fi + # ========== 测试3:KASAN 错误检测 ========== + mkdir -p /tmp/kasan-test + cat >> /tmp/kasan-test/Makefile << 'EOF' +obj-m += kasan_verify.o + +# 直接指向你的内核构建输出目录(包含顶层 Makefile 和 .config 的那个目录) +KDIR := __KERNEL_DEST__ + +all: + $(MAKE) -C $(KDIR) M=$(PWD) modules + +clean: + $(MAKE) -C $(KDIR) M=$(PWD) clean +EOF + # 再用 sed 替换占位符 + sed -i "s|__KERNEL_DEST__|${KERNEL_DEST}|g" /tmp/kasan-test/Makefile + + cat >> /tmp/kasan-test/kasan_verify.c < +#include + +static int __init kasan_verify_init(void) +{ + char *buf; + pr_info("KASAN verification: testing out-of-bounds...\n"); + buf = kmalloc(16, GFP_KERNEL); + if (!buf) return -ENOMEM; + + /* 故意越界写入,触发 KASAN */ + buf[16] = 'A'; // slab-out-of-bounds + + kfree(buf); + pr_info("KASAN verification: testing use-after-free...\n"); + + return 0; +} + +static void __exit kasan_verify_exit(void) {} + +module_init(kasan_verify_init); +module_exit(kasan_verify_exit); +MODULE_LICENSE("GPL"); +EOF + cd /tmp/kasan-test + # 编译并加载测试模块 + make + insmod kasan_verify.ko + if dmesg | grep -qiE "kasan.*slab-out-of-bounds"; then + echo "KASAN_FUNCTIONAL pass" + else + echo "KASAN_FUNCTIONAL fail" + fi + + # 检查结果后立即清理,为 Syzkaller 准备干净环境 + rmmod kasan_verify || true + dmesg -C +} + + +make_syzkaller(){ + zcat /proc/config.gz | grep -E "BINFMT_MISC|KCOV|VIRTIO_BLK|SELINUX|KASAN" + cd /build + dnf install -y gcc gcc-c++ make cmake automake autoconf git gdb glibc-devel libstdc++-devel binutils patch diffutils pkgconf libstdc++-static go + git clone https://github.com/google/syzkaller.git + cd syzkaller + export GOPROXY=https://goproxy.cn,https://mirrors.aliyun.com/goproxy/,direct #添加代理,加速下载依赖包 + make TARGETOS=linux TARGETARCH=riscv64 -j$(nproc) + ls ./bin/syz-manager ./bin/linux_riscv64/syz-executor +} + +syzkaller_fuzzing(){ + cd $SYZ_WORKDIR + mkdir $CRASH_DIR + RPC_PORT=42173 + cat >> config.json << EOF +{ + "name": "riscv64-local", + "target": "linux/riscv64", + "http": "0.0.0.0:61952", + "rpc": "0.0.0.0:$RPC_PORT", + "workdir": "$CRASH_DIR", + "kernel_obj": "$KERNEL_DEST", + "syzkaller": "$SYZ_WORKDIR", + "type": "none", + "cover": true, + "procs": 4, + "reproduce": false, + "sandbox": "namespace", + "enable_syscalls": [], + "disable_syscalls": [] +} +EOF + timeout $FUZZ_SEC ./bin/syz-manager --config=config.json & + echo "等待 syz-manager RPC 端口 $RPC_PORT 就绪..." + while ! nc -z 127.0.0.1 $RPC_PORT 2>/dev/null; do + sleep 60 + done + ./bin/linux_riscv64/syz-executor runner 0 127.0.0.1 $RPC_PORT +} + +check_result(){ + # 1. 判定: WORKDIR 下不存在 crashes 文件夹 -> PASS + if [ ! -d "$CRASH_DIR" ]; then + echo "kernel_syzkaller" "pass" >> $RESULT_FILE + else + # 2 & 3. 遍历 crashes 目录,区分内核问题与非内核问题 + KERNEL_CRASH_COUNT=0 + NON_KERNEL_CRASH_COUNT=0 + KERNEL_BUG_LIST="" + + # 匹配非内核问题的正则表达式 (可根据实际日志持续补充) + NON_KERNEL_PATTERN="lost connection|no output from test machine|timed out|ssh.*failed|executor.*not responding|qemu.*exited|out of memory|oom-killer.*syz" + + for bug_dir in "$CRASH_DIR"/*/; do + # 跳过空目录或非目录项 + [ ! -d "$bug_dir" ] && continue + + DESC_FILE="${bug_dir}description" + BUG_HASH=$(basename "$bug_dir") + + # 如果连 description 都没有,视为不完整/环境问题 + if [ ! -f "$DESC_FILE" ]; then + NON_KERNEL_CRASH_COUNT=$((NON_KERNEL_CRASH_COUNT + 1)) + continue + fi + + DESCRIPTION=$(cat "$DESC_FILE") + + # 使用大小写不敏感匹配判断是否为非内核问题 + if echo "$DESCRIPTION" | grep -qiE "$NON_KERNEL_PATTERN"; then + NON_KERNEL_CRASH_COUNT=$((NON_KERNEL_CRASH_COUNT + 1)) + else + KERNEL_CRASH_COUNT=$((KERNEL_CRASH_COUNT + 1)) + # 记录真实内核 Bug 信息供 LAVA 日志采集 + HAS_REPRO="NO" + [ -f "${bug_dir}repro.c" ] && HAS_REPRO="YES" + KERNEL_BUG_LIST="${KERNEL_BUG_LIST}\n - [${BUG_HASH:0:8}] $DESCRIPTION (Repro: $HAS_REPRO)" + fi + done + + # ========================================== + # 输出摘要与最终判定 + # ========================================== + echo "=== Syzkaller Result Summary ===" + echo "Total crash entries: $((KERNEL_CRASH_COUNT + NON_KERNEL_CRASH_COUNT))" + echo "Kernel bugs found: $KERNEL_CRASH_COUNT" + echo "Non-kernel issues: $NON_KERNEL_CRASH_COUNT" + + if [ "$KERNEL_CRASH_COUNT" -gt 0 ]; then + echo "kernel_syzkaller" "fail" >> $RESULT_FILE + else + echo "kernel_syzkaller" "pass" >> $RESULT_FILE + fi + fi +} + +echo "测试KASAN基本功能" +kasan_test >> $RESULT_FILE + +echo "编译syzkaller" +make_syzkaller + +echo "执行syzkaller fuzzing" +syzkaller_fuzzing + +echo "输出lava格式结果" +cd $LAVA_WORKDIR +check_result + + + + + + + + + + + + diff --git a/lava-testcases/security-test/syzkaller/syzkaller.yaml b/lava-testcases/security-test/syzkaller/syzkaller.yaml new file mode 100644 index 0000000..d3ba1ad --- /dev/null +++ b/lava-testcases/security-test/syzkaller/syzkaller.yaml @@ -0,0 +1,19 @@ +metadata: + name: syzkaller + format: "Lava-Test Test Definition 1.0" + description: "Run fio on RISC-V device" + maintainer: + - zhangju@iscas.ac.cn + os: + - openEuler-riscv64 + scope: + - security + devices: + - qemu + +run: + steps: + - cd lava-testcases/security-test/syzkaller + - bash syzkaller.sh "${HOURS}" + - chmod +x ../../utils/send-to-lava.sh + - ../../utils/send-to-lava.sh ./output/result.txt