aboutsummaryrefslogtreecommitdiffstats
path: root/psp_emu/harness/probe_sysdrv_53_log_prevalidate.py
diff options
context:
space:
mode:
authoruser <user@clank>2026-10-09 16:11:31 +0200
committeruser <user@clank>2026-10-09 16:11:31 +0200
commitbc43149d914325e15dc0490dee9d982e21287623 (patch)
treea632cf70de742d5a60d01c9c0d806bf5b9257538 /psp_emu/harness/probe_sysdrv_53_log_prevalidate.py
parentGCP->ASD 0x403: ASD-internal chain PROVEN end-to-end in emulator (real handlers) (diff)
downloadamd-psp-re-main.tar.gz
amd-psp-re-main.tar.xz
amd-psp-re-main.zip
Record PSP security investigation artifacts and probesHEADmain
Diffstat (limited to 'psp_emu/harness/probe_sysdrv_53_log_prevalidate.py')
-rw-r--r--psp_emu/harness/probe_sysdrv_53_log_prevalidate.py93
1 files changed, 93 insertions, 0 deletions
diff --git a/psp_emu/harness/probe_sysdrv_53_log_prevalidate.py b/psp_emu/harness/probe_sysdrv_53_log_prevalidate.py
new file mode 100644
index 0000000..4f0f03c
--- /dev/null
+++ b/psp_emu/harness/probe_sysdrv_53_log_prevalidate.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python3
+"""Scope signed .54 low opcode 0x53 logging before caller-string validation.
+
+Synthetic SVC/PCB/caller window only. No card request or cross-process claim.
+Signed SYS_DRV init/dispatch/logging string copy run; MMIO/log-drain effects
+are not hardware evidence.
+"""
+from __future__ import annotations
+
+import sys
+from pathlib import Path
+from unicorn import UC_HOOK_CODE, UC_PROT_NONE
+from unicorn.arm_const import UC_ARM_REG_R1
+
+sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
+from pspemu import sysdrv_env # noqa: E402
+from pspemu.component import Fault # noqa: E402
+
+SIGNED = Path(__file__).resolve().parents[2] / 'psp_out/elf/sys_drv_0.49.0.54_18bd9d26.elf'
+ENTRY = 0xE087E4
+BASE, END = 0x400000, 0x800000
+LOG_FLAG, LOG_LEVEL, BACKEND_FLAG = 0xE264E0, 0xE264E4, 0xE269CC
+STRING_HELPER, FORMATTER, DRAIN = 0xE2232C, 0xE01A34, 0xE21D44
+LOG_BUFFER = 0xEB5FB0
+
+
+def main() -> None:
+ sd = sysdrv_env.make()
+ assert Path(sd.image_path).read_bytes() == SIGNED.read_bytes()
+ rv, fault, _ = sysdrv_env.run_init(sd)
+ assert rv == 0 and fault is None and sysdrv_env.init_flag(sd) == 1, (rv, fault)
+ flags = (sd.read(LOG_FLAG, 1)[0], sd.rd32(LOG_LEVEL), sd.read(BACKEND_FLAG, 1)[0])
+ print('signed init logging (frontend, level, backend)=', flags, flush=True)
+ assert flags[0] == 1 and flags[2] == 1, 'both modeled init log gates required'
+ sd.uc.mem_map(BASE, 0x3000)
+ regs = sd.uc.mem_regions()
+ if not any(lo <= END-4 <= hi for lo, hi, _ in regs):
+ sd.uc.mem_map(END-0x1000, 0x1000)
+ if any(lo <= END <= hi for lo, hi, _ in sd.uc.mem_regions()):
+ sd.uc.mem_protect(END, 0x1000, UC_PROT_NONE)
+
+ def svc_window(comp, n):
+ out = comp.uc.reg_read(UC_ARM_REG_R1)
+ for i, v in enumerate((BASE, END, 0, 0)):
+ comp.wr32(out + 4*i, v)
+ return 0
+ sd.svc.register(0xB5, svc_window)
+ req, cfg = sd.alloc(0x100), sd.alloc(0x400)
+ sd.write(cfg, b'\x00' * 0x400)
+ src, edge = BASE+0x1000, END-4
+ sd.write(src, b'J' * 40)
+ sd.write(edge, b'K' * 4)
+ seen, fmt, before_drain = [], [], []
+ sd.uc.hook_add(UC_HOOK_CODE, lambda uc, ea, size, data: seen.append(ea),
+ begin=STRING_HELPER, end=STRING_HELPER+1)
+ sd.uc.hook_add(UC_HOOK_CODE, lambda uc, ea, size, data: fmt.append(ea),
+ begin=FORMATTER, end=FORMATTER+1)
+ sd.uc.hook_add(UC_HOOK_CODE,
+ lambda uc, ea, size, data: before_drain.append(bytes(
+ uc.mem_read(LOG_BUFFER+16, 39))),
+ begin=DRAIN, end=DRAIN+1)
+
+ def request(ptr: int, declared: int) -> int:
+ sd.write(req, b'\x00' * 0x100)
+ for i, word in ((0, 0x53), (2, ptr), (3, declared), (14, 16),
+ (sysdrv_env.REQ_CONFIG_DWORD, cfg)):
+ sd.wr32(req + i*4, word)
+ return sd.run_function(ENTRY, (req, 2, 0, 0), count=3_000_000,
+ timeout=4_000_000)
+
+ r = request(src, 4)
+ assert r == 0 and len(seen) == len(fmt) == 1
+ assert before_drain == [b'J' * 39], before_drain
+ print('mapped non-NUL input: declared4, signed logger copied 39 bytes '
+ 'before later NUL check; return', hex(r), flush=True)
+
+ n, m, d = len(seen), len(fmt), len(before_drain)
+ denied = request(edge, 40)
+ assert denied == 0xFFFF000F and (len(seen),len(fmt),len(before_drain)) == (n,m,d)
+ print('synthetic edge declared40 rejected before logger',hex(denied),flush=True)
+ try:
+ request(edge, 4)
+ except Fault as exc:
+ assert exc.addr == END, (exc, sd.faults)
+ assert (len(seen),len(fmt),len(before_drain)) == (n+1,m+1,d)
+ print('synthetic edge declared4: signed logger fault at',hex(exc.addr),
+ 'before later NUL check and log drain',flush=True)
+ else:
+ raise AssertionError('short-declared synthetic edge unexpectedly completed')
+
+
+if __name__ == '__main__':
+ main()