# What SVCs a ROP'd GCP TA can actually trigger -- the accurate, measured picture Correcting the earlier "16 SVCs reachable" (that was the GATE's *allowance*, not our *capability*). Two independent limits apply, and the real triggerable set is their intersection. ## Limit 1: we can only issue SVC immediates that exist as even-aligned `svc #imm` instructions The SVC number is encoded in the instruction (`0xDF imm8`), not a register, and GCP's `.bss`/heap is **not executable** (hijack report section 5), so we cannot forge new `svc` instructions -- only reuse the ones GCP's code already contains. Comprehensive scan of GCP `.77` `[0x400000,0x407000)`, even-aligned real instructions only: svc 0xf2 -- 26 sites (plenty of usable gadgets) svc 0xf3 -- 1 site svc 0xf4 -- 1 site svc 0xf5 -- 1 site Nothing else is even-aligned. `svc 0xf0` appears only at odd offsets (mid-instruction `0xDF` bytes, not executable). The tlApi page (`0xf00000`) adds only `svc 0x66` at `0xf00780`. **So `0xE0-0xE9` (the privileged aliases the gate would allow) are NOT issuable -- no gadget exists for them.** ## Limit 2: the dispatch gate (type-5) -- moot here, since 0xf2-0xf5 are all >= 0xf0 `0xf0+` take no type check (`AUDIT-TA-KERNEL-BOUNDARY`), so all four pass. `svc 0x66` (tlApi) is `<= 0xDF` and type-5-gated, so it is rejected -- not usable. ## The triggerable set and its audit (sos2.elf `sub_6450`, the 0xf0-0xf5 dispatcher) | SVC | handler | what it does | verdict | |---|---|---|---| | **0xf2** | `sos_proc_switch` (`0x22B4`) | RPC to a service with r0=service id, r1=msg | **the entire escalation surface** | | 0xf3 | returns `dword_64BC` | a boot constant | inert | | 0xf4 | `*(pcb_base + 96*PCB[75] + 28)` | reads the **caller's OWN** PCB field +0x1C | inert (own data) | | 0xf5 | `*(pcb_base + 96*PCB[75] + 32)` | reads the caller's OWN PCB field +0x20 | inert (own data) | (0xf0 wait and 0xf1 setexit are benign anyway, and not issuable.) **So of everything a ROP'd GCP TA can trigger, only `svc 0xf2` is useful. The whole TA->kernel attack surface is `svc 0xf2` -> a service.** `0xf3/0xf4/0xf5` read a constant or the caller's own PCB -- no escalation value. ## svc 0xf2 reach -- the real audit target `sos_proc_switch` with the type-5 caller (GCP) permits: * **service 1 = SYS_DRV** (permission-exempt), and **service 2 = ASD** (TA has cap bit 0x80). Service 3 needs caller type 1 -- unreachable. * Both require SP and msg in `[0x400000,0x800000)` -- satisfied by the stack-migration chain (Step 5b/6, proven on silicon). ### SYS_DRV (service 1) opcode reachability is gated, and the gate is BOOT-STATE, not static `sub_E087E4` -> (`opcode>=0x1000`) `sub_E105A8` -> `sub_E05A24` opcode-range ACL: find the {lo,hi,mask} range for the opcode; issue SVC 0x76; reject (0xffff0001) if the mask's caps are absent; opcodes OUTSIDE every range are allowed unconditionally. SVC 0x76 is `(reqmask & ~off_6428[2*PCB[75]]) == 0`, and **`off_6428` (the capability table) is BSS filled at boot** -- so which ranges pass CANNOT be read from the firmware image. It must be measured on silicon. Measured so far: range `0x3100-0x31FF` (mask `0xffff0`, contains the overflow handlers `0x3102/0x3103`) is **REJECTED** (`0xffff0001`). The ACL ranges are: 0x1100-0x11FF m=0x200 0x2000-0x20FF m=0x40 0x3000-0x30FF m=0x1000 0x3100-0x31FF m=0xffff0 (REJECTED) 0x4000-0x400F m=0x2000 0x6000-0x60FF m=0x4000 0x7000-0x70FF m=0x8000 0x8000-0x80FF m=0x10000 0x103D m=0x400 0x103F m=0x800 everything else (incl. <0x1100, 0x1200-0x1FFF where ASD's own 0x1021/0x103B.. live): FREELY ALLOWED ## The audit plan (accurate = measured) 1. **Map reachable SYS_DRV opcodes on silicon.** Reuse the stack-migration chain, vary the opcode, read the exfil'd status: `0xffff0001` == ACL-gated; a handler status == reachable. One shot per ACL range (10 ranges) + a couple of free opcodes gives the full reachability map. 2. **Audit the reachable handlers** (free opcodes + any allowed range) for memory safety -- the overflow handlers `0x3102/0x3103` are gated out, so the hunt is now among the *allowed* opcodes (the large free space `<0x1100`/`0x1200-0x1FFF`, plus whatever ranges pass). 3. **ASD (service 2)** is the other reachable service; its dispatcher surface (passes 1-2 of `LEAD-ASD-SERVICE2-ATTACK-SURFACE.md`) was uniformly validated at the first two levels. Bottom line: the accurate directly-triggerable SVC set is `{0xf2,0xf3,0xf4,0xf5}`, of which only `0xf2` matters; and `0xf2`'s SYS_DRV reach is gated by a boot-filled capability table that only hardware can resolve. The overflow opcodes are gated out; the remaining surface is the ACL-allowed opcodes, to be mapped on silicon and audited. ## MEASURED on silicon: the SYS_DRV svc-0xf2 opcode reachability map `hw/gcp_rop_sweep.py` + `hw/drv_sweep.sh` -- the stack-migration chain, one opcode per ACL range, fresh ATX per shot, reading the exfil'd SYS_DRV status (`0xffff0001` == ACL-rejected): OPCODE 0x1021 (free, no range) status 0x0 REACHED (handler ran) OPCODE 0x3103 (range 0x3100) status 0xffff0001 ACL-REJECTED OPCODE 0x3005 (range 0x3000) status 0xffff0001 ACL-REJECTED OPCODE 0x2005 (range 0x2000) status 0xffff0001 ACL-REJECTED OPCODE 0x1105 (range 0x1100) status 0xffff0001 ACL-REJECTED OPCODE 0x4001 (range 0x4000) status 0xffff0001 ACL-REJECTED **Every ACL range tested is rejected; only free (out-of-range) opcodes pass.** So `off_6428` grants the caller NONE of the range masks (`0x200/0x40/0x1000/0xffff0/0x2000/...`). This settles the confused-deputy question accurately: `SVC 0x76` checks the **real caller's (GCP, type 5) minimal caps** -- the ACL is NOT fooled by the nested RPC. The confused deputy only defeats `sos_proc_switch`'s *permission* bit (dest-1 exempt); the opcode-range ACL stands. ### Accurate reachable SYS_DRV surface via GCP ROP -> svc 0xf2 service 1 * **Crypto opcodes `< 0x1000`** -> `sub_E1DC30` (crypto dispatcher). No opcode-range ACL on this path. Reachable. (These are the MAC/hash/init/setkey ops HDCP uses.) * **High opcodes `>= 0x1000` OUTSIDE every ACL range** -> `sub_E105A8`, allowed unconditionally. Reachable. This includes `0x1000-0x10FF` (except `0x103D/0x103F`), `0x1200-0x1FFF`, `0x5xxx`, `0x9xxx+`, and is exactly where ASD's own emitted opcodes (`0x1021/0x103B/0x103C/0x1043/...`) live. * **ACL-range high opcodes** (`0x1100-0x11FF, 0x2000-0x20FF, 0x3000-0x31FF, 0x4000-0x400F, 0x6000-0x60FF, 0x7000-0x70FF, 0x8000-0x80FF, 0x103D, 0x103F`) -> **UNREACHABLE** (caps absent). ### Consequence for the escalation The stored-length overflow (#9, `sub_E0F364`/`sub_E0B090`, opcodes `0x3102/0x3103`) lives in the `0x3100` range -> **confirmed UNREACHABLE on silicon** from this path. That specific escalation is closed. The reachable SYS_DRV surface is now precisely: the crypto dispatcher (`<0x1000`) and the free high-opcode handlers (`>=0x1000`, out of range). Those are the handlers to audit for a memory-safety defect -- and much of the free high-opcode space overlaps what `fuzz_sysdrv` already exercised via the ASD-emitted opcodes. The audit continues there, not in the gated ranges. ## MEASURED (round 2): the 0x6000/0x7000/0x8000 ranges are ALSO rejected from GCP Prompted by `FINDING-SYSDRV-ACL-RANGE-TABLE.md`, which documents three ACL families the first sweep missed -- and they hold the most interesting primitives: 0x6001 = otp_block_read (OTP / FUSE read) range 0x6000-0x60FF, mask 0x4000 0x6002 = tlv_buffer_copy (SMN MMIO-write, 64 writes/call, attacker values) mask 0x4000 0x7001/0x7002 = ta_reg_access (register write/read, allowlist-gated) range 0x7000, mask 0x8000 0x8000-0x80FF mask 0x10000 Swept them from GCP via the same chain: OPCODE 0x1021 (free) status 0x0 REACHED (control) OPCODE 0x6001 (OTP) status 0xffff0001 ACL-REJECTED OPCODE 0x6002 (MMIO) status 0xffff0001 ACL-REJECTED OPCODE 0x7001 (reg w) status 0xffff0001 ACL-REJECTED OPCODE 0x7002 (reg r) status 0xffff0001 ACL-REJECTED OPCODE 0x8001 status 0xffff0001 ACL-REJECTED **All of them rejected.** Combined with round 1, every one of the 8 distinct ACL range masks (`0x200, 0x40, 0x1000, 0xffff0, 0x2000, 0x4000, 0x8000, 0x10000`) is denied to the GCP caller. GCP's capability entry in `off_6428` grants **none** of the gated ranges. ### Definitive reachability from a ROP'd GCP TA Reachable via `svc 0xf2` service 1: **only** the crypto dispatcher (`opcode < 0x1000`, `sub_E1DC30`) and the **free** high opcodes (`>= 0x1000`, outside all 10 ACL ranges, `sub_E105A8`). Every gated range is unreachable. So from GCP the following SYS_DRV primitives are all **out of reach**: * the stored-length overflow `0x3102/0x3103` (range 0x3100); * **OTP / fuse read `0x6001`** (range 0x6000) -- this is the definitive answer to "can we read fuses": **not from GCP**; * the SMN MMIO-write `0x6002` (range 0x6000); * TA register read/write `0x7001/0x7002` (range 0x7000). ### Strategic implication The gated ranges are reachable only from a TA whose caps hold the matching bit: the ACL-table doc notes **POWERPLAY emits `0x6001/0x6002/0x6003`** and **RAS emits `0x70xx`**, so those TAs hold the `0x4000` / `0x8000` caps that GCP lacks. Reaching the OTP read or MMIO-write (the high-value primitives) therefore requires compromising **POWERPLAY** (for `0x60xx`) or **RAS** (for `0x70xx`) -- a different TA with the right capability entry -- not GCP. GCP ROP is a dead end for the gated SYS_DRV surface; its only SYS_DRV reach is the crypto dispatcher and the free high opcodes. ## How many "free" opcodes can we actually call? ~164 (enumerated from the .54 dispatchers) Enumerated the handled opcodes in both SYS_DRV dispatchers (`sys_drv2.elf` = card's `.54`) and classified each against the 10 ACL ranges: CRYPTO sub_E1DC30 (<0x1000, no ACL): 0x1 - 0x9 9 free HIGH sub_E105A8 (ACL-gated): 0x100a-0x10a4 (minus gated 0x103d/0x103f) + 0x4013/0x4014/0x4015 155 free ------------------------------------------------ TOTAL FREE ~= 164 HIGH gated (unreachable from GCP): 122 opcodes -- the 0x1100/0x2000/0x3000/0x3100/0x4000-400f/ 0x6000/0x7000/0x8000/0x103d/0x103f ranges, i.e. every high-value primitive (overflow 0x3102/0x3103, OTP read 0x6001, MMIO-write 0x6002, reg access 0x70xx). So from a ROP'd GCP TA the reachable SYS_DRV service-1 surface is **~164 opcodes**: the 9 crypto ops and the ~155-opcode `0x1000-0x10A4`(+`0x4013-5`) band. That band is exactly the "0x1000-0x10A6" family the project's original model named, and it is the surface `fuzz_sysdrv` already exercised via ASD's emitted opcodes (`0x1021/0x103B/0x103C/0x1043/0x1044/0x1057/0x1079/0x1087/0x1095/0x109A/0x109B`) and found bounded. The 9 crypto ops (`0x1-0x9`) are the MAC/hash/init/free/setkey family (HDCP's usage), also audited. ### Net Callable free SYS_DRV surface from GCP: ~164 opcodes, almost entirely already-audited (the 0x1000-0x10A4 high band + 0x1-0x9 crypto). The 122 gated opcodes -- which hold every unaudited high-value primitive -- are unreachable from GCP's caps. A fresh memory-safety hunt from GCP would re-cover `fuzz_sysdrv`'s ground; the unaudited high-value surface requires a different caller (POWERPLAY for 0x60xx, RAS for 0x70xx).