# DF-5034 — VERDICT

**status: untested** (PoC intentionally not run — Info hardening finding,
hardware-gated; no AMD ASIC in the test guest)
**reproduced: 0, impact: none, confidence: certain (about the code shape)**

## Narrative

Pass-2 audit of `sys/dev/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c`
found that `acquire_i2c_hw_engine()` validates the DDC-line index only
against the UPPER bound:

- `i2caux_dce110.c:95-100`
  `if (ddc->hw_info.hw_supported) { enum gpio_ddc_line line = dal_ddc_get_line(ddc); if (line < GPIO_DDC_LINE_COUNT) engine = i2caux->i2c_hw_engines[line]; }`

`enum gpio_ddc_line` is signed with `GPIO_DDC_LINE_UNKNOWN = (-1)`
(`include/gpio_types.h:207`), so a -1 passes the check and indexes the array
one element low.

Why this is NOT a demonstrable memory-safety bug here (traced, not guessed):

1. `i2c_hw_engines[-1]` aliases `i2c_sw_engines[7]` per the struct layout in
   `i2caux/i2caux.h:67-71` (sw array immediately precedes hw array).
2. `i2c_sw_engines[7]` is never assigned in the dce110 constructor family:
   `use_i2c_sw_engine` is hardcoded false (`i2caux_dce110.c:213`), and even
   the dce80 variant only fills hw lines DDC1..DDC6 = indices 0..5
   (`i2caux_dce80.c:222-245`, loop bounded by `ARRAY_SIZE(hw_ddc_lines)`).
   The slot is therefore NULL and the function returns NULL — benign.
3. Reaching line == -1 at all needs a `hw_supported` ddc (flag comes from
   VBIOS `i2c_hw_assist`, `core/dc_link_ddc.c:270`) whose gpio pin enum
   (`dal_gpio_get_enum` via the offset→id translation,
   `gpio/gpio_service.c:418,566-570`) evaluates to UNKNOWN. No in-tree
   creator does that; it would take a crafted VBIOS on real DCE11 hardware.

This is the dce110 twin of already-filed DF-2089 (dce80,
`i2caux_dce80.c:122-127`, Info). Filed for family completeness: the enum
provides `GPIO_DDC_LINE_MIN` (gpio_types.h:218) precisely for this check,
and the current "benign by struct-layout accident" property is fragile
under any future struct/layout or engine-population change.

## Exploit chain

None. No attacker-controllable path to a non-NULL outcome was found; worst
case remains a NULL deref-free early return.

## Why untested (not `not_reproduced`)

The test guest (DragonFly 6.5-DEVELOPMENT, QEMU/KVM) has no AMD display
controller (`pciconf` shows only virtio GPU 1af4:1100) and no drm KLD
loaded; the DCE11 i2caux constructor/acquire path cannot execute there.
The finding is Info hardening; per the audit contract, Low/Info hardening
findings do not get a PoC phase. `analysis.sh` mechanically prints every
cited line for reviewers.

## Fix validation

`fix.diff` adds the `GPIO_DDC_LINE_MIN` guard. Not built/booted (nothing to
observe without DCE11 hardware; the change is a pure index guard).

kernel_refs:
- sys/dev/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c:92-100
- sys/dev/drm/amd/display/include/gpio_types.h:206-220
- sys/dev/drm/amd/display/dc/gpio/gpio_service.c:566-570
- sys/dev/drm/amd/display/dc/i2caux/i2caux.h:55-98
- twin: sys/dev/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.c:122-127 (DF-2089)

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