# DF-3913 — `intel_sdvo_connector_state` leaked on `intel_sdvo_connector_init()` failure (all four SDVO connector init paths)

File: `sys/dev/drm/i915/intel_sdvo.c` (pass 2, GLM 5.3 re-audit)

## What the bug is

`intel_sdvo_connector_alloc()` (intel_sdvo.c:2472-2491) allocates **two** objects:

1. `struct intel_sdvo_connector` (kzalloc, line 2477)
2. `struct intel_sdvo_connector_state` (kzalloc, line 2481), immediately
   installed as `connector->state` via
   `__drm_atomic_helper_connector_reset()` (line 2487).

If `intel_sdvo_connector_init()` (which calls `drm_connector_init()`) fails,
all four per-type init functions free **only** the connector and leak the
state object:

- `intel_sdvo_dvi_init()`      — intel_sdvo.c:2541-2544
- `intel_sdvo_tv_init()`       — intel_sdvo.c:2574-2577
- `intel_sdvo_analog_init()`   — intel_sdvo.c:2620-2623
- `intel_sdvo_lvds_init()`     — intel_sdvo.c:2656-2659

```c
	if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
		kfree(intel_sdvo_connector);        /* state (line 2481) leaks */
		return false;
	}
```

The leaked allocation is `sizeof(struct intel_sdvo_connector_state)` (~120
bytes on amd64). The state pointer is reachable only through the freed
connector, so it is unrecoverable. No UAF: the state is never touched again.

## Trigger

Requires Intel SDVO hardware (i915G–Ironlake era, SDVOB/SDVOC port with a
responding SDVO device on the GMBUS) **and** a failure of
`drm_connector_init()` at that point: realistic causes are `kzalloc` failure
inside the core, connector-index IDA exhaustion (`ida_simple_get(...,0,32)`
— at most 32 connectors per device), or sysfs/kobject registration failure.
Probe-time only; not user-triggerable at runtime.

## Why it is Low

- One-shot ~120-byte leak per failed probe, error path only.
- No use-after-free, no info leak, no attacker-controlled size.
- Upstream-inherited: identical code in Linux (through the file's removal
  in 5.20); worth fixing in DragonFly (and noting upstream) but not
  exploitable.

## Reproduce on real hardware (fault injection)

Apply `faultinject.diff` to `/usr/src/sys/dev/drm/i915/intel_sdvo.c` on an
Intel-SDVO-equipped DragonFly box, rebuild the kernel/module, boot:

    dmesg | grep DF3913

Expected:

    DF3913: simulating drm_connector_init failure for DVI device 0
    DF3913: LEAKED intel_sdvo_connector_state (152 bytes) at ...   [buggy path]

With `fix.diff` also applied, the second line becomes:

    DF3913: freed failing connector state ...                      [fixed path]

`sizeof(struct intel_sdvo_connector_state)` on the audited tree is 152
bytes (verify with the printout; struct layout depends on config).

## On this audit guest (QEMU)

Not runnable: the guest has no Intel GPU (only QEMU Bochs VGA,
chip 0x1234:1111 — see `env.txt`/`run.log`), so `i915` never attaches and
`intel_sdvo_init()` cannot execute. `probe.sh` records that gate.
`fix.diff` is `git apply --check`-clean against the pristine tree.

## Fix

`fix.diff` (git-apply-able, never applied to the read-only `sys/` tree):
free the installed state before freeing the connector at all four sites,
using the same helper the driver already registers as
`.atomic_destroy_state` (intel_sdvo.c:2234) —
`drm_atomic_helper_connector_destroy_state()` (drm_atomic_helper.c:3930),
which is a `kfree(state)` for a freshly-kzalloc'd, never-exposed state.
