FINDING: the PSP ring base is accepted misaligned, then wedges on first submit
Evidence class: [HW] — Navi 31 / RX 7900 XTX, sOS/SYS_DRV 0.49.0.54. Status: missing check CONFIRMED. Eighth DoS trigger. No memory corruption.
The ring-creation surface
The ring is created by writing its base (C2PMSG_69/70), its size (_71) and a create
command to _64, whose low 16 bits are the PSP's own status — so the firmware reports
acceptance directly and nothing has to be inferred. hw/ring_create_fuzz.py, one case per
fresh boot:
| case | status | outcome |
|---|---|---|
| control: correct base and size | 0x0 |
accepted, commands execute |
size 0 |
0x4 |
rejected |
size 1 |
0x4 |
rejected |
size 0xFFFFFFFF |
0x4 |
rejected |
size 0x80000000 |
0x5 |
rejected |
| base inside the TMR | 0xa |
rejected — explicitly range-checked |
base 0 |
— | rejected (ready bit never set) |
| base misaligned (+1) | 0x0 |
ACCEPTED, then wedges |
This validation layer is otherwise good: four distinct rejection codes, and the trusted region is explicitly excluded from the ring base.
The defect
hw/ring_unalign.py runs the aligned control first in the same boot — it succeeds, the
heartbeat advances — and only then creates a ring at base + 1:
aligned base (control) create status=0x0 ACCEPTED submit resp=0x0 hb_advancing=True
base+0x1 create status=0x0 ACCEPTED submit resp=TIMEOUT hb_advancing=False
The misaligned base is accepted at creation and the PSP then dies on the first submit. Because the control passed moments earlier in the same boot, this is not an inherited dead PSP — the failure mode that produced phantom hits twice in this audit.
Why it is a real inconsistency, not a policy choice
Alignment is enforced everywhere else in this interface:
cmd_bufmisaligned ⇒ rejected0x6(even at+0x800),- TA image misaligned ⇒ rejected
0x34, - ring base inside the trusted region ⇒ rejected
0xa, - ring size bogus ⇒ rejected
0x4/0x5.
Only the ring base's alignment is unchecked, and the consequence is deferred to first use.
This is the same shape as LOAD_TA with cmd_buf_len = 0 (accepted at load, hangs on first
invoke): a parameter validated incompletely, with the failure surfacing later as a hang.
Not memory corruption
The PSP hangs; it does not write anywhere it should not. Recovery requires
work/atx_power.py cycle 25; GPU/AM reset is insufficient.
Suggested fix
Check the ring base's alignment at creation and reject it with a status, as the size and the trusted-region overlap already are.
