# VERDICT — DF-4912

**status: untested** — deliberately: the vulnerable code is not part of any
kernel build, so there is no kernel artifact to test. **reproduced: 0**
(kernel path) / semantic off-by-one **demonstrated** in userspace
(`run.log`). **impact: none** (dead code + self-clobbering write). Severity
**Info**.

## Fact 1 — the module is dead code (certain)

- `sys/dev/drm/amd/amdgpu/Makefile:49-51` compiles `display/modules/freesync`,
  `display/modules/color`, `display/modules/info_packet` — **stats is absent**
  (confirmed both in the audit tree and in the guest's `/usr/src`, run.log).
- Repo-wide search (`rg -rn "modules/stats" sys/` and `rg mod_stats_*`): zero
  hits outside `modules/stats/stats.c` itself and `modules/inc/mod_stats.h`.
  No allocation, no call, no linkage. `sys/conf/files` has no stats entry.

## Fact 2 — latent off-by-one OOB write (certain, demonstrated)

`mod_stats_update_event` (`stats.c:296-326`):

```c
copy_length = length;                                  /* :316 */
if (length > MOD_STATS_EVENT_STRING_MAX)               /* :317 */
	copy_length = MOD_STATS_EVENT_STRING_MAX;
memcpy(&events[index].event_string, event_string, copy_length);
events[index].event_string[copy_length - 1] = '\0';    /* :321 — OOB at [-1] when length==0 */
```

`length == 0` → `copy_length - 1` wraps to `0xFFFFFFFF` (unsigned) → the
compiler itself proves it: building the exact clone with gcc 8.3 on the guest
emits `warning: array subscript 4294967295 is above array bounds of
'char[512]' [-Warray-bounds]` (run.log). At runtime the write lands at
`event_string[-1]` = offset 3 of `struct stats_event_cache` = the MSB of
`entry_id` on little-endian — and `stats.c:323` then assigns `entry_id`
wholesale, clobbering the OOB byte. Net memory effect: zero. No caller exists
to pass `length == 0` regardless.

## Other stats.c candidates checked and killed

- `mod_stats_reset_data` (`:283-287`): `memset(core_stats->time, 0, sizeof * 0)`
  when disabled — `memset(NULL, 0, 0)`, benign in the kernel; entries/event
  bounds in all four update functions are correctly guarded
  (`:310`, `:340`, `:385`, `:433`); `v_sync_time_in_us[num_vsyncs]` bounded by
  the `< MOD_STATS_NUM_VSYNCS` check (`:392`); `time[index - 1]` safe because
  index starts at 1 (`:166`); concurrent update threads can at worst
  double-increment the index past `entries` but every write is re-guarded, so
  no OOB; `mod_stats_dump` guards both array walks (`:235`, `:239`).
- `kcalloc(entries ≤ 0x01000000, ~120B)` ≈ 2 GB max on crafted persistent
  data — allocation failure is handled (`:148`, `:156`), and
  `dm_read_persistent_data` has no live backing store for this key on DF.

## Fix

Delete the module (matches upstream direction; it was never wired into the
amdgpu driver) or apply `fix.diff` (guard `length == 0`, clamp to
`MOD_STATS_EVENT_STRING_MAX - 1`).

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