# DF-4378 VERDICT — not_reproduced (no DRM hardware/module on guest), defect certain from source

## Reproduced?

**No — the guest has no DRM device at all.** `chk_drm.c` compiled and ran
(`BUILD_OK_4378`, run.log): `/dev/dri` is absent, `kldstat` lists only kernel,
ehci.ko, xhci.ko, and `sysctl hw.drm` is an unknown OID (the drm core module is not
loaded — QEMU's emulated VGA is handled by the classic vga/vt console stack).
The leak fires only when a DRM driver actually attaches (drm_dev_register → minors →
make_dev) and then detaches; neither exists here.

## Why the defect is certain anyway (path:line)

Resource creation (per minor, primary AND render):

- `sys/dev/drm/drm_drv.c:158` — `minor->kdev = drm_sysfs_minor_alloc(minor);`
- `sys/dev/drm/drm_sysfs.c:93` — `kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);`
- `sys/dev/drm/drm_sysfs.c:97-98` —
  `devnode = make_dev(&drm_cdevsw, minor->index, DRM_DEV_UID, DRM_DEV_GID,
  DRM_DEV_MODE, "dri/%s", dev_str);` — the returned cdev is stored in a **local**
  and never saved anywhere.

Resource release that never happens:

- `sys/dev/drm/drm_drv.c:176-196` — `drm_minor_free()`:
  `put_device(minor->kdev)` is compiled out (`#if 0`, :186-188); the function does
  `idr_remove` + `kfree(minor)` only. Neither the `struct device` nor the cdev is
  released.
- `sys/dev/drm/drm_drv.c:237-260` — `drm_minor_unregister()` NULLs the idr slot and
  `dev_set_drvdata(minor->kdev, NULL)`; no `destroy_dev`.
- Whole-tree check: `rg destroy_dev sys/dev/drm` → **zero** matches. The devfs node
  outlives the driver forever.
- `sys/dev/drm/drm_file.c:497` — `kdev->si_drv1 = dev;` is written at open time on
  the cdev; after `drm_dev_fini()` frees the `drm_device` (kref 0 →
  `drm_dev_release` → `drm_dev_fini` → `drm_minor_free`), the surviving node's
  `si_drv1` is a dangling pointer. Users cannot reach it: post-unregister opens
  fail ENODEV in `drm_minor_acquire()` (drm_drv.c:271-290, idr slot NULLed under
  `drm_minor_lock`), and mmap requires a successful open first.

Exploitability: not a memory-safety primitive for an unprivileged user — a
resource/lifetime hygiene bug (kernel heap leak per driver attach/detach cycle +
stale devfs entry + name collision on re-attach of the same minor index). Trigger
is privileged (kldunload/devctl) or physical (hotplug) → **Low**.

## What I checked and killed on this file (pass-2 negatives)

- `drm_minor_acquire`/`release` (drm_drv.c:271-295): the kref is taken under
  `drm_minor_lock` and minors are only freed at dev-refcount 0 in `drm_dev_fini`,
  *after* unregister NULLed the idr slot — no acquire/free race.
- `drm_stub_open` (:1015-1053) and `drm_release` glue: `#if 0` — dead on this port;
  real open/close are `drm_open`/`drm_close` (drm_file.c) with balanced
  acquire/release.
- `drm_cdevpriv_dtor` (:1194-1236): **dead code** — nothing in sys/dev/drm calls
  `devfs_set_cdevpriv`; had it been live, its missing `kfree(file_priv)` (and the
  duplicate release sequence vs `drm_close`) would double-release. Worth deleting.
- `drm_mmap_single` (:1256-1274): `dev = kdev->si_drv1` looks unchecked-NULL, but
  `si_drv1` is set by `drm_open_helper` before any fd exists, and an open fd pins
  the `drm_device` via the minor acquire ref → not reachable with NULL/dangling.
- `dmi_found` (:1281-1339): `kgetenv()` returns either a kmalloc'd copy (dynamic
  kenv) or a static pointer; `kfreeenv()` self-guards on `kenv_isdynamic`
  (kern_environment.c:229-251/332-336) → pairing is balanced, no bad free.
- `drm_dev_init` error path (:635-650): `drm_minor_free` is NULL-slot-guarded and
  idempotent; sysctl init/cleanup pairing is correct on every goto path.
- idr ranges (PRIMARY 0-63 / RENDER 64-127), `controlD%d` naming, `busid_str`
  ksnprintf sizing, `drm_debug`/tunable plumbing: all in-bounds/benign.

## Fix validation

`fix.diff` authored against the read-only tree (adds `struct cdev *devnode` to
`struct drm_minor`, stores the make_dev result, and destroys/frees both in
`drm_minor_free`, with `<sys/conf.h>` included before the function). **Not
applied**; fix validation `not_testable` — the guest cannot attach a DRM driver,
so neither the baseline leak nor the patched behavior can be observed. The diff is
compile-checkable by inspection (cdev_t == `struct cdev *`; incomplete-type member
declaration is valid in drm_file.h; `destroy_dev` prototype comes from
`<sys/conf.h>`).

## Guest evidence

- `run.log`: uname, BUILD_OK_4378, `/dev/dri absent`, EXIT=2, kldstat (no drm),
  `sysctl: unknown oid 'hw.drm'`.
- `env.txt`: guest identity + absence summary.

## 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.
