#!/usr/bin/env python3 """Malformed TA images: does the pre-authentication header parser hold up? Every LOAD_TA in this audit used a well-formed signed image. The header parse runs before authentication can complete, so a malformed image exercises code reachable by any host without needing a valid signature -- the classic pre-auth surface. Mutations of a real signed image (signature will fail; the question is HOW it fails): truncations at several points, header length fields set to 0 / huge / negative, and a header byte flipped. Benign = a clean error status. A stall or a crash is a finding. Control: the unmodified image must load with 0x0; if it does not the rig is wrong. """ 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) base=open(glob.glob('/root/psp/contall/ta_42-0-0-6_1c874c3c*')[0],'rb').read() def load(blob, applen=None, tag=''): ap_,amc=alloc(0x80000); cp,cmc=alloc(0x8000) n=(len(blob)+3)&~3 adev.vram.view(ap_,max(n,4))[:] = (blob+b'\x00'*(n-len(blob)))[:max(n,4)] 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) if applen is None else applen t.cmd_buf_phy_addr_lo,t.cmd_buf_phy_addr_hi=cmc&0xFFFFFFFF,cmc>>32; t.cmd_buf_len=0x4000 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(' %-40s -> %#-12x %.1fs%s'%(tag,st,dt,' <<< STALL' if dt>5 else ''), flush=True) return dt>5 if load(base, None, 'CONTROL unmodified image'): sys.exit(3) cases=[] for frac,nm in ((0.99,'99%'),(0.75,'75%'),(0.5,'50%'),(0.1,'10%')): cases.append((base[:int(len(base)*frac)], None, 'truncated to '+nm)) for off in (0x10,0x14,0x18,0x1c,0x20,0x24): for val,vn in ((0,'0'),(0xFFFFFFFF,'ones'),(0x7FFFFFFF,'maxint')): b=bytearray(base); struct.pack_into('