dce80_link_encoder_create indexes 7/6/6-entry const register tables with unvalidated VBIOS-derived transmitter/channel/hpd_source (DF-4312 family)
Summary
The three const-table indexings have no range validation. The DC core legitimately produces out-of-range values for all three (UNKNOWN/-1 defaults plus TRAVIS/UNIPHY_G transmitters, DDC_VGA/I2C_PAD channels, HPD_SOURCEID_UNKNOWN). The stored OOB pointers are dereferenced on live AUX/HPD register paths - feeding dm_read/write_reg with register addresses read from adjacent static data. Crafted/malformed VBIOS on a DCE8 GPU: semi-controlled MMIO during link-encoder setup. Guest-built reachability matrix; hardware-gated. Validate-before-index fix (caller handles NULL).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4319 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| df4319.c | β | 5.4 KB | view raw | |
| build.sh | β | 86 B | view raw | |
| run.sh | β | 89 B | view raw | |
| build.log | β | 16 B | view raw | |
| run.log | β | 1.7 KB | view raw | |
| env.txt | β | 891 B | view raw | |
| fix.diff | β | 1.6 KB | view raw | |
| VERDICT.md | β | 3.8 KB | β raw | |
| verdict.json | β | 4.2 KB | view raw |
VERDICT β DF-4319
Status: untested (kernel path) / index-reachability-confirmed (guest) Impact: none on this guest (hardware-gated); code defect certain, exploitation requires crafted VBIOS
Reproduced?
Not against the kernel: the indices come from the GPU's VBIOS object tables
(parsed by the DC BIOS parser) and the audit guest has no AMD GPU at all
(pciconf -l β virtio + generic VGA only; see env.txt).
What was verified:
-
Index reachability proof (
df4319.c) built and run on the guest (DragonFly cc 8.3): prints the full matrix of index values the DC core can legitimately produce for each of the three const tables, marking the OOB ones (seerun.log): transmitter -1/7/8/9 vs 7 entries; channel-1 -1/6/7 vs 6 entries; hpd_source 6 vs 6 entries. -
Line-by-line trace (static, cited): -
dce80_resource.c:661-678βdce80_link_encoder_createindexeslink_enc_regs[enc_init_data->transmitter](7 entries, :249-257),link_enc_aux_regs[enc_init_data->channel - 1](6 entries, :221-228),link_enc_hpd_regs[enc_init_data->hpd_source](6 entries, :235-242) with no validation. - Provenance:core/dc_link.c:1177-1183fills the three fields fromget_ddc_line()(:964-1004),get_hpd_line()(:925-962) andtranslate_encoder_to_transmitter()(:1006-1069). All three helpers have default arms returning UNKNOWN/-1 variants, and map legitimate enum values (DDC_VGA, I2C_PAD, TRAVIS_*, UNIPHY_G) that exceed the dce80 table bounds. Enums live ininclude/grph_object_defs.h:45-94(TRANSMITTER_UNKNOWN = -1; TRAVIS_CRT=7, TRAVIS_LCD=8, UNIPHY_G=9; CHANNEL_ID_DDC_VGA=7, I2C_PAD=8; HPD_SOURCEID_UNKNOWN=6). - Dereference sites of the stored OOB pointers:dce_link_encoder.c:494and:501(AUX_REG(...)βdm_read_reg/dm_write_reg) and:1370/:1384(HPD_REG(DC_HPD_CONTROL)βdm_read_reg/dm_write_reg).
Impact ceiling
Register addresses are read from static data adjacent to the const tables
(&arr[-1] / &arr[6..8] land in neighboring .data/.rodata), then used
for MMIO reads and writes. With a crafted VBIOS (physical access /
VBIOS flash / PCIe device spoofing) this is semi-controlled MMIO corruption;
on stock hardware the realistic outcome for an unknown-encoder/VGA-DDC/no-HPD
connector object is programming garbage register offsets β display engine
misbehavior or hang. No path from an unprivileged local user was found that
influences these values (they never traverse userspace).
Calibration: same family and severity as DF-4312 (dcn10, Low, AV:P).
Exploit chain
Physical/VBIOS prerequisite β none from an unprivileged user. Chain for a
VBIOS-controlling attacker: choose encoder object id/enum_id and DDC/HPD
GPIO lines in the ROM object table β pick which adjacent static data is
read as the register base β MMIO write with partially chosen 32-bit value
at dm_write_reg(ctx, addr, value) during link encoder setup / HPD
enable-disable. Deterministic per-VBIOS, but hardware-bound.
Fix validation
fix.diff adds explicit range checks before the three lookups
(transmitter β [0,6], channel β DDC1..DDC6, hpd β HPD_SOURCEID1..6) and
frees enc110/returns NULL on violation; caller handles NULL gracefully
(dc_link.c:1187-1189 β link_enc_create_fail). Not kernel-tested β no
hardware on the guest.
Conclusion
Missing validation is certain; exploitation is hardware/physical-gated β Low severity, confidence "likely".
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.
Fix verification
not_testablefix.diff adds range checks (transmitterβ[UNIPHY_A,NUTMEG_CRT], channelβ[DDC1,DDC6], hpdβ[SOURCEID1,SOURCEID6]) with kfree(enc110)+NULL return; caller dc_link.c:1187-1189 fails link construction gracefully. Not kernel-testable: guest has no AMD GPU and the trigger values require a crafted VBIOS.
fix.diff; reachability matrix in run.log showing exactly the enum values the new guards reject
Confirmed kernel references
- sys/dev/drm/amd/display/dc/dce80/dce80_resource.c:661
- sys/dev/drm/amd/display/dc/core/dc_link.c:1006
- sys/dev/drm/amd/display/dc/core/dc_link.c:964
- sys/dev/drm/amd/display/dc/core/dc_link.c:925
- sys/dev/drm/amd/display/dc/dce/dce_link_encoder.c:494
- sys/dev/drm/amd/display/dc/dce/dce_link_encoder.c:1370
- sys/dev/drm/amd/display/include/grph_object_defs.h:81
Detail
Exploit chain
Physical/VBIOS-gated: flash crafted VBIOS with encoder object (e.g. EXTERNAL_TRAVIS enum_id=2 β transmitter=8) or connector without HPD GPIO (hpd_source=UNKNOWN=6) on a Sea Islands dGPU β OOB regs pointer into adjacent .data at link creation β dm_write_reg at semi-chosen offsets during encoder setup/HPD handling β display-engine misprogramming or hang (corruption ceiling with fully chosen adjacent data). No unprivileged route: values never traverse userspace.
Evidence (decisive lines)
run.log (guest-built index matrix: -1/7/8/9 vs 7; -1/6/7 vs 6; 6 vs 6, all marked OUT OF BOUNDS); enum defs include/grph_object_defs.h:45-94; provenance dc_link.c:925-1069; deref sites dce_link_encoder.c:494,501,1370,1384; env.txt (no AMD GPU on guest)
PoC changes
No seed PoC (pass-2 checklist applying DF-4312's family to dce80). Authored df4319.c reachability proof with enum values transcribed from grph_object_defs.h and table sizes from dce80_resource.c; fixed an enumerator-name collision (HPD_SOURCEID6) found during the first guest build.
Verified recommended fix
Bounds-validate transmitter/channel/hpd_source against the three table ranges in dce80_link_encoder_create before forming the pointers; free enc110 and return NULL on violation (caller already handles NULL).
Verdict
dce80_link_encoder_create (dce80_resource.c:661-678) indexes three const register tables with unvalidated VBIOS-derived enum values: &link_enc_regs[transmitter] (7 entries) accepts TRANSMITTER_UNKNOWN=-1 (default arm of translate_encoder_to_transmitter, dc_link.c:1006-1069) and TRAVIS_CRT=7/TRAVIS_LCD=8/UNIPHY_G=9; &link_enc_aux_regs[channel-1] (6 entries) accepts channel=CHANNEL_ID_UNKNOWN(0)β-1, DDC_VGA(7)β6, I2C_PAD(8)β7 (get_ddc_line, dc_link.c:964-1004); &link_enc_hpd_regs[hpd_source] (6 entries) accepts HPD_SOURCEID_UNKNOWN=6 (get_hpd_line default, dc_link.c:925-962). The stored OOB pointers are dereferenced on live paths (AUX_REG at dce_link_encoder.c:494,501; HPD_REG at :1370,1384 β dm_read_reg/dm_write_reg), programming register addresses read from adjacent static data. Same defect family as DF-4312 (dcn10). Kernel-path reproduction untested: guest has no AMD GPU and the indices originate in the GPU ROM, so no local user can influence them; exploitation requires crafted VBIOS (physical access). Index-reachability proof built and run on the guest (run.log) β the code-level defect is certain, exploitation hardware-gated, hence Low/likely.
No comments yet.