DF-5538 / verdict.json
{ "finding_id": "DF-5538", "status": "reproduced", "reproduced": true, "impact": "dos", "confidence": "certain", "verdict": "REPRODUCED + FIX VALIDATED. sys/platform/vkernel64/platform/copyio.c:165 (swapu32) and :229 (fuwordadd32) use the 64-bit twins page-straddle guard `PAGE_SIZE - (p & PAGE_MASK) < sizeof(uint64_t)` for 32-bit operations, so a 4-byte-aligned word at page offset 0xFFC (which fits entirely in-page) is spuriously rejected with the fault sentinel -1. Live via umtx_sleep(2) (kern_umtx.c:146/172/224 reads the word with fuwordadd32): inside a vkernel, a page-tail futex NEVER sleeps on a matching value (instant EBUSY, verified elapsed=0.000s vs control 1.460s at offset 0) and sleeps the FULL timeout on a phantom -1 that is not the words value (verified 0.300s sleep with word=0x41). Native pc64 reference with the identical binary: all probes correct. No memory unsafety (guard is over-strict, never under-strict); impact ceiling is broken userland synchronization inside a vkernel (lost wakeups / busy-fail / phantom sleeps). Applying fix.diff (sizeof(uint64_t) -> sizeof(uint32_t) at both sites), rebuilding VKERNEL64 and re-running the exact PoC: all probes pass (B sleeps 1.510s, C instant EBUSY, RESULT OK mask=0).", "exploit_chain": "", "evidence": "run.log (vkernel baseline: probe B off0xFFC EBUSY elapsed 0.000, probe C sleeps 0.300s on phantom -1, control A off0x000 OK; plus native pc64 reference run all-OK in build/run transcript), run.fixed.log (post-fix: B sleeps 1.510s, C instant EBUSY, VKPROBE_RC=0), fix-build.log (incremental rebuild NK_RC=0, copyio.o recompiled), fix.diff (two-line change), env.txt (guest uname + image md5)", "kernel_refs": [ "sys/platform/vkernel64/platform/copyio.c:165", "sys/platform/vkernel64/platform/copyio.c:229", "sys/platform/vkernel64/platform/copyio.c:96", "sys/kern/kern_umtx.c:146", "sys/kern/kern_umtx.c:127", "sys/platform/pc64/x86_64/uwrapper.c:82" ], "poc_changes": "Seed had no code: wrote df5538.c from scratch (three umtx_sleep probes: page-offset-0 control, page-tail 0xFFC matching-value, page-tail 0xFFC sentinel-value, classified by elapsed time because DF umtx_sleep returns EAGAIN after sleeping out its timeout). Initial probe classification wrongly required rc==0 for slept \u2014 fixed to time-based classification after the native reference run revealed the EAGAIN-on-timeout convention. Run rig (build_kernel/image/run.sh) adapted from the proven DF-5337 vkernel rig.", "attempts": 3, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 1380, "guest_dirty": 1, "build_cmd": "cc -static -O2 -o /root/df5538 /root/df5538.c (guest); cd /usr/src && make -j6 nativekernel KERNCONF=VKERNEL64 (vkernel kernel)", "run_cmd": "sh /root/run5538.sh (boots /usr/obj/usr/src/sys/VKERNEL64/kernel.debug -m 512m -r /vkroot.img -n 2, runs /root/df5538 on the vkernel console); native reference: /root/df5538", "code_hash": "be43ea7fdd4baeb7a4d16b06e80b753fac2ffe464424ed93787be60f29e8f85c", "notes": "vkernel-only; host kernel pc64 path verified correct natively (same binary, all probes OK). swapu32 latent (no in-tree caller); casu32/casu64/swapu64/fuwordadd64 also caller-less. Guest /usr/src was patched for fix validation and the guest rebuilt VKERNEL64 \u2014 guest reset with-src performed before return per contract.", "recommended_fix": "copyio.c:165 and :229: change the 32-bit ops straddle guard from sizeof(uint64_t) to sizeof(uint32_t)", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "Baseline vkernel: probe B off0xFFC instant EBUSY (0.000s) and probe C slept 0.300s on phantom -1 (BROKEN mask=3). After applying fix.diff to guest /usr/src, incremental make nativekernel KERNCONF=VKERNEL64 (NK_RC=0), exact same PoC: probe B sleeps the full 1.510s (EAGAIN after sleep = word read correctly), probe C instant EBUSY, RESULT OK mask=0, VKPROBE_RC=0. Bad behavior gone; no regressions in control probe A.", "fix_evidence": "fix.diff; fix-build.log; run.fixed.log (post-fix console); run.log (baseline console)" } |