# DF-5144 — VERDICT

**Status: untested (Phase V skipped — Info severity, no guest run).**
**Impact: none (function is dead code in this tree).**

## Narrative

Pass-2 re-audit of `sys/dev/drm/amd/display/dc/core/dc_surface.c` (210 LOC),
known finding DF-2140 (construct() NULL derefs at :42-46) excluded from
re-reporting.

The pass-2 hunt concentrated on the destruct() pairing, refcount lifetimes,
and the API surface of the plane-state object. Findings:

* **destruct() pairing is correct.** `dc_gamma_release(&plane_state->gamma_correction)`
  (dc_surface.c:52) takes `struct dc_gamma **` and NULLs the caller's pointer
  (dc_surface.c:159-163); `dc_transfer_func_release(plane_state->in_transfer_func)`
  (dc_surface.c:55-56) takes a single pointer and does **not** NULL it
  (dc_surface.c:190-193), but destruct() NULLs the field manually at :57.
  The only other in-tree release of a plane's transfer func is the
  `fill_plane_attributes()` error path (`amdgpu_dm.c:2454-2458`), which likewise
  releases-then-NULLs before the caller's `dc_plane_state_release()`
  (`amdgpu_dm.c:5477-5480`); destruct() then skips the NULL field. **No
  double-release exists in this tree.** The `**` vs `*` API asymmetry between
  `dc_gamma_release` and `dc_transfer_func_release` is a trap for future callers
  but not a bug today.

* **Refcount pairing in the DC core is balanced** — retain on attach
  (dc_resource.c:1397-1398), release on detach (dc_resource.c:1477-1479),
  release-all in `dc_resource_state_destruct` (dc_resource.c:2556-2560),
  retain-all in copy-construct (dc_resource.c:2593-2596).

* **`enable_surface_flip_reporting()` (dc_surface.c:64-69) is dead code** — no
  callers; its unchecked `controller_id + DC_IRQ_SOURCE_PFLIP1 - 1` enum
  arithmetic is latent only.

* **`dc_plane_get_status()` (dc_surface.c:98-129) is dead code** — declared at
  `dc.h:563`, zero callers tree-wide. It carries three latent defects:

  1. `core_dc->res_pool` dereferenced unchecked at **dc_surface.c:118**
     (`core_dc->res_pool->pipe_count`) while `plane_state`, `ctx`, `ctx->dc`
     (:105-107) and `current_state` (:115) are all checked.
  2. **Lockless iteration** over `core_dc->current_state->res_ctx.pipe_ctx[]`
     at :118-126: `dc->current_state` is swapped and the old state freed at
     `dc.c:1026-1030` / `:1649-1650` with no internal DC lock — the function
     relies entirely on caller-side serialization. A future caller that does
     not hold the DRM modeset locks races a use-after-free read.
  3. Unchecked function-pointer call `core_dc->hwss.update_pending_status(pipe_ctx)`
     at :125 — currently populated by every hw sequencer (dce110:2883,
     dcn10:2719; dce80 delegates via dce80_hw_sequencer.c:77), so robustness only.

  Why this matters despite being dead today: this is vendor DC code tracking
  Linux amdgpu_dm, where `dc_plane_get_status()` **is** called from user-visible
  atomic-check paths. The next driver sync lights these up. Filed as Info.

## Exploit chain

None — unreachable in this tree (no callers). Impact ceiling if a future caller
appears without modeset locks: kernel UAF read / NULL deref (panic/DoS class).

## Fix validation

Not performed — Info-severity hardening finding; Phase V fix validation is
skipped per the reviewer contract. The recommended fix is in README.md /
`fix.diff`-form below (authored against the read-only `sys/` tree, never applied):

```diff
--- a/sys/dev/drm/amd/display/dc/core/dc_surface.c
+++ b/sys/dev/drm/amd/display/dc/core/dc_surface.c
@@ -112,10 +112,14 @@ const struct dc_plane_status *dc_plane_get_status(
 	plane_status = &plane_state->status;
 	core_dc = plane_state->ctx->dc;
 
+	if (core_dc->res_pool == NULL)
+		return NULL;
 	if (core_dc->current_state == NULL)
 		return NULL;
 
+	dc_retain_state(core_dc->current_state);
 	for (i = 0; i < core_dc->res_pool->pipe_count; i++) {
 		struct pipe_ctx *pipe_ctx =
 				&core_dc->current_state->res_ctx.pipe_ctx[i];
 
 		if (pipe_ctx->plane_state != plane_state)
 			continue;
 
+		if (core_dc->hwss.update_pending_status == NULL)
+			continue;
 		core_dc->hwss.update_pending_status(pipe_ctx);
 	}
+	dc_release_state(core_dc->current_state);
 
 	return plane_status;
```

(`dc_retain_state`/`dc_release_state` already exist: dc.c:1091/1103.)

## Bottom line

No exploitable defect in the shipped tree; one Info hardening note on a dead
public API whose upstream callers will arrive with the next vendor sync.

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

(No fix.diff for this item: documented recommendation only - see Fix above.)
