# DF-5034 — i2caux_dce110 `acquire_i2c_hw_engine`: missing lower-bound check on signed `gpio_ddc_line` allows negative-index array read (dce110 twin of DF-2089)

- File: `sys/dev/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c`
- Line: 98 (`if (line < GPIO_DDC_LINE_COUNT)`)
- Severity: Info (hardening). Confidence: certain (code shape), no demonstrated impact.

## What the code does

`acquire_i2c_hw_engine()` derives the engine-slot index from the DDC object:

```c
if (ddc->hw_info.hw_supported) {
        enum gpio_ddc_line line = dal_ddc_get_line(ddc);
        if (line < GPIO_DDC_LINE_COUNT)                       /* only UPPER bound */
                engine = i2caux->i2c_hw_engines[line];        /* i2caux_dce110.c:98-99 */
}
```

`enum gpio_ddc_line` is SIGNED and its first member is
`GPIO_DDC_LINE_UNKNOWN = (-1)` (`sys/dev/drm/amd/display/include/gpio_types.h:206-220`).
The enum API explicitly ships `GPIO_DDC_LINE_MIN`/`GPIO_DDC_LINE_MAX` for
bounds checks, but this site (and its dce80 twin, DF-2089) only compares
against `GPIO_DDC_LINE_COUNT`. A `-1` passes `(-1 < 8)` and reads
`i2c_hw_engines[-1]`.

## Why it is benign today (and why it is filed anyway)

`struct i2caux` layout (`i2caux.h:55-98`): `ctx`, `funcs`,
`i2c_sw_engines[8]`, `i2c_hw_engines[8]`, `aux_engines[8]`, …
so `i2c_hw_engines[-1]` aliases `i2c_sw_engines[7]`. In the whole dce110
constructor family (`dce100/dce110/dce112/dce120/dcn10` all funnel through
`dal_i2caux_dce110_construct`, i2caux_dce110.c:202-295) the SW-engine branch
is dead (`use_i2c_sw_engine = false`, i2caux_dce110.c:213) and only line
slots DDC1..DDC6 (indices 0..5) are ever written, so `i2c_sw_engines[7]`
stays NULL and the function returns NULL. No OOB past the struct occurs.

Reachability of `line == -1` additionally requires a ddc whose
`hw_info.hw_supported` is true (a VBIOS-derived flag: `i2c_hw_assist`,
`core/dc_link_ddc.c:270`) while `dal_ddc_get_line()` — which returns
`dal_gpio_get_enum(ddc->pin_data)` (`gpio/gpio_service.c:566-570`), an enum
produced by the register-offset→id translation (`gpio_service.c:418`) —
yields UNKNOWN. No such path was found on a well-formed ASIC/BIOS; a crafted
VBIOS on real AMD hardware is the only conceivable trigger, and it still
lands on NULL. Filed as the dce110 bookkeeping twin of DF-2089 (dce80,
identical shape, Info) so the family record is complete and the next
refactor does not have to re-derive this.

## Fix (one line)

```diff
-		if (line < GPIO_DDC_LINE_COUNT)
+		if (line >= GPIO_DDC_LINE_MIN && line < GPIO_DDC_LINE_COUNT)
 			engine = i2caux->i2c_hw_engines[line];
```

## Reproduce / evidence

No PoC run: the finding is an Info hardening note gated on AMD display
hardware (DCE11 ASIC) that the QEMU test guest does not have
(guest has only a virtio GPU; no radeon/amdgpu KLD). Run
`./analysis.sh` to print the cited source lines. See VERDICT.md.
