# DF-4372 VERDICT — unchecked fan/ext-header offsets in r600_parse_extended_power_table

## Bottom line

**Certain by static proof; PoC phase not executed (Low severity, and the
audit VM has no radeon GPU / no /dev/dri).** Two container offsets from the
VBIOS are dereferenced with no zero/bounds validation, distinct from the
count/index walks already covered by DF-1566.

## Detail

* `r600_dpm.c:893-895` — `fan_info` derived from `usFanTableOffset` (u16)
  and dereferenced at :896-915, including the *versioned* union reads
  (`fan2.usTMax` at :904, `fan3.ucFanControlMode`/`usFanPWMMax`/
  `usFanOutputSensitivity` at :909-914) whose format byte
  (`ucFanTableFormat`) itself comes from the same unvalidated location.
* `r600_dpm.c:1070-1073` — `ext_hdr` derived from
  `usExtendendedHeaderOffset` with **no check whatsoever**: offset 0 reads
  the PowerPlayInfo header as the extended header (in-bounds but wrong
  object — all derived sub-table offsets become header garbage); an offset
  beyond the image reads off the end of the ≤256 KiB `rdev->bios` kmalloc
  buffer. Six downstream blocks (`:1074-1293`) then chase the garbage
  offsets; their internal count/index behavior is DF-1566 (not re-reported).
* `atom_parse_data_header()` (`atom.c`) already returns an unbounded
  `data_offset` (noted in DF-1566); the container-offset checks added by
  this finding's fix close the remaining provenance holes inside this
  parser.

## Threat model / impact

Requires control of the GPU VBIOS (physically modified card, option-ROM
injection, or ACPI VFCT image at `radeon_bios.c:717`). Impact: OOB kernel
heap reads (values copied into `rdev->pm.dpm.fan.*` and dyn_state tables,
potentially observable via hwmon/debugfs on some setups) and mis-programmed
fan/voltage behavior. Consistent with DF-1566's Medium rating for the
stronger count-walk variant; the offset-provenance half is narrower → **Low**.

## Verification on the audit VM

Not attempted at runtime: no radeon hardware (QEMU virtio VGA only), no
/dev/dri, VBIOS not attacker-controllable in this VM. Status `untested`,
impact `none` on this guest; the code defect itself is certain from
inspection.

## Fix validation

`fix.diff` (3 files: radeon.h adds `bios_size`; radeon_bios.c records it at
all five allocation sites :68/:98/:153/:269/:717; r600_dpm.c validates both
offsets and gates the six ext-table conditions on `ext_hdr_ok`). Verified
`patch -p1 --dry-run` → APPLIES_CLEAN on scratch copies. Runtime validation
impossible on this VM → `fix_status: not_testable`.

## kernel_refs

* sys/dev/drm/radeon/r600_dpm.c:893-915 (fan table walk)
* sys/dev/drm/radeon/r600_dpm.c:1070-1073 (ext_hdr deref, no checks)
* sys/dev/drm/radeon/r600_dpm.c:1074-1293 (six ext-table consumers)
* sys/dev/drm/radeon/radeon_bios.c:68,98,153,269,717 (bios allocation, ≤256 KiB)
* sys/dev/drm/radeon/radeon.h:2333 (*bios field)

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