# DF-4459 — PoC Verification Verdict

**File:** `sys/dev/drm/drm_gem.c` (pass 2), `drm_gem_init()` at
drm_gem.c:130-163.
**Guest:** DragonFly 6.5-DEVELOPMENT (X86_64_GENERIC), cc 8.3.

## Verdict: INCONCLUSIVE at runtime (code defect Certain; OOM-gated)

## Root cause

```c
139:	mm = kzalloc(sizeof(struct drm_gem_mm), GFP_KERNEL);
140:	vma_offset_manager = kzalloc(sizeof(*vma_offset_manager), GFP_KERNEL);
141:	if (!vma_offset_manager) {              /* <-- mm is NOT checked */
142:		DRM_ERROR("out of memory\n");
143:		return -ENOMEM;
144:	}
146:	dev->mm_private = mm;
148:	if (drm_ht_create(&mm->offset_hash, 12)) {
149:		kfree(mm);                       /* <-- dev->mm_private dangles */
150:		return -ENOMEM;
151:	}
```

Three defects on the OOM paths:

1. **NULL-deref panic:** if `kzalloc(mm)` (139) fails while
   `kzalloc(vma_offset_manager)` (140) succeeds, execution proceeds to
   `drm_ht_create(&mm->offset_hash, 12)` (148) — a NULL pointer offset
   dereference inside the drm hashtable create (`&NULL->offset_hash`,
   dereferenced by drm_ht_create) → kernel panic. Unprivileged users
   can drive the system into kernel-memory exhaustion (GFP_KERNEL
   allocations fail under pressure), but the allocation here happens
   at drm device registration (module load / device attach), so the
   practical trigger is memory pressure coinciding with a drm
   (re)load.
2. **Memory leak:** on the `!vma_offset_manager` path (141-144), `mm`
   (139) is leaked.
3. **Dangling `dev->mm_private`:** `dev->mm_private = mm` (146) is
   assigned *before* `drm_ht_create` can fail; the failure path
   kfrees `mm` (149) without clearing `dev->mm_private` — later
   `drm_gem_destroy()` runs `drm_mm_takedown(&mm->offset_manager)`
   (170) and `drm_ht_remove` (171) on freed memory (UAF), and every
   `drm_gem_create_mmap_offset_size()` in between dereferences the
   stale pointer (drm_gem.c:570, 576-577). (vma_offset_manager is
   likewise leaked on this path.)

Upstream FreeBSD checks both allocations (`if (!mm) …`); the DragonFly
port dropped the mm check and reordered the assignment.

## Reproduction

Not runtime-reproducible: the only trigger is `kzalloc(GFP_KERNEL)`
failure during drm device init — not injectable on the QEMU guest (no
fault-injection knob for this site, and no drm hardware; force-loading
drm.ko without hardware wedges the loader). Static verification of the
defect: `run.sh` (greps the tree, `run.log`); the data-flow is fully
cited above.

## Fix validation

`fix.diff` checks both allocations, frees both on failure, and moves
`dev->mm_private = mm` after the `drm_ht_create` success point.
Compile-validated on the guest: drm.ko rebuilt with the patch,
`-Werror`, RC=0 (build.log; combined with the sibling DF-4458/DF-4460
hunks). `git apply --check` passes against the pristine tree.
fix_status=not_testable (no OOM injection / no drm hardware),
compile-validated.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
