LEAD: use the anti-rollback gap to make the confirmed count-underflow reachable
Status: CLOSED NEGATIVE on its central hypothesis. The rollback does not make the count-underflow reachable. Retained because the reasoning and artifacts are reusable, and because the rollback finding itself stands independently.
Why this lead exists
Two separate results now sit next to each other:
-
A confirmed corruption defect that is not reachable.
sub_E04B68(and clonesub_E04DFC) read a count frombuf+0x88unvalidated, use it unclamped formemcpy(glob+0x6c0, buf+8, count), then compute0x400 - countunsigned for a second copy. Verified 14/14 mechanically and reproduced in emulation through the real dispatcher. Not host-reachable in 49.0.54: planting the count needs0x8cbytes into the0x33descriptor helper (sub_E1EA54->sub_E18EAC, sole writer ofchannel+0x70), and no corpus TA delivers that much - OC0x30is a firmware global, AUC/OPM/FP give0x10, GCP is auth-gated, MERIT gated. (fw/CANDIDATE-SYSDRV-E04B68-COUNT-UNDERFLOW.md) -
No anti-rollback. An older AMD-signed SYS_DRV boots and services requests on a part shipping 49.0.54 - 49.0.37 and 49.0.47 both verified from a cold power cycle. (
fw/FINDING-PSP-SYSDRV-NO-ANTIROLLBACK.md)
The defect's unreachability is a property of one specific build's gates, and rollback lets the attacker choose the build. So the question is precise:
In 49.0.37 or 49.0.47, does any path deliver >=
0x8ccaller-controlled bytes into the payload helper that writes the slot staging buffer - is the front half open in an older build?
If yes, rollback plus the existing defect is an exercisable memory-corruption primitive: choose the old build, open the front half, plant the count, trigger the unclamped copy.
Closed: the required payload does not shrink in an older build
First, a correction to this lead's own logic. The 0x8c requirement is TA-side - how
many caller-controlled bytes a TA pushes into the payload helper - and TA choice is already
free, since 63 corpus TA builds load on this part and the front-half survey covered all of
them. So rolling back SYS_DRV only helps if the older build needs a smaller payload,
i.e. reads the count at a lower offset.
It does not. Scanning both older images for every LDR.W rD,[rN,#imm12], grouped by
immediate:
| build | LDR.W sites | distinct immediates | sites with imm = 0x88 |
|---|---|---|---|
| 49.0.37 | 923 | 260 | 15 |
| 49.0.47 | 925 | 265 | 14 |
Those sites cluster at file offsets 0x49e8, 0x4a10 and 0x4c7a-0x4cd8 (v37; v47
identical shifted +0xc). At the established load base 0xE00100, the two defective
functions in the current build sit at file offsets 0x4A68 (sub_E04B68) and 0x4CFC
(sub_E04DFC) - the same two clusters. The count is read at +0x88 in the older builds
too, so the payload needed is still 0x8c and the front-half blocker is unchanged.
Caveat on strength: the offset-to-function mapping is inferential (base arithmetic plus
cluster position), not a confirmed symbolisation of the older images. The conclusion therefore
rests on the weaker, safer claim that +0x88 count reads are still present in the same
region of both older builds, so there is no evidence the requirement shrank - and a lead
needs positive evidence to stay open.
What would still be needed (if resumed)
- Load
data/rollback/sysdrv_v37.binandsysdrv_v47.bin, taking the load base from the segment table, never from a printed address (the 0x100 trap; current build is0xE00100). - Re-run the validated detectors (
fw/ta_copylen_slice.py,fw/ta_bufferfield_audit.py,fw/ta_bufferfield_xfn.py) and confirm each rediscovers a known defect in that image before trusting any negative from it. - Locate the older equivalents of
sub_E087E4(request entry),sub_E1DC30(53-opcode family),sub_E1EA54/sub_E18EAC(the0x33payload helper) and compare the length gate. - Also check whether
sub_E04B68's count read is already clamped in an older build, which would invert the picture.
Both images are plaintext - entropy 6.74 / 6.77 over the body versus ~8.0 for encrypted - so they are directly analyzable.
Honest caveats
- The defect shape was found in all 31 SYS_DRV builds, so the back half is presumably open in the older ones - but that must be confirmed per image, not assumed.
- A v37/v47 string diff shows no added error messages, so there is no cheap signal that a bounds fix landed in that window; this needs real code comparison.
- Rollback changes which SYS_DRV runs. The front-half blocker is partly about what TAs send, and TAs load separately - so the thing to look for is an older SYS_DRV with a laxer gate, not an older TA.
Artifacts
data/rollback/sysdrv_v37.bin (0x310025, 157,584 B, sha 8ff372e135a0342b8d3b...) and
data/rollback/sysdrv_v47.bin (0x31002f, 157,584 B, sha 1ec6756ce3e37cea207b...), both
hashed into data/MANIFEST.sha256, extracted from public linux-firmware psp_13_0_0_sos.bin
by hw/rollback_inspect.py.
