1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
# 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:
1. **A confirmed corruption defect that is not reachable.** `sub_E04B68` (and clone
`sub_E04DFC`) read a count from `buf+0x88` unvalidated, use it unclamped for
`memcpy(glob+0x6c0, buf+8, count)`, then compute `0x400 - count` **unsigned** 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 needs `0x8c` bytes into the `0x33`
descriptor helper (`sub_E1EA54` -> `sub_E18EAC`, sole writer of `channel+0x70`), and **no
corpus TA delivers that much** - OC `0x30` is a firmware global, AUC/OPM/FP give `0x10`,
GCP is auth-gated, MERIT gated. (`fw/CANDIDATE-SYSDRV-E04B68-COUNT-UNDERFLOW.md`)
2. **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 >= `0x8c` caller-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.bin` and `sysdrv_v47.bin`, taking the load base **from the
segment table, never from a printed address** (the 0x100 trap; current build is `0xE00100`).
* 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` (the `0x33` payload 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`.
|