# DF-5134 — dma_buf_fd() never drops the caller's file reference: every PRIME
# export permanently leaks file + dma_buf + GEM object (+ pinned pages)

`sys/dev/drm/linux_dma-buf.c:139-166` — on Linux, `dma_buf_fd()` ends with
`fd_install(fd, dmabuf->file)`, and `fd_install()` **consumes** one reference
to the file: the reference the caller owns (from `dma_buf_export()`, or from
the `get_dma_buf()` it did before calling). The DragonFly port instead uses
`fdalloc()` + `fsetfd()`, and `fsetfd_locked()` **takes an additional
reference** (`fhold(fp)`, kern_descrip.c:2191) — it consumes nothing. The
port's `dma_buf_fd()` then returns without the balancing `fdrop()`.

Consequence, per successful `DRM_IOCTL_PRIME_HANDLE_TO_FD`
(drm_prime.c:669): exactly one `struct file` reference is orphaned
(f_count never returns to 0), so:

* `fo_close` = `dmabuf_close()` never runs → `dmabuf->ops->release()` never
  runs → the `drm_gem_object_get()` taken by `drm_gem_dmabuf_export()`
  (drm_prime.c:372) is never dropped → the GEM object (and, for i915, its
  backing pages — user-chosen size) is immortal;
* the `drm_dev_get()` from the same path is never dropped;
* `struct file` stays allocated and on the global filelist forever, and
  `nfiles` never decreases → looping exports walks the system into
  `kern.maxfiles` (ENFILE for every process, root included).

Reference ledger for one export → close(handle) → close(fd) on the buggy
kernel: falloc(+1, orphan) → fsetfd(+1) → close fd(−1) → last-GEM-handle
close → drm_gem_object_exported_dma_buf_free → dma_buf_put(−1) ⇒ **1 left,
owned by nobody**. On Linux the fd_install consumes the caller's +1 and the
count reaches 0.

## Reproduce (audit QEMU guest, no GPU)

The `dmabugdemo` kmod performs the real `dma_buf_export()` + `dma_buf_fd()`
(stock drm.ko symbols) in the firing process's context — the same two calls
`drm_gem_prime_handle_to_fd()` makes — then the unprivileged trigger simply
closes the fd and a second sysctl prints the orphaned file's `f_count`.

```
# build
cd /root/poc
cc -O -o leak_trigger leak_trigger.c
printf 'KMOD=\tdmabugdemo\nSRCS=\tdmabuf_demo.c\n\n.include <bsd.kmod.mk>\n' > Makefile
make

# run (as nobody)
kldload drm && kldload /usr/obj/root/poc/dmabugdemo.ko
su -m nobody -c /tmp/leak_trigger
```

## Expected output (baseline)

```
[leak_trigger] uid=65534 pid=1296 got dmabuf fd=3 (refs: 1 from dma_buf_export/falloc + 1 from fd table)
[leak_trigger] closing fd=3; after this NO ONE holds the buffer ...
[leak_trigger] check: orphan f_count=1 => LEAK: struct file + dma_buf never freed (repro)
LEAK_RC=2
```

On the fixed kernel the same run prints
`f_count=0 => no leak` and the kmod logs `ops->release(...) ran -> dmabuf_close() frees it`.

## Fix validation

`fix.diff` (same file as DF-5133's fo_shutdown fix) adds the balancing
`fdrop(dmabuf->file)` after `fsetfd()` in `dma_buf_fd()`. Rebuilt drm.ko on
the guest, rebooted, re-ran:

```
[leak_trigger] uid=65534 pid=999 got dmabuf fd=3 ...
dmabug: mkfd: ... f_count=1 (expect 2: falloc + fd-table)   <- fdrop consumed the ref
dmabug: ops->release(dmabuf=0xfffff8008d602060) ran -> dmabuf_close() frees it
dmabug: check: ops->release ran + file freed -> NO leak (fixed kernel)
LEAK_RC=0
```
