DF-2275 / verdict.json
{ "finding_id": "DF-2275", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "REPRODUCED on the CAM verbatim-interposition harness kernel (DragonFly 6.5-DEVELOPMENT X86_64_GENERIC, INVARIANTS): a userland ioctl(DAIOCTRIM) with a non-512-aligned length {0,4104} or offset {520,4096} on the fabricated but fully real /dev/da99 (real make_dev + real daopen SYSCAP gate) panics the machine exactly at scsi_da.c:443 and :444 - the panic strings cite harness lines 558/559 which are verbatim 443/444 after the 115-line preamble, and the backtrace is the full real dispatch daioctl <- dev_dioctl <- devfs_fo_ioctl <- mapped_ioctl <- syscall2. Both panics captured on serial console. Honest reach: openers must pass SYSCAP_RESTRICTEDROOT at daopen (scsi_da.c:505), so this is a privileged-reach local DoS (panic), not privesc; on non-INVARIANTS kernels the asserts vanish and the same bad input falls into the DF-2276 loop machinery. Fix validated A/B on a single-fix kernel: both misaligned cases now return EINVAL with the guest staying up while the aligned control still succeeds with a byte-identical TRIM CDB.", "exploit_chain": "", "evidence": "panic.txt has both console traces with the assertion text and backtraces; serial_mlen_full.log and serial_moff_full.log are the raw serial consoles; run.log pairs each userland trigger with its panic and the fixed EINVAL results; rig/verbatim.log proves the compiled driver is byte-for-byte the audited scsi_da.c; rig/run_baseline_outer.log has the functional aligned control through the real TRIM path.", "kernel_refs": [ "sys/bus/cam/scsi/scsi_da.c:443", "sys/bus/cam/scsi/scsi_da.c:444", "sys/bus/cam/scsi/scsi_da.c:415-485", "sys/bus/cam/scsi/scsi_da.c:505", "sys/bus/cam/scsi/scsi_daio.h:38", "sys/kern/sys_generic.c:681-724", "sys/vfs/devfs/devfs_vnops.c:1786" ], "poc_changes": "No seed PoC existed for this finding; the rig was written from scratch following the established DF-2263..2273 CAM verbatim-interposition pattern (scsi_da.c replaced in place on the guest by df_pre.c + verbatim + df_post.c because device da must stay configured; fabricated second disk da99; per-object pass-through shims). First build failed on three compile errors (opaque struct cam_path replaced by an identity-token array, void* ccb_bio cast, ccb timeout_ch pointer allocation); after those fixes the harness built and every run reproduced first try.", "attempts": 2, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Sun Oct 18 01:07:00 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 240, "guest_dirty": 0, "build_cmd": "cd rig && ./build.sh (nativekernel + installkernel + reboot, then cc -O2 -o /root/da_user da_user.c)", "run_cmd": "vm.sh run_root sysctl debug.dfda.setup=1; vm.sh run_root /root/da_user mlen; vm.sh run_root /root/da_user moff", "code_hash": "d490a01c2284caa9d0512cea3283e3e7ade0c03a130745c315a3069d398f2af0", "notes": "Privileged-reach DoS class per team directive: no unprivileged route (daopen SYSCAP_RESTRICTEDROOT). KKASSERT is a diagnostic, so production non-INVARIANTS kernels are not panicked by this case; the same invalid input there flows into the DF-2276 loop instead. FreeBSD canonical shape for the equivalent DIOCGDELETE validates alignment and length <= 0 with EINVAL up front (sys/geom/geom_dev.c:609-618). Guest was reset with-src after the run.", "recommended_fix": "Replace both KKASSERTs in daioctl with EINVAL returns for misaligned or negative user ranges (fix.diff, validated A/B).", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #2: Sun Oct 18 01:35:38 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Single-fix kernel (fix.diff: reject negative range, then EINVAL for misaligned length and offset) built with quickkernel and A/B tested: mlen and moff both return errno 22 with the guest staying up (baseline panicked at scsi_da.c:443/:444), and the aligned control {0,4096} still completes the full real TRIM path with a byte-identical CDB (1 range, lba 0, count 8, dxfer 512).", "fix_evidence": "fix_run.log (mlen/moff EINVAL lines and aligned control); rig/run_fixed_outer.log (full suite); rig/disasm_daioctl_fixed.txt (patched daioctl shows the js sign-check branches to the EINVAL path)." } |