aboutsummaryrefslogtreecommitdiffstats

PSP ring frame (psp_gfx_rb_frame, 64 bytes) — complete field map

Evidence class: [HW] — Navi 31 / RX 7900 XTX, sOS/SYS_DRV 0.49.0.54. Every row measured, each with a control re-run after the mutation so a wedged PSP cannot manufacture results.

The ring frame is entirely host-written and was not examined at all until late in the memory-safety hunt; every earlier pass varied command content. This is what each field actually does on this firmware.

offset field behaviour probe
+0 / +4 cmd_buf_addr_lo/hi used. 0xFFFFFFFF or MC 0 ⇒ PSP wedge (VMC fault flood). TMR-range destinations rejected. frame_sweep.py, aperture_test.py
+8 cmd_buf_size ignored entirely — 0, 1, 0x1001, 0x100000, 0x7FFFFFFF, 0xFFFFFFFF all complete 0x0, no guard writes. Command size is implicit. frame_cmdsize.py
+12 / +16 fence_addr_lo/hi used as a write destination. Not range-checked against the TMR (unlike cmd_buf). 0 ⇒ PSP wedge. fence_tmr2.py, fence_land.py
+20 fence_value the host-chosen value written to fence_addr. fence_write.py
+24 / +28 sid_lo/hi no observable effect. frame_sweep.py
+32 b0 vmid honoured as the VM context for the PSP's own accesses, unvalidated. Any non-zero value ⇒ PSP wedge, with an L2 read fault (0x100d33) at the PSP's own command buffer tagged with that VMID. vmid_test.py, vmid_fault.py
+32 b1 frame_type ignored (1, 255 harmless). vmid_test.py
+34..35 reserved1 no effect. frame_sweep.py
+36..+60 reserved2[7] no effect. frame_sweep.py

The ring index

Separate from the frame: the write pointer C2PMSG_67 is bounded to the ring size (hw/ring_wptr_oob.py). A valid frame planted one ring-length and 1 MB past the end is not executed, and the PSP stays healthy — out-of-range indices are ignored rather than faulting. That graceful handling is exactly what fence_addr = 0 and a non-zero vmid lack.

Ring creation

The base/size given at ring creation are well validated — hw/ring_create_fuzz.py: size 0/1/0xFFFFFFFF rejected 0x4, size 2 GB rejected 0x5, and a base inside the trusted region rejected 0xa. The one gap is alignment: base + 1 is accepted and then wedges on first submit (FINDING-PSP-RING-BASE-ALIGNMENT-UNCHECKED.md, eighth DoS trigger).

Security summary

  • Two unvalidated host-controlled fields: fence_addr (a write destination not checked against the trusted region, where cmd_buf is) and vmid (a translation context used by trusted firmware).
  • Three of the seven known DoS triggers live in this structure: bad cmd_buf_addr, fence_addr = 0, and any non-zero vmid.
  • No memory corruption: the fence write does not land in the TMR (dense functional test, fence_spray.py), and a host-chosen VM context grants the host nothing on a bare-metal part because it already owns its own page tables and the frame's addresses.

Details: fw/FINDING-PSP-FENCE-ADDR-UNVALIDATED.md, fw/FINDING-PSP-RING-FRAME-VMID-UNVALIDATED.md, fw/REPORT-PSP-DOS-TRIGGERS.md.