DF-4803 / verdict.json
{ "finding_id": "DF-4803", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "parityops() computes its transfer size as imin(DEFAULT_REVIVE_BLOCKSIZE, plex->stripesize << DEV_BSHIFT) (vinumrevive.c:274-275) with stripesize an int in sectors and no upper bound from the config parser (plex org raid5 3g is accepted). For stripesize >= 2 GiB the shift overflows int; 3 GiB wraps to 0xC0000000 (negative), imin selects it, and parityrebuild() derives mysize via the same overflowing expression (:382) and Malloc()s the sign-extended ~1.8e19 value (:393) -- kmalloc(M_WAITOK) cannot fail, so the first parity ioctl panics in kmem_slab_alloc. Reproduced deterministically on the stock kernel: one vinum checkparity on the 3g-stripe plex -> panic: kmem_slab_alloc(): kernel_map ran out of space! with backtrace _kmalloc <- parityrebuild+0x162 <- parityops+0x82 <- vinumioctl (panic.log).", "exploit_chain": "root: config string plex org raid5 3g (or any stripesize >= 2 GiB) + one checkparity/rebuildparity ioctl -> immediate kernel panic (local DoS)", "evidence": "panic.log (full serial console: the panic backtrace through parityrebuild/parityops/vinumioctl, plus the config acceptance lines)", "kernel_refs": [ "sys/dev/raid/vinum/vinumrevive.c:274", "sys/dev/raid/vinum/vinumrevive.c:382", "sys/dev/raid/vinum/vinumrevive.c:393", "sys/dev/raid/vinum/vinumext.h:258" ], "poc_changes": "none - shell-only trigger", "attempts": 1, "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": 120, "guest_dirty": 0, "build_cmd": "(none)", "run_cmd": "sh run_vbd1.sh (raid5 3g config + setstate up + vinum checkparity rv.p0)", "code_hash": "7eaa9f52a13ad267472a48f738c0fee5507e1b458664b4b01e3dd790ec357604", "notes": "root-gated (controld 0600 + config ioctls), deterministic one-ioctl panic; severity Low consistent with the DF-1886 div0 sibling", "recommended_fix": "compute the stripe cap in 64-bit (vinum_off_t) and clamp to DEFAULT_REVIVE_BLOCKSIZE before demoting to int, in both parityops (:274) and parityrebuild (:382)", "fix_status": "not_testable", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff not built this run (Low-severity root-gated panic; the 64-bit clamp is mechanical and risk-free) - baseline panic captured, patch recommended", "fix_evidence": "panic.log" } |