# DF-3600 — sq_edc_source_names[] indexed by unbounded 3-bit HW field (OOB rodata read -> %s)

## What

`gfx_v8_0_parse_sq_irq()` reads the EDC source from hardware:

```c
	gfx_v8_0.c:6811
	sq_edc_source = REG_GET_FIELD(RREG32(mmSQ_EDC_INFO), SQ_EDC_INFO, SOURCE);
```

`SQ_EDC_INFO__SOURCE_MASK = 0x1c0` (3-bit field,
sys/dev/drm/amd/include/asic_reg/gca/gfx_8_0_sh_mask.h:14083) → values 0..7,
but the lookup table has only **7** entries:

```c
	gfx_v8_0.c:710-718
	static const char * const sq_edc_source_names[] = {
		"SQ_EDC_INFO_SOURCE_INVALID", ... "SQ_EDC_INFO_SOURCE_TA",   /* 7 entries */
	};
```

and the printf at :6831 does
`sq_edc_source_names[sq_edc_source]` with no bound check. When the field
reads 7 (reserved encoding — real on parts where the EDC source latches
garbage, e.g. uncorrected-but-unmapped EDC events), index 7 reads one
pointer past the array in kernel rodata and `%s` walks it:

* if the adjacent qword is not a valid string pointer → kernel page fault
  from the *log formatter* while handling an SQ interrupt (panic from what
  is supposed to be an error-reporting path), or
* if it happens to be a valid pointer, it prints unrelated kernel rodata
  to dmesg (minor info disclosure of static kernel content).

Path: `gfx_v8_0_sq_irq` :6848-6867 → `gfx_v8_0_parse_sq_irq` :6769 (both
ISR and work-queue contexts; `in_task()` only gates whether the SQ_EDC_INFO
register is read — in ISR context sq_edc_source stays -1 and is safe; the
unbounded index is the work-queue/task path).

## Trigger / severity

Requires the GPU to raise an SQ interrupt with EDC/ECC encoding whose
SQ_EDC_INFO.SOURCE latches 7 — a hardware error-event path (not directly
commandable by unprivileged GPU users), so: **Low**, defense-in-depth with
a panic side effect.

## Reproduce

Source assertion (guest is virtio-only, no AMD HW):

```
./run.sh
```
prints the 7-entry array, the 3-bit mask, and the unbounded index site.

## Fix

`fix.diff`: bound the index with `ARRAY_SIZE(sq_edc_source_names)`.
