DCE12 copy of the uninitialized-*id defect: offset_to_id returns success for all DDC-family offsets (165-189) without writing *id β dal_gpio_service_create_irq switches on an uninitialized gpio_id; garbage==GPIO_ID_HPD smuggles en=6/7 into the 6-entry hpd_regs[] (OOB)
Summary
Identical contract violation in the Vega12-family unit (proven verbatim with the real REG() constants on the guest); VBIOS gpio_pin_lut input. Same fix hunks (write *id in the DDC branches + the consumer domain guard).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4945 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.8 KB | β raw | |
| VERDICT.md | β | 2.4 KB | β raw | |
| harness_dce120.c | β | 10.0 KB | view raw | |
| build.sh | β | 92 B | view raw | |
| run.sh | β | 89 B | view raw | |
| build.log | β | 68 B | view raw | |
| run.log | β | 979 B | view raw | |
| env.txt | β | 419 B | view raw | |
| fix.diff | β | 3.3 KB | view raw | |
| manifest.json | β | 735 B | view raw | |
| verdict.json | β | 3.9 KB | view raw |
DF-4945 β hw_translate_dce120.c: offset_to_id returns success for DDC-family offsets without writing *id (DCE12 copy of DF-4943)
File audited (pass 2): sys/dev/drm/amd/display/dc/gpio/dce120/hw_translate_dce120.c
Lines: 165-189. Consumer: gpio_service.c:143-157.
What to run
./build.sh && ./run.sh # harness_dce120.c (run.log)
harness_dce120.c is a verbatim copy of the DCE12 offset_to_id
(hw_translate_dce120.c:61-201) with the real DCE12/Vega10 constants:
REG(x) = DCE_BASE__INST0_SEG2(0x34C0) + mm x (vega10_ip_offset.h:277,
all DC_GPIO regs BASE_IDX 2) β exactly the full-offset domain the VBIOS
gpio_pin_lut.data_a_reg_index stores (bios_parser2.c:537-539), e.g.
REG(DC_GPIO_DDC1_A)=0x55a7.
Expected (reproduced on the DF 6.5-DEVELOPMENT guest)
offset_to_id(REG(DDCVGA),0x100) = true en=6(id==0x7b7b7b7b UNTOUCHED)
-> BUG(DF-4945): success, *id never written; garbage id==GPIO_ID_HPD(3)
=> dal_gpio_create(HPD, en=6) with en>=6 indexes hpd_regs[6] OOB
offset_to_id(REG(I2CPAD),0x1) = true en=7(id==0x7b7b7b7b UNTOUCHED)
-> BUG(DF-4945): en=7 >= hpd_regs[6]: garbage-id==HPD path is OOB
Kernel chain (code trace)
- VBIOS
gpio_pin_lut v2.1entry (data_a_reg_index= a DCE12 DDC-family full offset β bios_parser2.c:537-539) for a connector's HPD pin βget_hpd_gpio(dc_link.c:115-118) βdal_gpio_service_create_irq. gpio_service.c:148-151:iduninitialized;offset_to_idreturns true having written only*en(hw_translate_dce120.c:165-189).- Garbage
id == GPIO_ID_HPD(3)βdal_gpio_create(HPD, enβ{0..7})βdal_gpio_service_openβdefine_hpd_registers(pin, en)βhpd_regs[6..7]OOB (hpd_regs[]has 6 entries, hw_factory_dce120.c:76-83,158) βREG_GET(int_status)/REG_UPDATE_2(toggle_filt_cntl)MMIO from garbage descriptors (hw_hpd.c:89,110). DDC-line values 6/7 (DDC_VGA / I2C_PAD) are the OOB producers; values 0..5 alias valid HPD pins (wrong-pin programming).
DCE120-specific notes
- No
mmGPIOPAD_Acase exists in the DCE12 reverse map (verified: harness T2 rejects 0x183) and noGPIO_ID_GPIO_PADcase inid_to_offsetβ the deterministic GPIOPADβDDC OOB producer (DF-4942) does not exist on dce120; only the uninit-*iddefect does. - The
REG()base arithmetic (SEG2=0x34C0) matches the VBIOS full-offset domain β the switch constants are correct (negative result).
After fix.diff
The dce120 hunks set *id = GPIO_ID_DDC_DATA in all 8 DDC-family branches
plus the dal_gpio_create_ddc consumer guard β structurally eliminating the
uninitialized id on this family as well.
Impact ceiling
Same as DF-4943 (Low): crafted VBIOS + stack-garbage==HPD; worst case OOB rodata read β wild MMIO β panic at driver attach on Vega10-class ASICs.
DF-4945 VERDICT
Status: reproduced (unit-level contract violation executed on the DF guest with the verbatim DCE12 function); kernel consequence chain proven by code trace, probabilistic final stage.
harness_dce120.ccarries a verbatim copy of the dce120offset_to_id(hw_translate_dce120.c:61-201) with real constants. The REG() macro arithmetic was verified against the register headers:REG(x) = DCE_BASE__INST0_SEG2 (0x34C0) + mm x(vega10_ip_offset.h:277; all DC_GPIO regs BASE_IDX 2), yielding e.g.REG(DC_GPIO_DDC1_A)=0x55a7β exactly the full-offset domain VBIOSgpio_pin_lut.data_a_reg_indexstores (bios_parser2.c:537-539). So the switch constants are correct; the defect is purely the unwritten*id.- Guest execution (run.log):
offset_to_id(REG(DC_GPIO_DDCVGA_A), 0x100)β true, en=6, id untouched at poison;offset_to_id(REG(DC_GPIO_I2CPAD_A), 0x1)β true, en=7, id untouched. Consumerdal_gpio_service_create_irq(gpio_service.c:148) declaresiduninitialized β CWE-457. - Chain for garbage id == GPIO_ID_HPD(3):
dal_gpio_create(HPD, 6/7)βdal_gpio_service_openβdefine_hpd_registersβ&hpd_regs[6..7]β OOB past the 6-entry array (hw_factory_dce120.c:76-83,158) βREG_GET(int_status)/REG_UPDATE_2(toggle_filt_cntl)MMIO from garbage rodata descriptors (hw_hpd.c:89,110). - DCE12 differences vs dce80, both verified: (a) no
mmGPIOPAD_Areverse-map case and noGPIO_ID_GPIO_PADforward-map case β the deterministic DF-4942 producer is absent (harness T2: offset 0x183 β false); (b) ddc arrays still 8 entries (DDC1..6 + VGA + I2CPAD), consistent with the DDC enum domain 0..7 (no finding). - Fix: dce120 hunks of fix.diff (8Γ
*id = GPIO_ID_DDC_DATA) + consumer guard; validated on the dce80 harness twin (fixrun.log, 0 regressions). - Severity Low: crafted-VBIOS precondition + stack-garbage==HPD; worst case OOB rodata read β wild MMIO β panic at attach on Vega10-class hardware. Not unprivileged-user-reachable on stock systems.
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 *id = GPIO_ID_DDC_DATA to all eight DDC-family branches of the dce120 offset_to_id and the dal_gpio_create_ddc consumer guard; the same edit applied to the dce80 harness family (harness_fixed) demonstrates the uninitialized id is structurally eliminated and the DDC decode is the only accepted domain β 0 regressions (fixrun.log). The dce120 hunks are textual twins of the validated dce80 hunks.
fix.diff hunks for sys/dev/drm/amd/display/dc/gpio/dce120/hw_translate_dce120.c and gpio_service.c; fixrun.log (dce80 model run of the same fix).
Confirmed kernel references
- sys/dev/drm/amd/display/dc/gpio/dce120/hw_translate_dce120.c:165
- sys/dev/drm/amd/display/dc/gpio/gpio_service.c:148
- sys/dev/drm/amd/display/dc/gpio/gpio_service.c:366
- sys/dev/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c:76
- sys/dev/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c:158
- sys/dev/drm/amd/display/dc/gpio/hw_hpd.c:89
- sys/dev/drm/amd/display/dc/core/dc_link.c:115
- sys/dev/drm/amd/display/dc/bios/bios_parser2.c:537
Detail
Exploit chain
crafted VBIOS gpio_pin_lut v2.1 (data_a_reg_index = REG(DC_GPIO_DDCVGA_A)=0x55bf or REG(DC_GPIO_I2CPAD_A)=0x55d7, bios_parser2.c:537) -> get_hpd_gpio (dc_link.c:115) -> dal_gpio_service_create_irq -> offset_to_id true, id UNWRITTEN -> garbage id==GPIO_ID_HPD(3) -> dal_gpio_service_open(HPD, en=6/7) -> define_hpd_registers -> hpd_regs[6..7] OOB rodata read -> REG_UPDATE MMIO at garbage offsets -> panic/MCE. Probabilistic final stage.
Evidence (decisive lines)
run.log T1: 'offset_to_id(REG(DDCVGA),0x100) = true en=6(id==0x7b7b7b7b UNTOUCHED)' and 'offset_to_id(REG(I2CPAD),0x1) = true en=7(id==0x7b7b7b7b UNTOUCHED)'; T2: no GPIOPAD mapping (0x183 rejected) proving the dce80-style deterministic producer is absent on dce120.
PoC changes
n/a β fresh harness (verbatim dce120 offset_to_id copy, real DCE12/Vega10 constants incl. SEG2 base 0x34C0).
Verified recommended fix
Write *id (GPIO_ID_DDC_DATA) in every successful offset_to_id DDC-family branch (dce120 file), matching the dce80 fix.
Verdict
The DCE12 copy of offset_to_id (hw_translate_dce120.c:165-189) has the same defect as DF-4943: all eight DDC-family branches return true after writing only en. dal_gpio_service_create_irq (gpio_service.c:148-156) then switches on the uninitialized id; garbage==GPIO_ID_HPD(3) with a DDC-line en of 6 (DDC_VGA) or 7 (I2C_PAD) reaches define_hpd_registers, which indexes the 6-entry hpd_regs[] (hw_factory_dce120.c:76-83,158) out of bounds β garbage int_status/toggle_filt_cntl descriptors then drive MMIO (hw_hpd.c:89,110). Executed on the DF guest with a verbatim copy of the dce120 function and real DCE12 REG() constants (REG(DDCVGA)=0x55bf, REG(I2CPAD)=0x55d7 β run.log T1: both return true with id untouched). Kernel-stage execution requires a Vega10-class ASIC + crafted VBIOS (absent in QEMU). Unlike dce80, dce120 has no GPIOPAD case (T2 negative control), so the deterministic DF-4942 producer does not exist on this family β the uninit-id path is the only cross-domain route and is probabilistic.
No comments yet.