# DF-4206 — vlv_dsi_init !fixed_mode error path kfrees a *registered* connector → dangling entry in mode_config list/IDR

File: `sys/dev/drm/i915/vlv_dsi.c` (pass 2)
Severity: Low | Confidence: certain | CWE-416 (use after free) with CWE-401 (leak of connector->name / probed modes)

## Build / Run

No build or run: Phase V skipped per contract (Low severity — the trigger is
a drm_mode_duplicate allocation failure, i.e. kernel OOM at exactly this
point in DSI init; the audit guest has no Intel GPU). The defect is provable
from source.

## The bug (path:line)

Execution order in `vlv_dsi_init()`:

1. vlv_dsi.c:1839 `drm_connector_init(dev, connector, ...)` — registers the
   connector in the mode-object IDR (`__drm_mode_object_add`,
   drm_connector.c:208) and links it into
   `dev->mode_config.connector_list` (drm_connector.c:258).
2. vlv_dsi.c:1842 `drm_connector_helper_add`.
3. vlv_dsi.c:1848 `intel_connector_attach_encoder`.
4. vlv_dsi.c:1851 `intel_dsi_vbt_get_modes()` — duplicates
   `vbt.lfp_lvds_vbt_mode` (non-NULL is guaranteed on this path because
   `intel_dsi_vbt_init()` already dereferenced it, intel_dsi_vbt.c:544) and
   adds it as PREFERRED.
5. vlv_dsi.c:1852-1857 loop picks the PREFERRED mode into `fixed_mode` via a
   **second** `drm_mode_duplicate`.
6. vlv_dsi.c:1860-1863 — if `fixed_mode == NULL` (either duplicate failed:
   kernel OOM), `goto err`.
7. err label vlv_dsi.c:1875-1878: `drm_encoder_cleanup(&intel_encoder->base);
   kfree(intel_dsi); kfree(intel_connector);` — **`drm_connector_cleanup()` is
   never called.**

Consequences after step 7 (i915 driver init continues — a failed output does
not abort the driver):

* `dev->mode_config.connector_list` still contains `&connector->head` which
  now points into freed memory (`connector` is embedded in the freed
  `intel_connector`). Every walker dereferences freed memory:
  - `DRM_IOCTL_MODE_GETRESOURCES` (unprivileged) builds the connector id
    list from that list;
  - `DRM_IOCTL_MODE_GETCONNECTOR` with the stale id resolves via
    `drm_mode_object_find()` → the IDR still holds the freed connector's id
    (only `drm_connector_cleanup` → `drm_mode_object_unregister` removes it,
    drm_connector.c:405) → returns the freed pointer → UAF read/write;
  - `drm_mode_config_cleanup()` at unload does `drm_connector_put()` on each
    list entry → refcount write to freed memory → UAF write, guaranteed
    crash on unload.
* `connector->name` (kasprintf, drm_connector.c:236-239) and any probed
  modes leak ( drm_connector_cleanup would have freed both,
  drm_connector.c:392-396,406).

## Trigger

`drm_mode_duplicate` → `drm_mode_create` → kzalloc failure: i.e. kernel
memory exhaustion during DSI connector init (step 4 or step 5). All other
`goto err` sites (:1811 host init, :1818 vbt init) are *before*
`drm_connector_init` and are correctly handled.

## Distinct from known findings

* DF-1446 covers the leak of `dsi_hosts[port]` (host + mipi_dsi_device) on
  the same `err:` label and on encoder teardown. This finding is a
  *different object class* (the drm_connector) and a *different impact*
  (use-after-free of globally-linked state vs. a pure allocation leak).

## Fix

Dedicated `err_connector` label calling `drm_connector_cleanup(connector)`
before the encoder cleanup — see `fix.diff`. `drm_connector_cleanup`
(drm_connector.c:375-422) removes probed modes, unregisters the IDR object,
frees the name, and `list_del`s from `connector_list`, so the dangling state
is fully unwound.

## Threat model / impact ceiling

Trigger is OOM-gated (not attacker-chosen timing without memory-pressure
influence). After the trigger, ordinary unprivileged DRM ioctls walk/use the
freed connector — a genuine UAF surface — but the object is a small
driver-owned struct; practical exploitation is constrained. Treated as Low.
