⬢ DragonFlyBSD Kernel Audit
DF-4891 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-4891",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "leak",
  "confidence": "likely",
  "verdict": "DragonFlys DIV_ROUND_DOWN_ULL(x,n) compat shim (sys/dev/drm/include/linux/kernel.h:61) computes (x/n)*n instead of Linuxs floor(x/n); its only user clip_scaled() (sys/dev/drm/drm_rect.c:64) therefore returns a ~dst-times-too-large, mod-2^32-wrapped new_src_w for every clipped 1:1 or downscaled plane update, corrupting plane_state->src AFTER the DRM core validated the original src against the framebuffer. Called the real drm_rect_clip_scaled() from the guests stock drm.ko via a test kld: all three unprivileged-SetPlane geometries produced corrupted source rectangles (12288px-wide src on a 1920px fb; INT_MAX-inverted rects) where Linux semantics yield in-fb 1440/810/960px rects, with visible=1 (plane accepted). Sink code-traced end-to-end on i915 (vlv_sprite_check -> i9xx_check_plane_surface has no src bounds check -> offset = y*pitch + x*cpp, u32, intel_display.c:2410 -> DSPSURF/viewport programming => OOB display-engine scanout = cross-process pixel leak / engine-fault DoS); final screen-leak capture impossible on the std-VGA QEMU guest (no i915 hardware). One-line shim fix validated on the guest: patched drm.ko returns exactly Linux-semantics rectangles, corruption gone.",
  "exploit_chain": "unpriv local user w/ DRM master -> SetPlane/atomic ioctl, 1:1 (NO_SCALING) or downscale geometry with plane partially off-CRTC -> drm_atomic_plane_check validates ORIGINAL src (drm_atomic.c:573) -> drm_atomic_helper_check_plane_state:790 -> drm_rect_clip_scaled -> clip_scaled() else-branch returns (tmp/dst)*dst mod 2^32 (attacker-tuned via src/dst/clip) -> plane_state->src corrupted post-validation -> vlv/skl sprite check paths never re-validate fb bounds -> intel_compute_aligned_offset folds src.x1/width into DSPSURF offset + viewport size -> display engine reads past the framebuffer object -> adjacent GTT/aperture memory displayed (cross-process info leak) or engine fault (DoS). In-kernel corruption primitive demonstrated live; hardware sink traced.",
  "evidence": "run.log lines DF4891[C-1to1-bottomright] KERNEL ... w=805306368(12288px) vs LINUX ... w=94371840(1440px) + DIVERGENCE ... POST-VALIDATION SRC CORRUPTION x3; fix_run.log no divergence x3 after fix.diff; VERDICT.md case table + sink trace",
  "kernel_refs": [
    "sys/dev/drm/include/linux/kernel.h:61",
    "sys/dev/drm/drm_rect.c:53",
    "sys/dev/drm/drm_rect.c:64",
    "sys/dev/drm/drm_rect.c:85",
    "sys/dev/drm/drm_rect.c:106",
    "sys/dev/drm/drm_atomic_helper.c:775",
    "sys/dev/drm/drm_atomic_helper.c:790",
    "sys/dev/drm/drm_atomic.c:562",
    "sys/dev/drm/drm_plane.c:622",
    "sys/dev/drm/i915/intel_sprite.c:1195",
    "sys/dev/drm/i915/intel_sprite.c:255",
    "sys/dev/drm/i915/intel_display.c:3312",
    "sys/dev/drm/i915/intel_display.c:2410",
    "sys/dev/drm/i915/intel_display.c:3025"
  ],
  "poc_changes": "seed was a concept; wrote the real kld (MODULE_DEPEND on drm resolves the no-OP-EXPORT_SYMBOL global), C89-style declarations, sys/types uint32_t instead of linux u32; fixed Case C geometry to hit the else-branch (initial draft hit the correct up-rounding branch); added Linux-semantics reference implementation for side-by-side divergence printing",
  "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": 1150,
  "guest_dirty": 0,
  "build_cmd": "sh /root/df4891/build.sh   (cd /root/df4891 && make; kmod against guest /usr/src)",
  "run_cmd": "sh /root/df4891/run.sh      (kldload drm; kldload df4891.ko; dmesg | grep DF4891)",
  "code_hash": "3d81dbfd2691e4003801738f3dad625fe619ac7099d6cd219cb1fdec5c4c786e",
  "notes": "drm.ko unload stalls on this guest (pre-existing); patched-run performed on fresh boot. calc_scale dst<<16 signed-UB and clip_scaled dst-clip u32-underflow analyzed and killed as findings (contained, see audit negative notes). Guest reset with-src after runs.",
  "recommended_fix": "Fix the shim: DIV_ROUND_DOWN_ULL(x,n) = ((unsigned long long)(x) / (n)) (Linux do_div-truncated quotient); one-line change to sys/dev/drm/include/linux/kernel.h:61, validated on guest",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "One-line shim fix restores Linux floor-division semantics. Guest drm.ko rebuilt with fix.diff on a fresh boot: same test module now returns rectangles identical to upstream Linux semantics on all three geometries (no divergence); baseline stock drm.ko showed corruption on all three. Bad behavior gone.",
  "fix_evidence": "findings/poc/DF-4891/fix_run.log (no divergence x3, kernel==LINUX) vs findings/poc/DF-4891/run.log (DIVERGENCE ... POST-VALIDATION SRC CORRUPTION x3); fix_build.log shows patched drm.ko link"
}