#!/usr/bin/env python3 """Does the PSP's TMR check validate the whole cmd_buf RANGE, or only its start address? Pass 86 showed a cmd_buf inside the TMR is rejected (0xa). The classic failure is checking only the start: a buffer that STARTS outside and EXTENDS into the trusted region would then be accepted, and any TA output written into it would land in TMR -- a write primitive across the security boundary. Cases (each a fresh LOAD_TA): A start well below TMR, length small -> expect accept (control) B start below TMR, length straddling TMR start -> accept would be the BUG C start inside TMR -> expect reject (control, known 0xa) D start just below TMR end, length past the end -> accept is fine (leaving TMR) E start at TMR end exactly -> expect accept """ import glob, struct, sys, time sys.path.insert(0,'/root/psp/hw') from tinygrad import Device import tinygrad.runtime.autogen.am.am as am from ring_wrap import install adev=Device["AMD"].iface.dev_impl; psp=adev.psp submit=install(psp,adev) def alloc(n): pa=adev.mm.palloc(n,align=0x1000,zero=True,boot=False); return pa,adev.paddr2mc(pa) blob=open(glob.glob('/root/psp/contall/ta_42-0-0-6_1c874c3c*')[0],'rb').read() tmr_mc = adev.paddr2mc(psp.tmr_paddr); tmr_end = tmr_mc + psp.tmr_size print('TMR mc range: %#x .. %#x (size %#x)'%(tmr_mc,tmr_end,psp.tmr_size), flush=True) def try_load(tag, cmd_mc, cmd_len): ap_,amc=alloc(0x80000) n=(len(blob)+3)&~3 adev.vram.view(ap_,n)[:]=blob+b'\x00'*(n-len(blob)); adev.gmc.flush_hdp() c=am.struct_psp_gfx_cmd_resp(cmd_id=am.GFX_CMD_ID_LOAD_TA); t=c.cmd.cmd_load_ta t.app_phy_addr_lo,t.app_phy_addr_hi=amc&0xFFFFFFFF,amc>>32; t.app_len=len(blob) t.cmd_buf_phy_addr_lo,t.cmd_buf_phy_addr_hi=cmd_mc&0xFFFFFFFF,cmd_mc>>32 t.cmd_buf_len=cmd_len t0=time.time() try: r=submit(c); st=r.resp.status&0xFFFFFFFF except Exception as e: try: st=int(str(e).strip().split()[-1])&0xFFFFFFFF except Exception: st=-1 dt=time.time()-t0 print(' %-46s addr=%#-12x len=%#-8x -> %#-10x %.1fs%s'%(tag,cmd_mc,cmd_len,st,dt, ' <<< HANG' if dt>5 else ''), flush=True) return st cp,cmc=alloc(0x8000) try_load('A control: normal buffer', cmc, 0x2000) try_load('B start BELOW tmr, extends INTO tmr', tmr_mc-0x2000, 0x8000) try_load('C control: start inside tmr', tmr_mc+0x1000, 0x1000) try_load('D start below tmr end, extends past end', tmr_end-0x1000, 0x8000) try_load('E start exactly at tmr end', tmr_end, 0x2000)