# DF-4564 — radeon_kms: dropped `radeon_bo_unreserve` in open path permanently holds the IB-pool BO reservation → first DRM close/open wedges the GPU for every client

* File: `sys/dev/drm/radeon/radeon_kms.c`
* Class: DragonFly port divergence from Linux upstream → lock leak → unprivileged local DoS (requires a Cayman-or-newer radeon GPU)
* Verified by code trace + upstream diff; **not runnable on the audit guest (no radeon GPU)**

## TL;DR

`radeon_driver_open_kms()` reserves the IB-pool buffer object and never
releases it — not on the success path, not on any error path:

```c
sys/dev/drm/radeon/radeon_kms.c:662
	r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);   /* taken */
	if (r)
		goto err_vm_fini;
	vm->ib_bo_va = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo);
	if (!vm->ib_bo_va) { r = -ENOMEM; goto err_vm_fini; }  /* STILL HELD */
	r = radeon_vm_bo_set_addr(rdev, vm->ib_bo_va, ...);
	if (r) goto err_vm_fini;                               /* STILL HELD */
	...
	return 0;                                              /* STILL HELD */
```

`radeon_bo_reserve(bo, false)` → `ttm_bo_reserve(&bo->tbo, interruptible=false,
...)` → `ww_mutex_lock(&bo->resv->lock, NULL)` (sys/dev/drm/radeon/radeon_object.h:64,
sys/dev/drm/include/drm/ttm/ttm_bo_driver.h:653-676) — a **blocking,
non-interruptible** reservation. The reservation is not owned by a thread or
syscall; nothing ever releases it:

* the only `radeon_bo_unreserve(rdev->ring_tmp_bo.bo)` in the entire driver is
  the one inside `radeon_driver_postclose_kms()` at radeon_kms.c:737, guarded
  by its *own* `radeon_bo_reserve()` at :733 succeeding.

Consequences on any cayman+ (`rdev->family >= CHIP_CAYMAN`) radeon with
`accel_working`:

1. The **first** client's `close()` of `/dev/dri/card0` hangs forever inside
   `radeon_driver_postclose_kms()` at :733 (`ww_mutex_lock`, uninterruptible).
   The process cannot be killed; the fd never finishes closing.
2. Every **subsequent** `open()` by any user hangs at :662 — the DRM device is
   permanently wedged for the whole system (X, wayland, every GL app).
3. The error-path variant (vm_bo_add ENOMEM / set_addr failure) additionally
   wedges the device with no client at all.

## Upstream divergence (the dropped lines)

Linux v3.18 `drivers/gpu/drm/radeon/radeon_kms.c`
(`radeon_driver_open_kms`), immediately after `radeon_vm_bo_set_addr`:

```c
		r = radeon_vm_bo_set_addr(rdev, vm->ib_bo_va, RADEON_VA_IB_OFFSET,
					  RADEON_VM_PAGE_READABLE |
					  RADEON_VM_PAGE_SNOOPED);

		radeon_bo_unreserve(rdev->ring_tmp_bo.bo);     /* <-- dropped in DF */
		if (r) {
			radeon_vm_fini(rdev, vm);
			kfree(fpriv);
			return r;
		}
```

The DragonFly port removed the unconditional `radeon_bo_unreserve()` (and the
equivalent in the `!ib_bo_va` error path), leaving the reservation permanently
held. Restore the upstream lines (see fix.diff).

## Reachability / severity

* Requires a physically present cayman+ radeon (HD 6900 / GCN era) with
  `accel_working` — the open path only takes the reservation when
  `rdev->accel_working` is set (radeon_kms.c:656).
* Unprivileged: `open()`+`close()` of the DRM node only; no DRM_AUTH, no
  master, no ioctls needed. First close = permanent wedge.
* Medium severity (hardware-gated unprivileged DoS; no memory corruption).
* Not testable on the audit guest (QEMU, no radeon PCI device, `/dev/dri`
  absent) — verdict is a code-trace verdict: `not_reproduced` runtime,
  divergence confirmed against upstream sources.

## Fix

`fix.diff` restores the upstream `radeon_bo_unreserve()` calls (error path and
after `radeon_vm_bo_set_addr`).
