DF-5134 / verdict.json
{ "finding_id": "DF-5134", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "dma_buf_fd() (sys/dev/drm/linux_dma-buf.c:139-166) ends with fdalloc()+fsetfd(), and DragonFly fsetfd() takes an ADDITIONAL file reference (fhold, kern_descrip.c:2191) where Linuxs fd_install() consumes the callers; the missing balancing fdrop() orphans one reference per PRIME export. Reproduced live as uid 65534 on stock drm.ko: after the trigger closes the only fd, the dma_bufs struct file sits at f_count=1 with zero owners; dmabuf_close() can never run, which in the real drm_prime path also makes the GEM object (+ its pinned, user-sized pages) and the drm_device immortal and permanently consumes one entry of the global file table (kern.maxfiles exhaustion). This is the export-side mirror of the known import-side DF-2132 (over-drop UAF): here the port under-drops, producing an unbounded kernel memory + fd-table leak reachable from a drm render node. fix.diff (fdrop after fsetfd) validated on the guest: f_count reaches 0, ops->release runs, dmabuf_close frees everything.", "exploit_chain": "unpriv render node -> DRM_IOCTL_PRIME_HANDLE_TO_FD -> drm_gem_prime_handle_to_fd (drm_prime.c:643-685, no dma_buf_put on success, correct for Linux fd_install semantics) -> dma_buf_fd() fsetfd(+1) with no fdrop -> close(fd)(-1) + last-gem-handle drm_gem_object_exported_dma_buf_free -> dma_buf_put(-1) => orphaned +1; struct file + struct dma_buf + drm_gem_object (+pages) + drm_device never freed; loop new-object exports => kernel memory pinning + nfiles -> kern.maxfiles => system-wide ENFILE DoS.", "evidence": "run.log: [leak_trigger] check: orphan f_count=1 => LEAK (LEAK_RC=2) as uid 65534 with kernel-side dmesc check: ... f_count=1 (fd closed, no other owner exists); fix_run.log: f_count=0 => no leak, ops->release(...) ran -> dmabuf_close() frees it, LEAK_RC=0 on the patched drm.ko.", "kernel_refs": [ "sys/dev/drm/linux_dma-buf.c:139", "sys/dev/drm/linux_dma-buf.c:163", "sys/dev/drm/linux_dma-buf.c:54", "sys/kern/kern_descrip.c:2186", "sys/dev/drm/drm_prime.c:368", "sys/dev/drm/drm_prime.c:669", "sys/dev/drm/drm_gem.c:267" ], "poc_changes": "PoC written from scratch (no seed). No GPU on the guest, so the kmod performs the stock dma_buf_export()+dma_buf_fd() calls (same calls drm_prime makes) in the unprivileged triggers context; the trigger closes the fd and a CTLFLAG_ANYBODY sysctl reads back the orphans f_count.", "attempts": 2, "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": 400, "guest_dirty": 0, "build_cmd": "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_cmd": "kldload drm && kldload /usr/obj/root/poc/dmabugdemo.ko && su -m nobody -c /tmp/leak_trigger", "code_hash": "b88fa89ec9255bf424440dff0c5f08c637ef53a627d7626f00c5fcac477a74b6", "notes": "Distinct from known DF-2132/DF-4515 (import-side dma_buf_get()/fd_to_handle over-drop UAF): this is the export side under-dropping (over-hold leak). Repeated re-export of the same object cycles refs harmlessly; each NEW object export leaks one immortal cluster. Guest reset clean after validation.", "recommended_fix": "In dma_buf_fd(), fdrop(dmabuf->file) after fsetfd(curproc->p_fd, dmabuf->file, fd) so the fd install consumes the callers reference exactly like Linux fd_install().", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff adds the balancing fdrop() in dma_buf_fd(); drm.ko rebuilt on the guest, rebooted, identical uid-65534 trigger: f_count now reaches 0, ops->release runs, dmabuf_close frees the object, LEAK_RC=0. Baseline leaked on the same guest minutes earlier.", "fix_evidence": "fix_run.log (ops->release(dmabuf=0xfffff8008d602060) ran -> dmabuf_close() frees it, check: ... NO leak (fixed kernel), LEAK_RC=0); fix_build.log (drm.ko rebuild with both dma-buf hunks).", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0 (same base kernel; /boot/kernel/drm.ko rebuilt from patched source)" } |