โฌข DragonFlyBSD Kernel Audit
DF-5222 / verdict.json
โ† back to finding โ†“ download raw
{
  "finding_id": "DF-5222",
  "status": "untested",
  "reproduced": false,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Confirmed at code level, untested at runtime by design (Info hardening; PoC exempt per contract). Exported drm_legacy_ioremapfree() (sys/dev/drm/drm_memory.c:76-83) frees device mappings with a raw pmap_unmapdev() (:81) instead of the linuxkpi iounmap(), so any kmod pairing it with drm_legacy_ioremap()/_wc() permanently orphans the struct iomap entry that __ioremap_common() registered in iomap_list (sys/dev/drm/linux_iomapping.c:50-56): leaked kernel memory + stale SLIST node naming freed KVA + skipped PAT restore (linux_iomapping.c:88-91,99,102). NOT attacker-reachable: zero in-tree callers exist (whole-tree search โ€” only drm_memory.c:64-83 and drm_legacy.h:191-193); the live MMIO paths use ioremap/iounmap directly (drm_bufs.c:219-222,341,358,524) with consistent bookkeeping, and the only user-reachable ioctl in the area is DRM_IOCTL_ADD_MAP gated DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY (drm_ioctl.c:590). Triggering requires root to load a bespoke kmod โ€” root attacking itself.",
  "exploit_chain": "",
  "evidence": "VERDICT.md (root-cause trace with path:line + reachability analysis); README.md (mechanism + why Info); fix.diff (one-line fix: iounmap(map->handle)). No run logs โ€” PoC intentionally not executed for an Info-severity finding with no unprivileged path; guest not booted.",
  "kernel_refs": [
    "sys/dev/drm/drm_memory.c:64-68",
    "sys/dev/drm/drm_memory.c:76-83",
    "sys/dev/drm/linux_iomapping.c:41-59",
    "sys/dev/drm/linux_iomapping.c:61-103",
    "sys/dev/drm/drm_bufs.c:219-222",
    "sys/dev/drm/drm_bufs.c:524",
    "sys/dev/drm/drm_ioctl.c:590",
    "sys/dev/drm/include/drm/drm_legacy.h:191-193",
    "sys/dev/drm/include/asm/io.h:146"
  ],
  "poc_changes": "No seed PoC existed (finding produced by this pass-2 audit). PoC intentionally not authored/run: Info hardening finding, exempt from Phase V per contract; impact ceiling is root-self-harm via bespoke kmod.",
  "attempts": 0,
  "guest_uname": null,
  "runtime_sec": 0,
  "guest_dirty": 0,
  "build_cmd": "",
  "run_cmd": "",
  "code_hash": "6ab59be7484e1848538f4da00b07a00af39e0bc81ea65898204548a7d6f72247",
  "notes": "code_hash is sha256 of fix.diff (no PoC source exists). Also verified while auditing: pmap_unmapdev rounds size up (pmap.c:6227-6229) so no partial-unmap hazard; __ioremap_common BUG_ONs unaligned offset/size (linux_iomapping.c:47-48) and its only user-parameterized caller pre-validates alignment (drm_bufs.c:176-179); the file contains no size math, no copyin/copyout, no page allocators (drm_get_max_iomem is #if 0; agp_remap stub unused).",
  "recommended_fix": "In drm_legacy_ioremapfree() replace the direct pmap_unmapdev() call with iounmap(map->handle) so the linuxkpi iomap_list bookkeeping stays balanced (see fix.diff).",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": null,
  "fix_patched_reproduced": null,
  "fix_verdict": "fix.diff is a one-line reroute of the free path through iounmap(); declaration already visible via drmP.h:43 -> linux/io.h:32 -> asm/io.h:146. Not runtime-validated because there is no reproduction to validate against (finding is Info with no in-tree trigger); fix_status=not_testable accordingly.",
  "fix_evidence": "findings/poc/DF-5222/fix.diff; include chain sys/dev/drm/include/drm/drmP.h:43 -> include/linux/io.h:32 -> include/asm/io.h:146."
}