# DF-4445 — uninitialized `val` written into DDC/CD router mux registers when the router i2c read fails

## Verdict

**Status: untested** (Low severity — verification skipped per audit contract;
additionally no radeon hardware exists on the audit guest). Static analysis:
certain.

## Line-cited trace

1. `sys/dev/drm/radeon/radeon_i2c.c:1110` — `u8 val;` **uninitialized** (same
   in `radeon_router_select_cd_port` at `:1138`).
2. `radeon_i2c_get_byte(router_bus, i2c_addr, 0x3, &val)`
   (`radeon_i2c.c:1118-1120`): its only write to `*val` is inside
   `if (i2c_transfer(...) == 2)` (`radeon_i2c.c:1077-1079`). On transfer
   failure — NAK from a missing/broken router chip — `val` keeps the previous
   stack contents. The failure branch also leaks that byte to the log:
   `DRM_DEBUG("i2c 0x%02x 0x%02x read failed\n", addr, *val)`
   (`radeon_i2c.c:1081-1083`).
3. `radeon_i2c.c:1121` — `val &= ~ddc_mux_control_pin;` — garbage survives in
   every bit not owned by `control_pin`.
4. `radeon_i2c.c:1122-1124` — the garbage-derived byte is **written back to
   router register 0x3**; the same pattern repeats for register 0x1 at
   `:1125-1132` (`val |= ddc_mux_state` only constrains the mux bits).

Consequences: unpredictable corruption of the external i2c router's config
registers (other bits of 0x3/0x1 control unrelated mux functions on those
chips — display routing malfunctions), plus a one-byte kernel-stack disclosure
into the debug log when `drm.debug` is enabled (log readable per sysctl
policy).

Reachability: `radeon_ddc_probe()` calls `radeon_router_select_ddc_port()`
(`radeon_i2c.c:63-64`) on every connector probe of a router-equipped
connector (HPD poll / modeset). Trigger requires the router read to fail —
i.e. a router chip that NAKs (common with KVM tricks/DP-mST docks/hardware
faults) — while the subsequent `put_byte` of garbage goes out on the same
dead bus (no effect on DF's stubbed bit-bang shim; real effect on
working-hardware configurations, incl. upstream Linux which has the identical
code).

Divergence note: this is *not* DF-specific code — verified byte-for-byte
against upstream's radeon_i2c.c (the DF file's only functional divergences
are the `lockinit`/`i2c_add_adapter` shim lines at `:932` and `:970-973`).
Filed because it is a real, fixable defect in the audited file
(CWE-457, upstreamable).

## Fix

`u8 val = 0;` in both functions (fix.diff). The stronger fix — make
`radeon_router_select_*` bail when the read fails — needs an API change to
`radeon_i2c_get_byte` (return int) and can be proposed upstream separately.

## Why not runtime-verified

Low severity (contract: skip); no radeon hardware on the audit guest
(virtio-gpu 0x1234:1111 only — see DF-4444/env.txt for the PCI inventory).

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