aboutsummaryrefslogtreecommitdiffstats
path: root/README.md (follow)
Commit message (Collapse)AuthorAge
* Restructure the findings corpus: add INDEX.md, resolve duplicates, re-prioritiseuser2026-09-23
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 131 documents had accumulated organically, with three overlapping "summary" files, several topics split across 3-6 documents, and ten retracted documents whose filenames still read as findings. Restructured rather than rewritten, so no history is lost. Added psp_out/INDEX.md as the map, built from a scan of all 131 files rather than memory: * the spine -- the four documents that govern the rest (CONSTRAINTS, VULN-AUDIT-WHAT-WE-ACTUALLY-HAVE as the vulnerability register, ATTACK-SURFACE, INDEX); * RETRACTED, do not cite -- the ten files carrying retraction banners, listed explicitly because their names mislead; * duplicate clusters with the authoritative file named for each of ten topics (subcmd12, ASD 0x308, SRM walker, Route C, VCN, TMR fence, rollback, SMN map, emulator bring-up, hardware validation); * settled negatives, 17 of them, flagged as "do NOT re-run" since repeating them is the likeliest way to waste a session; * methodology, including the recurring failure mode named once: a measurement producing a confident result its own control invalidates, with this session's five instances listed; * priorities P1-P4, each with its blocker and next concrete step, plus an explicit deprioritised list. Updated the vulnerability register for this session, since it predated it: added the VCN type-49 write as a Tier-1 entry with its precise wording constraint ("completes a register-write loop over attacker-controlled entries", not "arbitrary VCN register write"); qualified Route C's "nothing reads those registers" with the fact that the scan covered only images we hold and the window has since been shown to be a PSP-private space, still unidentified; and corrected the Tier-1 summary from one write primitive to two, neither with a demonstrated consumer. Annotated nine non-authoritative documents with a pointer banner so a reader landing on them directly is not misled, and pointed README at the index. Retraction checker clean over 59 harvested claims.
* full_system.py: sOS + SYS_DRV + all four TAs executing in one runuser2026-09-23
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | "sOS + TAs running" was already claimed by boot_sos_and_tas, but that claim could not name a single TA. It classifies blocks by VA, and every TA runs at VA 0x400000 in its OWN address space, so its "TA/other=28 blocks" line cannot distinguish HDCP from DTM from RAS -- the VA-aliasing trap this tree documents elsewhere and then fell into here. Measured by (VA, live PA) instead, that run was HDCP 205 / DTM 9 / RAS 8 blocks, and ASD zero. ASD was the real gap. It is driver-class, its boot-time staging slot is gated off, and it arrives over the host ring -- which boot_sos_and_tas has no ring to do, and load_asd.py does only in isolation. This harness does both in one system: boot sOS (bl_stage2_task loads and verifies the boot modules), bring the ring up, then ring-load ASD. Attribution is two independent signals that must agree: address space (ASD at 0xD00000, TAs at 0x400000, SYS_DRV at 0xE00000, sOS below 0x300000) and the live physical page of each block, matched against staged image content. Content matching intersects several 48-byte slices because a single slice near a page start hits shared libc boilerplate and matches all five images. Result, deterministic across runs: sys_drv 532806 hdcp 204 (0x420e000, 0x420b000) dtm 9 (0x41f3000) ras 8 (0x41e0000, 0x41de000) asd 145 (5 pages) sOS 214934 4 modules loaded+verified at boot, ASD over the ring, 0 faults SKIP_ASD=1 is a control, and the first version of it was confounded: skipping the ring load also removed the run time that drain provided, so HDCP and DTM stopped executing too and the control proved nothing about ASD. Both paths now get an equal settle budget, and the control isolates cleanly -- only ASD flips to NO, RSA verifications drop 4 -> 3 (ASD's), exit 1.
* ASD loads, verifies and runs (harness/load_asd.py)user2026-09-22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The tree recorded ASD as "not loaded", gated off by an undecoded runtime flag, with the note that on hardware it arrives through the host-initiated load path "which needs the ring/mailbox model". That model exists now, so ASD is loaded through it. The boot-time gate, decoded. bl_stage2_task guards the +0x6F8000 staging slot: 00204a32 ldr r0, [r4, #4] 00204a34 ldr.w r0, [r0, #0x3e8] 00204a38 cmp r0, #0 00204a3a bge 0x204a76 ; >= 0 -> skip the ASD load entirely r4 is the global table at 0x2060E8, [r4+4] the state struct at 0x20E000, so the flag is VA 0x20E3E8. Measured at the branch it is 0x00000000 both times it is reached, and a write hook over the entire boot records ZERO writes to that word -- nothing on this path ever sets it, so it keeps its zeroed BSS value and the skip is unconditional. That also makes ASD's OVERSIZE staging line a red herring: the image is never handed to the loader, so the 0x30000 slot bound is never consulted. Loading it the way hardware does -- boot, ring init, ring command 1 with the image PA and length, the path already proven for HDCP: image: asd_full.bin 209152 bytes class body+0x14 = 0x5244 ('DR' driver) clean image ASD blocks=81 faults=0 RSA ops=3 ASD executes 81 distinct basic blocks in its own address space at 0xD00000, zero faults, after the firmware's own loader verified it on the CCP model. Deterministic: 81 blocks on repeated runs. Controls, since "it ran" is only meaningful if it could have failed: 1 bit flipped in signed body ASD blocks=0 1 bit flipped in signature ASD blocks=0 Both corrupted images execute ZERO ASD blocks, so the 81 are contingent on the real RSA-PSS check, not on the harness writing bytes into memory. The harness exits non-zero unless the positive control and both negatives hold. One fresh emulator per observation, because a rejected load disturbs ring/session state and reusing an instance makes later observations look dead for the wrong reason. Scope stated in the finding: this is ASD loaded and running, NOT ASD command handling. ASD is driver-class, not a TA, so it is not reached through TA_InvokeCommandEntryPoint and the 81 blocks are its load/init path. Driving its audited opcode surface needs its RPC dispatcher, which services.py still stubs (AsdRpcService returns 0) and which Bus can route into but is not wired to by default. That work is now unblocked rather than done: the real ASD is resident and running instead of absent. Regression: smoke, ccp_selftest, verify_real_image, boot_sos_full, boot_sos_and_tas, boot_and_mailbox all unchanged; fuzz_ta_invoke still exits 2 by design.
* Track the firmware images and keep the symbol maps alongside themPeter Geissler2026-09-22
| | | | | | | | | | | | | | | | | | | | | Adds 301 PSP/SMU firmware images (*.bin, *.elf, ~33 MB) that were previously gitignored. They are public material: the module images come from linux-firmware and publicly mirrored VBIOS dumps, and nothing was decrypted -- the encrypted on-flash stages (BOOT_LOADER#1, TRUSTED_OS) remain encrypted and unanalysed, so sOS is the earliest stage present. Checked the whole-flash dumps before publishing: they carry board SKU strings only (XFX D702_XTX / 113-31XFSHBS1), no serials, MACs or unique per-board identifiers. With the images tracked, the symbol maps in psp_out/phase3/, vdiff/, sigs/ and handover/symbols/ are now directly reproducible against the exact bytes they were derived from, and data/MANIFEST.sha256 still pins all 301 hashes. Still excluded: IDA databases (228 MB, regenerable and churn-prone), psp_out/decompiled/ (Hex-Rays output mechanically derived from AMD code), and AMD-internal register maps, which are vendor documents rather than public firmware.
* Initial import: AMD PSP reverse engineering, emulator and vulnerability researchPeter Geissler2026-09-22
Split out of a tinygrad working tree, where all of this lived untracked. tinygrad remains a dependency for hardware-facing scripts only. Contents: psp_emu/ Unicorn-based PSP emulator that boots the real signed firmware from the ARM reset vector: sOS -> SYS_DRV -> HDCP/DTM/RAS TAs, with a CCP crypto device model faithful enough to run the firmware's own drivers (RSA-PSS/SHA-256 container verification passes 5/5 with 5/5 negatives rejected). A simulated host drives the real mailbox/ring path through to TA_InvokeCommandEntryPoint. psp_out/ Static analysis: six PSP modules fully named (asd 1562, sys_drv 1141, sos 527, ras 119, hdcp 109, dtm 14) plus SMU 1033, a cross-version diffing pipeline over 34+ builds, per-handler annotated analysis and ~125 findings documents. Deliberately not tracked: AMD firmware images, the Hex-Rays decompilation derived from them, and IDA databases. data/MANIFEST.sha256 pins the SHA-256 of all 301 blobs results were derived from, so findings remain traceable to their inputs without redistributing AMD code. 6 MB tracked instead of 315 MB. Verified from the new location: test_smoke 5/5, ccp_selftest 11/11, verify_real_image 5/5 + 5/5 negatives, fuzz_ta_invoke controls passing and host-driven TA invoke working (0.73s per invoke).