aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoruser <user@clank>2026-09-24 10:55:29 +0200
committeruser <user@clank>2026-09-24 10:55:29 +0200
commit4ebe39dca802e17d41b16444767dfaf16f1eedd6 (patch)
treebd9fa315358a1bed7d6dbb1ab3a6a0588e12c198
parentDemonstrate the pre-auth IFWI wrapping bug executing in the emulator (diff)
downloadamd-psp-re-4ebe39dca802e17d41b16444767dfaf16f1eedd6.tar.gz
amd-psp-re-4ebe39dca802e17d41b16444767dfaf16f1eedd6.tar.xz
amd-psp-re-4ebe39dca802e17d41b16444767dfaf16f1eedd6.zip
Confirm the 4.1c disclosure mechanism in our build, at corrected addresses
Drove the second half of the TSU chain in the emulator's firmware image. All three code facts the disclosure claim rests on are now verified in OUR sys_drv build, at addresses recovered from the code rather than the v53 map, which is wrong for this entire subsystem. Address recovery: the parse flow at 0xE1B050/0xE1B070 -- two rom_parse_directory calls with svc #0x7d mapping 0xD100000 between them, exactly as documented -- falls through to bl 0xE099E4 with (err, img, ctx1, ctx2). That is the real tsu_write_active_slot. The v53 map's 0xE09868 has zero callers. Fact 1, the caller passes the verify flag as zero (tsu_write_active_slot, 0xE09ACE): it loads *(ctx2 + 16*i + 0x84) and *(+0x88), stores the value plus TWO zeros on the stack (strd r2,r1,[sp]; str r1,[sp,#8]) and calls 0xE06904. 0x84 and 0x88 are 132 and 136 decimal -- precisely the offsets the analysis named. Fact 2, the callee skips verification on that flag (tsu_write_block, 0xE06904): `ldrd r6,r0,[sp,#0x44]` then `cbz r6, 0xE0693E` jumps over the verify call at 0xE20B18 and lands on `add.w r0, sl, fp` (source = a2 + a3) followed by the write at 0xE1A930. That cbz is the `if (a6 != 0)` guard, and the caller hardcodes 0, so verification never runs. Fact 3, the source is the attacker's offset: a3 comes from the parsed context at +136, out of the host-supplied image, having passed only the wrapping checks that the previous commit demonstrated are broken. So the mechanism is confirmed in this build rather than inherited from another version's addresses. Kept the boundary explicit: this is still not demonstrated end to end. Reaching the writer needs a crafted image that parses cleanly through BOTH rom_parse_directory calls, since the flow returns early on any parse error. That next step is also emulator-side -- the write sink can be hooked rather than executed, so no flash write and no card are involved.
-rw-r--r--psp_out/FINDING-IFWI-WRAP-CONFIRMED-IN-EMULATOR.md59
1 files changed, 59 insertions, 0 deletions
diff --git a/psp_out/FINDING-IFWI-WRAP-CONFIRMED-IN-EMULATOR.md b/psp_out/FINDING-IFWI-WRAP-CONFIRMED-IN-EMULATOR.md
index 2c51034..71cac1b 100644
--- a/psp_out/FINDING-IFWI-WRAP-CONFIRMED-IN-EMULATOR.md
+++ b/psp_out/FINDING-IFWI-WRAP-CONFIRMED-IN-EMULATOR.md
@@ -77,3 +77,62 @@ work depends on is shown to be unreliable before it was relied upon.
`if (err) return` into `tsu_write_active_slot` and the erase/write state
machine, which is flash-side and remains dropped by `CONSTRAINTS.md`. Nothing
here writes flash or touches the card.
+
+---
+
+# The 4.1c mechanism, confirmed in THIS build at corrected addresses
+
+The disclosure claim rests on three code facts. All three are now verified in our
+`sys_drv` image, at addresses recovered from the code rather than from the stale
+v53 map (which is wrong for this whole subsystem — see the table above).
+
+**Address recovery.** The parse flow at `0xE1B050`/`0xE1B070` (two
+`rom_parse_directory` calls, with `svc #0x7d` mapping `0xD100000` between them,
+exactly as documented) falls through to `bl 0xE099E4` with
+`(err, img, ctx1, ctx2)`. That is the real `tsu_write_active_slot`; the v53 map
+points at `0xE09868`, which has zero callers.
+
+**Fact 1 — the caller passes the verify flag as zero.** In
+`tsu_write_active_slot` at `0xE09ACE`:
+
+ add.w r0, r7, r6, lsl #4 ; ctx2 + 16*i
+ movs r1, #0
+ ldr.w r2, [r0, #0x84] ; *(ctx + 16*i + 132)
+ strd r2, r1, [sp] ; stack: value, 0
+ str r1, [sp, #8] ; stack: 0 <-- a6 = 0
+ ldr.w r3, [r0, #0x88] ; *(ctx + 16*i + 136)
+ bl 0xE06904 ; tsu_write_block
+
+The offsets `0x84` and `0x88` are **132 and 136 decimal** — precisely the
+`*(a3 + 16*i + 132)` and `+136` the analysis named, from a context parsed out of
+the host-supplied image.
+
+**Fact 2 — the callee skips verification on that flag.** In `tsu_write_block`
+(`0xE06904`):
+
+ ldrd r6, r0, [sp, #0x44] ; r6 = a6 (verify flag)
+ cbz r6, 0xE0693E ; a6 == 0 -> SKIP
+ ...
+ bl 0xE20B18 ; the verify call, jumped over
+ 0xE0693E:
+ add.w r0, sl, fp ; source = a2 + a3
+ bl 0xE1A930 ; the write, runs regardless
+
+`cbz r6` is the `if (a6 != 0)` guard. With the caller hardcoding 0, the verify
+never runs and execution proceeds to the write with `source = base + offset`.
+
+**Fact 3 — the source is the attacker's offset.** `sl`/`fp` are `a2`/`a3`, and
+`a3` comes from the parsed context at `+136`, i.e. out of the host-supplied
+image, having passed only the wrapping checks demonstrated to be broken above.
+
+## Status
+
+§4.1c's mechanism is now confirmed **in our build**, statically, on addresses
+validated by call-scan rather than inherited from a map that is wrong here. The
+earlier confirmation was on a different version's addresses.
+
+**Still not demonstrated end to end.** Driving it in the emulator needs a crafted
+image that parses *cleanly* through both `rom_parse_directory` calls — the flow
+returns early on any parse error and never reaches the writer. That is the next
+step, and it is entirely emulator-side: no flash write and no card, because the
+write sink can simply be hooked rather than executed.