> ## RE-VERIFIED (after the CCP finding was retracted) > > All three claimed sOS/SYS_DRV fixes were re-audited at instruction level and > **all three stand** (see `METHODOLOGY-INLINING-VS-ADDED-GUARDS.md`). Its > sibling `FINDING-SOS-CCP-WINDOW-FIXED-IN-54.md` was briefly retracted in > error and has been reinstated; the CCP guard's real constants > (`0xCB00000`/`0xCB10000`) are genuinely absent before .52. > > This finding was re-checked independently and **it survives.** > > The discriminator is that **inlining preserves constant counts** — the > constants move between sites but do not multiply. Constant census across > builds (alignment-aware decode + literal-pool search): > > | build | 0xFB800000 | 0xFB000000 | movw #0xFFFD | mov #0x800000 | > |---|---|---|---|---| > | 0.49.0.37 | 2 | 1 | 5 | 3 | > | 0.49.0.47 | 2 | 1 | 5 | 3 | > | 0.49.0.50 | 2 | 1 | 5 | 3 | > | 0.49.0.51 | 2 | 1 | 5 | 3 | > | **0.49.0.54** | **3** | 1 | **7** | **5** | > > `.54` gains +1 / +2 / +2 — new instances of the constants, not relocated > ones. `range_overlap_check` uses exactly one `0xFB800000`, two `#0xFFFD` and > two `#0x800000`, which matches the delta. In the CCP case the older builds had > *more* sites than the newer one, which is the opposite pattern. > > Two newly-carved SYS_DRV builds place cleanly on this: `71a1ee31` matches the > post-fix profile (3,1,7,5) and `1cef477d` the pre-fix profile (2,1,5,3). # FIXED VULNERABILITY: TEE shared-memory map lacks a 16 MB range guard in SYS_DRV <= 0.49.0.51 > **VERSION CORRECTION (from the Phase 4 complete-diff pipeline):** this fix > actually landed in **0.49.0.53**, not 0.49.0.54. Evidence: the guard functions > are absent from the .51 corpus, present in .53, and the **.53 text is > byte-identical to .54**; for the sOS case the guard's window constants > (0x3900000 / 0x3A00000 / 0x3800000 / 0x3700000) appear **nowhere in the whole > .51 image** but do in .53 and .54. `0.49.0.53` is a genuine distinct build > (sha256 differs from both .51 and .54). The original finding compared .51 > against .54 because **.53 was not in the archive at that time** — note it is > still absent from `versions/*.bin`. The fix itself is unchanged; only the > version attribution moves one release earlier. **Status: the version delta is CONFIRMED at instruction level and by constant census across all 8 archived builds.** SYS_DRV **0.49.0.54** (live) refuses to map a 16 MB protected window through the TEE shared-memory RPC. **Every archived older build (0.49.0.37 .. 0.49.0.51) has no such check.** This is the second fix found by the symbol-port diff, and unlike the sOS/CCP one (`FINDING-SOS-CCP-WINDOW-FIXED-IN-54.md`) it sits on a **host-reachable RPC** rather than behind a TA compromise. -------------------------------------------------------------------------------- ## 1. The call chain (all four links DIVERGED in .51) ``` sysdrv_rpc_dispatch (0xE105A8) case 5 -> sysdrv_tee_map_shared_mem (0xE142A0) -> range_overlap_check (0xE212DC) <-- the new guard -> ranges_must_not_overlap (0xE0F2F0) ``` ## 2. The guard added in .54 ```asm range_overlap_check: 0xE212E6 MOV.W R0, #0x800000 ; length 8 MB 0xE212F0 MOVW R1, #0xFFFD ; high dword of the 64-bit base 0xE212F4 LDR R0, =0xFB800000 0xE212F6 STRD.W R0, R1, [SP] ; base = 0x0000FFFD_FB800000 0xE212FE BL ranges_must_not_overlap 0xE21304 BNE out ; overlap -> reject 0xE2130A MOV.W R0, #0x800000 ; length 8 MB 0xE21314 MOVW R1, #0xFFFD 0xE21318 MOV.W R0, #0xFB000000 0xE2131C STRD.W R0, R1, [SP] ; base = 0x0000FFFD_FB000000 0xE21324 BL ranges_must_not_overlap ``` Two adjacent 8 MB regions, i.e. a contiguous protected window **`[0x0000FFFD_FB000000, 0x0000FFFD_FC000000)` — 16 MB.** `ranges_must_not_overlap` (`0xE0F2F0`) is a 64-bit overlap test (`adds/adc/subs/sbcs` pairs) returning nonzero when the requested `[base, base+len)` intersects the forbidden range. ## 3. The older builds do not have it — constant census Resume-on-fault linear disassembly of every SYS_DRV build, counting immediates (note: a naive capstone sweep stops at the first literal pool and reports zeros): | build | `0xFB000000` | `0x800000` | `0xfffd` | |---|---|---|---| | 0.49.0.37 | **0** | 5 | 5 | | 0.49.0.41 | **0** | 5 | 5 | | 0.49.0.47 | **0** | 5 | 5 | | 0.49.0.48 | **0** | 5 | 5 | | 0.49.0.49 | **0** | 5 | 5 | | 0.49.0.50 | **0** | 5 | 5 | | 0.49.0.51 | **0** | 5 | 5 | | **0.49.0.54 (live)** | **1** | **7** | **7** | `0xFB000000` appears **nowhere** in any build before .54. The `+2` on `0x800000` and `0xfffd` are exactly the two new 8 MB/high-dword setups above. ## 4. Impact `sysdrv_tee_map_shared_mem` is the handler that establishes a shared mapping for TEE clients. On `<= 0.49.0.51` it performs no overlap test against the 16 MB window at `0x0000FFFD_FB000000`, so a caller that controls the requested base and length can obtain a mapping of that region. The high dword `0xFFFD` places this in the PSP's 64-bit physical view; a 16 MB carve-out that `.54` deliberately fences off from TEE shared mappings is consistent with PSP-private DRAM / the firmware reserved region. Mapping it would give read/write access to memory the TEE boundary is meant to protect. ## 5. What is NOT established * **The exact identity of the 16 MB region** is inferred from its address and size, not proven. It should be confirmed (e.g. against the TMR/carve-out layout) before the impact is stated more strongly than "a region .54 deliberately protects". * **The precise host path.** `sysdrv_tee_map_shared_mem` is dispatched from `sysdrv_rpc_dispatch` (case 5), which is the entry point sOS calls, and prior hardware testing recorded GFX ring cmd `0x08` returning `0xffff0006` — an error internal to this function, implying the host does reach it. The exact ring command -> RPC opcode mapping was not re-confirmed in this pass. * **No exploit was attempted.** Demonstrating it requires rolling SYS_DRV back to `<= .51` and issuing the mapping RPC with a base inside the window. ## 6. The full .51 -> .54 SYS_DRV divergence set (32 functions) ``` sysdrv_rpc_dispatch, sysdrv_init, sysdrv_tee_map_shared_mem, spi_xfer_cmd, tsu_mailbox_dispatch, irq_dispatch_pending, spi_read_region, spi_set_bank_protect, svc_queue_dispatch, svc_queue_wait, flash_recovery_probe, config_context_init, bootrec_flush, memcpy2, spi_read_status, heap2_op_dispatch, spi_read_id, heap2_realloc, desc_slot_alloc, derive_psp_dram_hmac_key, svc_queue_worker, sysdrv_vbios_flash_step, range_overlap_check, buffer_pair_check, bootrec_set_field, ranges_must_not_overlap, bootrec_open, heap2_alloc, bootrec_select_buffer, heap2_free, is_debug_build, spi_addr_bytes ``` Two further clusters in that set are unexamined and worth the same treatment: * **SPI/flash**: `spi_set_bank_protect`, `spi_read_region`, `spi_xfer_cmd`, `spi_addr_bytes`, `sysdrv_vbios_flash_step`, `flash_recovery_probe` — flash write-protection changes are a classic place for a fixed bug. * **heap2**: `heap2_alloc`, `heap2_free`, `heap2_realloc`, `heap2_op_dispatch` — an allocator changing wholesale is often a heap-corruption fix. * `derive_psp_dram_hmac_key` also changed, mirroring `bl_derive_key` in sOS. ## 7. Method `vport2.py` — ports the 1141 named SYS_DRV functions onto each archived build and classifies IDENT / RELOC / MOVED / DIVERGED using alignment-independent mnemonic matching. Same-offset comparison is useless (SYS_DRV grew +4 KB between .51 and .54, so nearly everything shifts); the earlier pass in `VERSION-AUDIT-STATUS.md` matched only copy-primitive call sites and so did not cover mapping-permission checks like this one.