# DF-3656 — Error-path UAF: registered i2c adapter / connector / encoder / planes freed while still in core lists

**File:** `sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c`
**Lines:** 4080-4136 (`amdgpu_dm_connector_init` `out_free`), 1937-1942 (`amdgpu_dm_initialize_drm_device` `fail`)
**Severity:** Low (requires OOM / debugfs failure at driver init — fault-injection class) · **CWE-416** · confidence: certain

## What

Two broken unwinds leave dangling pointers in DRM/i2c core lists:

1. **`amdgpu_dm_connector_init()`** registers the DDC i2c adapter
   (`i2c_add_adapter(&i2c->base)`, amdgpu_dm.c:4080), then continues
   (`drm_connector_init` 4089, `connector_debugfs_init` 4120). On any later
   failure it runs `out_free:` which does `kfree(i2c)` (4133) **without
   `i2c_del_adapter()`**, and returns an error. If `drm_connector_init` had
   already succeeded (debugfs failure case), the connector is also still
   registered in `dev->mode_config.connector_list` while the caller frees it.

2. **`amdgpu_dm_initialize_drm_device()`'s `fail:` path (1937-1942)** — reached
   e.g. from `dce110_register_irq_handlers()` failure (1922) *after* all
   connectors/encoders were fully created and registered — unconditionally
   does `kfree(aencoder); kfree(aconnector);` for the last-allocated pair and
   `kfree(mode_info->planes[i])` for all planes, **none** of which are
   de-registered. Every one of those objects is still referenced by
   `dev->mode_config.{connector,encoder,plane}_list`, and `aconnector` is
   still the `link->priv` HPD-cookie and the `mst_mgr` owner.

The error path then runs `amdgpu_dm_fini()` → `amdgpu_dm_destroy_drm_device()`
→ `drm_mode_config_cleanup()` (1947) which iterates those very lists and
calls cleanup on the freed memory → **use-after-free**. Likewise any later
i2c transaction on the DDC bus dereferences the freed adapter (`i2c_get_adapdata`).

## Trigger

Allocation failure or debugfs failure during display-manager init
(module load / boot / GPU reset re-init). Not attacker-timing-controllable
without fault injection — hence Low severity — but it is exactly the
error-path lifetime class the pass-2 audit targets (contrast DF-1153, which
covers the *reset functions*, not this init unwind).

## Reproduction

Not runnable on the audit guest (virtio-only, no AMD GPU — env.txt);
source-level certainty. No harness is meaningful for an OOM-timing UAF; the
VERDICT.md contains the full ownership trace.

## Contents

`env.txt` · `VERDICT.md` · `fix.diff` · `manifest.json` · `verdict.json` · `README.md`
