# dmcub/ — the DCN display microcontroller (DMCUB / DMUB) New target, opened 2026-09. Read in this order: 1. `AUDIT-DMCUB-03-COMMANDS.md` — **the per-command audit of all 24 implemented `DMUB_CMD__*` types**, three candidate findings, and the coverage limits. 1. `AUDIT-DMCUB-07-DPAUX.md` — the **newer images** (3.5/3.6/4.0.1): a taint-root bug that had made the whole 4.0.1 run a false negative, the retraction of the "`DP_AUX_ACCESS` is a stub everywhere" claim, and **FINDING-11**. 2. `AUDIT-DMCUB-02.md` — dispatcher/register-map infrastructure, the address base, and the first finding. 3. `AUDIT-DMCUB-01.md` — provenance, container format, ISA determination (partially superseded; carries a banner). Short version: the DMCUB is a **Tensilica Xtensa** (windowed ABI) microcontroller inside AMD's DCN display IP, PSP-loaded, body mapped at **0x60000000** (`VA = 0x60000000 + file_off - 0x200`), driven by the host over a 64-byte-frame inbox ring plus a GPINT doorbell. For Navi 31 the image is `fw/dcn_3_2_0_dmcub.bin`, 1036 functions, 24 implemented command types. Three candidate findings so far, all **static only**, all host→DMCUB (the inbox is driven by amdgpu, so none is a privilege escalation *for* the host — see the threat model note in `AUDIT-DMCUB-02.md`): | # | command | primitive | | --- | --- | --- | | 1 **[HW]** | `ABM_INIT_CONFIG` (66) | unchecked 16-bit `bytes` → **confirmed on hardware**: ~32 KB of attacker-supplied data written past a 712-byte slot (`bytes=0x8000`, 32492 bytes changed, processed cleanly); `bytes` ≥ 0x9c00 also wedges the command loop | | 8 **[HW]** | *(firmware loading)* | **DMUB rollback works** — 7.0.38 / 7.0.42 load and run on a card shipping 7.0.51, and a DCN **3.5** image is accepted and starts executing on DCN 3.2 silicon. Signature enforced, version/ASIC binding absent. Dates findings 1/2/3 to ≥ 7.0.38 (2024-02) | | 6 **[HW]** | `ABM_INIT_CONFIG` (66) | one command with `bytes` ≥ 0x9c00 **wedges the inbox command loop** (display DoS); `SCRATCH0`/timer still look healthy, so liveness must be judged by ring consumption | | 2 **[HW]** | `GET_VISUAL_CONFIRM_COLOR` (8) | unbounded 16-bit `panel_inst` → 8-byte OOB read returned to the host. **Confirmed on hardware**: indices 2..227 return memory past the 2-entry array. The DoS leg is retracted (out-of-window reads return zeros) | | 3 **[HW partial]** | `HW_LOCK` (69) | unbounded 8-bit `dig_inst` → register pointer fetched past a 7-entry table, then read-modify-written. **Hardware: reachable and `dig_inst` provably selects the register (1/2/3 → OTG1/2/3), but no OOB write achieved** — the table lives in PSP-owned CW0, so the pointer *value* is never attacker-controlled. Latent, not a primitive | | 4 **[HW not demonstrated]** | `REPLAY` (83), `CACP` (87), `VBIOS` (128) | handlers run and write state, but the offsets are **index-independent** for idx 0..255; Replay is additionally caller-bounded (`bgeui idx, 2`). Same class: an unchecked `panel_inst`/instance byte scaled by 0x130 / 0x30c / 0xd4 into per-instance state or into the register-address table (Replay's is a plain `s8i` write; AMD's own ABI says that field "is only 0 or 1") | | 11 **[ST+EMU]** | `DP_AUX_ACCESS` (70), in `yellow_carp`, `dcn_3_1_4`, `dcn_3_5`, `dcn_3_6` | unchecked 8-bit `instance` on the DPIA path → **host-controlled 1-byte write at `base + + instance`, stride 1, up to 252 bytes past a 4-entry array**, repeatable. The sibling function on the same path applies the intended `instance < 4` bound (3×) one call *too late*. Reaches a multiply-referenced adjacent structure at `instance` 8–12. Stays inside the mapped data region (adjacent-global corruption, not a wild write). Stubbed in 3.2.x/4.0.1, which is why a 3.2.0-anchored audit missed it. See `AUDIT-DMCUB-07-DPAUX.md` | Newer images (`dcn_3_5`, `dcn_4_0_1`) implement 31 command types including `DMUB_CMD__PSP`, `LSDMA` (host-supplied DMA src/dst/count) and `FUSED_IO`; those are static-only leads because the 4.0.1 image is refused by this card's PSP and the 3.5 image will not finish booting on DCN 3.2. `DP_AUX_ACCESS` (70) is a **stub in** 3.2.0 **and** 4.0.1 — but **not** in 3.5/3.6, where it is fully implemented and carries FINDING-11; the earlier generalisation that "there is no AUX sink path via that command in any image we hold" was **retracted** in `AUDIT-DMCUB-07-DPAUX.md`. Only the two stub images had been checked. Also recorded **[HW]**: the host **cannot** program `DMCUB_REGION3_CW0/CW1` or `DMCUB_SEC_CNTL` (writes dropped, reads 0), so `backdoor_load` is blocked on Navi 31 and DMCUB code execution requires a PSP-signed image — a security-positive result, and the reason bring-up goes through `GFX_FW_TYPE_DMUB`. Also recorded: types 1/3/4 are the legacy `REG_SEQ_*` / `REG_REG_WAIT` commands and are an *intentional* arbitrary register read/write/poll interface. They are **documented ABI**, not "unpublished" as this tree said until corrected — present in `enum dmub_cmd_type` from v5.6 through v6.18-rc1 and deleted from the header only by upstream commit `9a591ae691b5` (2026-06-05, "command IDs 1-4 have been deprecated"). `fetch_ref.sh` pulls master, which is why they looked undocumented. **The firmware still dispatches them in every image in `fw/`, including DCN 4.0.1** — the deprecation is header-only. Name IDs from the pinned `ref/dmub_cmd_v6.17.h`; `DP_AUX_ACCESS` (70) is a **stub** in this build (3.2.0 only — see FINDING-11 for 3.5/3.6). Bounded and closed: EDID/CEA reassembly and its VSDB parse, all 23 `jx` dispatches, 27/28 `callx8` sites (the one indexed site is double-guarded), and 55 of 57 memcpy sites. ## Tooling Xtensa needs **capstone 6**; the system capstone (5.0.9) has no `CS_ARCH_XTENSA`: ```sh python3 -m venv /home/user/.venvs/cs6 && /home/user/.venvs/cs6/bin/pip install --pre capstone ``` `dmcub_cfg.py` and `dmcub_regmap.py` must run under that interpreter; the other scripts work with the system python. IDA 9.3/9.4 also ship `procs/xtensa.so` (this corrects the note in `psp_out/FIRMWARE-INVENTORY.md`). ```sh ./fetch_ref.sh # kernel reference sources -> ref/ python3 dmcub_parse.py fw/*.bin # container + dmub_fw_meta_info python3 dmcub_isa_evidence.py fw/dcn_3_2_0_dmcub.bin 0x1c100 0x44000 # ISA + controls V=/home/user/.venvs/cs6/bin/python $V dmcub_dis.py fw/dcn_3_2_0_dmcub.bin hot 12 # hottest call targets $V dmcub_dis.py fw/dcn_3_2_0_dmcub.bin dis 0x6001c780 # the inbox1 dispatcher $V dmcub_regs.py fw/dcn_3_2_0_dmcub.bin ref/dcn_3_2_0_offset.h access --grep INBOX $V dmcub_regs.py fw/dcn_3_2_0_dmcub.bin ref/dcn_3_2_0_offset.h vote # aperture evidence $V dmcub_jxaudit.py fw/dcn_3_2_0_dmcub.bin # jump-table bounds audit $V dmcub_copyaudit.py fw/dcn_3_2_0_dmcub.bin # memcpy length audit $V dmcub_dpaux_audit.py fw/*.bin fw/old/*.bin # FINDING-11 cross-version sweep $V dmcub_emu_dpaux.py --selftest # FINDING-11 in emulation (7 controls x2 images) ``` `dmcub_cmdaudit.py` auto-detects which register holds the command-frame pointer (`a3` on 3.2.x/3.5/3.6, **`a4`** on 4.0.1/renoir) and prints a `WARNING: ... Treat every "0 sinks" result in this run as UNVERIFIED` line if taint never entered a case's handlers. Do not trust a run that prints it — that warning exists because a hardcoded `a3` silently produced a clean audit of 30 unexamined command types. ## Hardware PoC (Option A) `hw/` brought the DMCUB up on the rig and **reproduced FINDING-2 on silicon** (2026-09). The tinygrad-AM stack initialises no display IP, so the core is loaded via the PSP (`GFX_FW_TYPE_DMUB`, stock signed image) and then driven over inbox1. Read `hw/README.md`; transcript in `hw/EVIDENCE-type8-poc.txt`. ## Contents * `fw/` — 10 `linux-firmware` images, Renoir .. DCN 4.0.1 (hashed in `data/MANIFEST.sha256`). * `ref/` — **untracked** upstream kernel sources (register offsets, `dmub_cmd.h` ABI, loader); re-fetch with `fetch_ref.sh`. * `AUDIT-DMCUB-01.md` — the audit. * `dmcub_*.py` — analysis tools, described at the bottom of the audit. * `hw/` — hardware bring-up + PoC scripts (probe, bring-up, type-8 PoC), dry-run by default, plus offline selftests.