# DF-3856 — VERDICT

## Status: `inconclusive` (UB proven by harness on audit toolchain; kernel write sinks hardware-gated, no radeon GPU on guest)

## Full narrative

### The bug family

Four parser sites in `radeon_combios.c` use a raw BIOS byte as a shift
count for 32-bit values. C99 6.5.7p3: shifting a 32-bit value by ≥ 32 (or by
a negative count) is undefined behavior. Nothing bounds these bytes:

1. `combios_parse_pll_table()` case 1 — `sys/dev/drm/radeon/radeon_combios.c:3102-3113`:
   ```c
   shift = RBIOS8(offset) * 8;            /* 0..2040 */
   offset++;
   and_mask = RBIOS8(offset) << shift;    /* UB for byte >= 4 */
   and_mask |= ~(0xff << shift);          /* UB */
   or_mask  = RBIOS8(offset) << shift;    /* UB */
   tmp = RREG32_PLL(addr); tmp &= and_mask; tmp |= or_mask;
   WREG32_PLL(addr, tmp);                 /* PLL register rewritten */
   ```
   Executed by `radeon_combios_asic_init()` at driver init/resume from the
   PLL INIT / DYN CLK tables (`radeon_combios.c:3329-3332, 3407-3410`).

2. voltage gpio mask — `radeon_combios.c:2751-2752, 2759-2760`:
   `mask = (1 << tmp)` with `tmp = RBIOS8(...)`: consumed by the
   `r100_pm_misc()` RMW (see DF-3852).

3. i2c gpiopad masks — `radeon_combios.c:654-658`:
   `combios_setup_i2c_bus(rdev, DDC_MONID, (1 << clk), (1 << data))` — the
   masks become `i2c.mask_*_mask` written to GPIO registers during DDC
   transfers.

4. thermal-controller gpio bits — `radeon_combios.c:2669-2687`:
   `combios_setup_i2c_bus(rdev, gpio, 1 << clk_bit, 1 << data_bit)`.

### Observed behaviour (audit toolchain: DragonFly cc 8.3, x86-64)

`harness.c` (volatile operands, so no constant folding) shows gcc silently
taking the count mod 32: `shift=32` behaves as `shift=0`, `1<<200` yields
`0x100`. The PLL read-modify-write therefore applies an
`and_mask`/`or_mask` pair built for the *wrong byte lane* — e.g. the sample
shows the intended `~0xff000000`-style mask coming out as `0x0000ffff` —
and writes it to a PLL register. No trap, no warning; other compilers are
entitled to different (or no) results — the guarantee is simply gone.

### Impact (honest)

Wrong PLL/GPIO programming from a crafted (or corrupted) VBIOS: GPU clock
misconfiguration, failed posting, hardware hangs; a force-multiplier for
DF-3852 (mask) rather than an independent memory-safety bug. Low severity.

### Fix

`fix.diff`: pll-table case 1 validates the shift byte (≤3) and skips the
record otherwise (consuming its 2 operand bytes to stay aligned); i2c table
and thermal-controller sites only accept bit numbers < 32. (The voltage-mask
site is covered by DF-3852's fix.diff; the two diffs are independent.)
Apply-verified (`fix_apply.log`); runtime fix validation not possible:
`fix_status = not_testable`.

## kernel_refs
- sys/dev/drm/radeon/radeon_combios.c:3102-3113 (pll table case 1)
- sys/dev/drm/radeon/radeon_combios.c:2751-2760 (voltage masks)
- sys/dev/drm/radeon/radeon_combios.c:650-658 (i2c table masks)
- sys/dev/drm/radeon/radeon_combios.c:2669-2687 (thermal masks)
- sys/dev/drm/radeon/radeon_combios.c:3329-3340, 3407-3410 (executors)

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