# DF-4778 — VERDICT

**UNTESTED at runtime (no AMD GPU on the audit guest); code defect CONFIRMED
by line-level trace. Not a memory-safety violation — in-bounds data
corruption of DisplayPort AUX read data.**

## Root cause (line-level)

`sys/dev/drm/amd/display/dc/i2caux/aux_engine.c`:

- `read_command()` (aux_engine.c:245-307) loops a native/I2C-over-AUX read
  across partial ACKs. Each iteration:
  - `memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length)` (line 284)
  - `ctx.request.data = ctx.buffer + ctx->offset;` (line 286)
- `process_read_reply()` (aux_engine.c:119-181) on `AUX_ACK` with
  `returned_byte < current_read_length` advances
  `ctx->offset += ctx->returned_byte` (line 135) and continues.
- `process_read_request()` (aux_engine.c:183-243) then sets
  `ctx->reply.length = ctx->returned_byte; ctx->reply.data = ctx->buffer;`
  (lines 204-205) — **the base, not `ctx->buffer + ctx->offset`**.
- The concrete engine copies the reply payload into `reply->data`:
  `i2caux/dce110/aux_engine_dce110.c:300-325 read_channel_reply` reads the
  AUX_SW_DATA registers into `buffer[i]` for `i < bytes_replied`, bounded by
  `size == reply->length`.

So on iteration 2+ of a continued read, the freshly received chunk lands at
`buffer[0..returned)` while the protocol state expects it at
`buffer[offset..offset+returned)`. The bound check
(`returned_byte > current_read_length` at line 196, plus the invariant
`offset + current_read_length == original length`) keeps every copy inside
the caller's buffer — **no OOB write** — but the assembled DPCD/EDID data is
wrong (chunk #2 overwrites chunk #1's tail region start).

Twin: `sys/dev/drm/amd/display/dc/dce/dce_aux.c:501-502` has the identical
`ctx->reply.data = ctx->buffer;` in its own `process_read_request`
(dce_aux.c:486-506), reached from `read_command` (dce_aux.c:547-600) — the
whole DCN+ path shares the bug.

## Reachability

* Trigger condition: a DP sink that ACKs a read with fewer bytes than
  requested (`returned_byte < current_read_length`). This is a legal and
  real-world sink behavior — it is precisely the case the retry logic at
  aux_engine.c:132-144 exists to handle.
* Impact surface: native DPCD reads (link training, capability probes) and
  I2C-over-AUX reads (EDID) on DCE80–DCE120 ASICs via
  `dal_aux_engine_submit_request()` (aux_engine.c:560-591) from
  `dal_i2caux_submit_aux_command()` (i2caux/i2caux.c:196-267) /
  `dc_link_ddc.c:598`. Corrupted link-training/EDID data → unstable or
  misconfigured display links, wrong modes. No kernel memory unsafety.

## Why not run on the guest

The audit guest (QEMU/KVM, no AMD graphics device) cannot instantiate any
DCE AUX engine: `amdgpu`/DC is not compiled into the booted kernel and no
AMD hardware exists behind the QEMU PCI bus. The finding is therefore filed
as runtime-UNTESTED with code-level certainty (the defect and its bound-
safety were fully traced; see kernel_refs).

## Severity reasoning

Low: in-bounds data corruption inside a display configuration path; requires
specific (legal) sink behavior; no confidentiality/integrity impact on kernel
memory; worst realistic outcome is display malfunction persisted until the
next successful AUX read.

## Fix

`fix.diff`: point `reply.data` at `buffer + offset` in both engines
(aux_engine.c:205, dce_aux.c:502). Compile-validated only (no HW to run).

## kernel_refs
- sys/dev/drm/amd/display/dc/i2caux/aux_engine.c:132-135 (offset advance)
- sys/dev/drm/amd/display/dc/i2caux/aux_engine.c:196-208 (reply.data = buffer)
- sys/dev/drm/amd/display/dc/i2caux/aux_engine.c:283-296 (request at offset)
- sys/dev/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c:281-331 (copy)
- sys/dev/drm/amd/display/dc/dce/dce_aux.c:493-506 (twin)

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