# DF-4417 — i915 `wal_add()` leaks the previous W/A list buffer on every growth; lists are never torn down

## Verdict (short)

**Status: untested** — dormant leak; no in-tree platform list exceeds 16
entries, so the growth path (`IS_ALIGNED(wal->count, grow)` with
`wal->list != NULL`) never executes on current hardware, and the QEMU guest
has no Intel GPU. Filed as Info-severity hardening/correctness.

## Root cause (path:line)

`sys/dev/drm/i915/intel_workarounds.c:604-618` (`wal_add`):

```c
	if (IS_ALIGNED(wal->count, grow)) { /* Either uninitialized or full. */
		list = kmalloc_array(ALIGN(wal->count + 1, grow), sizeof(*wa), GFP_KERNEL);
		...
		if (wal->list)
			memcpy(list, wal->list, sizeof(*wa) * wal->count);

		wal->list = list;      /* <-- old kmalloc'd buffer leaked */
	}
```

When `wal->count` hits 16/32/…, a new buffer is allocated and the old pointer
is overwritten without `kfree()`. Additionally there is no teardown anywhere:
`rg "kfree.*(wa_list)"` over `sys/dev/drm/i915/*.c` finds nothing, so
`gt_wa_list` and per-engine `wa_list` allocations (one per engine) live until
the drm device is destroyed — and since DRM is compiled into the kernel here,
a GPU hot-unplug/re-attach cycle leaks each list once per cycle.

## Reachability today

Largest lists in this file (counted): ICL GT list = 9 entries, ICL RCS engine
list = 8, Gen9 RCS = 6 — all < 16, so only the initial allocation (no leak)
runs. The leak becomes live the day a platform table grows past 16 entries.

## Fix

`findings/poc/DF-4417/fix.diff` — free the old buffer after the copy.
(A full fix would also add an `intel_wa_list_free()` on driver teardown;
minimal growth-leak fix included here.)

## Reproduce

Not reproducible in this environment (needs gen8+ Intel GPU, plus a W/A table
>16 entries to take the growth path). Static proof only: the overwritten
pointer is unreferenced after `wal->list = list;` — no other alias exists.

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