1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
#!/usr/bin/env python3
"""Full-resolution dword sweep of the LOAD_TA command structure.
The named fields (app address/length, cmd_buf address/length) were fuzzed in passes 86-88 and
104-105, but the command region was never swept dword by dword the way the INVOKE structure
was in pass 108. Any dword that changes the outcome is a field the loader reads.
Control: the unmodified descriptor loads 0x0. Each mutation is applied to a fresh descriptor
with the known-good fields written afterwards, so a hit means that dword specifically matters.
"""
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)
base=open(glob.glob('/root/psp/contall/ta_42-0-0-6_1c874c3c*')[0],'rb').read()
def alloc(n):
pa=adev.mm.palloc(n,align=0x1000,zero=True,boot=False); return pa,adev.paddr2mc(pa)
ap_,amc=alloc(0x80000); cp,cmc=alloc(0x8000)
n=(len(base)+3)&~3
adev.vram.view(ap_,n)[:]=base+b'\x00'*(n-len(base)); adev.gmc.flush_hdp()
def go(mut=None):
c=am.struct_psp_gfx_cmd_resp(cmd_id=am.GFX_CMD_ID_LOAD_TA)
raw=memoryview(c).cast('B')
if mut is not None: struct.pack_into('<I',raw,mut[0],mut[1])
t=c.cmd.cmd_load_ta # write the good fields AFTER the mutation
t.app_phy_addr_lo,t.app_phy_addr_hi=amc&0xFFFFFFFF,amc>>32; t.app_len=len(base)
t.cmd_buf_phy_addr_lo,t.cmd_buf_phy_addr_hi=cmc&0xFFFFFFFF,cmc>>32; t.cmd_buf_len=0x4000
t0=time.time()
sid=None
try:
r=submit(c); st=r.resp.status&0xFFFFFFFF; sid=r.resp.session_id
except Exception as e:
try: st=int(str(e).strip().split()[-1])&0xFFFFFFFF
except Exception: st=-1
dt=time.time()-t0
if st==0 and sid is not None: # free the session or the wall (0xb) masks everything
u=am.struct_psp_gfx_cmd_resp(cmd_id=am.GFX_CMD_ID_UNLOAD_TA)
u.cmd.cmd_unload_ta.session_id=sid
try: submit(u)
except Exception: pass
return st, dt
b,_=go()
print('CONTROL unmodified load -> %#x'%b, flush=True)
hits=[]
for off in range(16, 16+784, 4):
st,dt=go((off,0xFFFFFFFF))
if dt>5: print('STALL at dword %#x'%off, flush=True); break
if st!=b: hits.append((hex(off),hex(st)))
print('dwords that change the LOAD_TA outcome: %s'%(hits if hits else 'NONE across all 196'), flush=True)
|