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
|
# How powerful are the GCP defects? A capability assessment
Honest separation of what is demonstrated on silicon from what the code establishes but the
hardware cannot yet show.
## Proven on hardware (Navi 31, stock firmware)
| capability | evidence |
|---|---|
| **Handle disclosure** — obtain a valid handle for a crypto session you did not create, by querying with zeros | `FE0F` zero query returned the live session's handle `0x1` |
| **Unauthorised destroy** — destroy that session | `FE0D` with the disclosed handle returned status 0 |
| **Repeatable destroy** — keep destroying the dead slot, decrementing the shared refcount each time | `FE0D` accepted again after the destroy |
| **Acquire-gate bypass** — create crypto sessions although the ASD acquire never succeeded | `FE0C` #1 refused `0x2000002f`, #2 and #3 returned 0 |
On their own these are **denial of service plus state desync**. Not memory corruption (the
handle is rebound on slot reuse, so no UAF), not privilege escalation.
## The real ceiling: a stolen handle is accepted by the *key-using* commands
The interesting question is not what the refcount does, it is **what else accepts a handle**.
Surveying every GCP command that takes `params->arg10` as a session handle:
| command | state required | what it does with the session |
|---|---|---|
| `FE0D` DestroyCryptoSession | none | destroy — **proven reachable with a stolen handle** |
| `FE0E` KeyExchangeCryptoSession | **1** | key exchange — and state 1 is exactly what `FE0C` leaves |
| `FE02` GetObfKeyCryptoSession | **2** | **operates under the session's key** (below) |
| `FE10`/`FE11` Start/FinishKeyRefresh | **2** | key refresh on that session |
`FE02` is the one that matters. Its gate is `ctx->crypto[HIBYTE(arg10)].state != 2 -> 801`
(the `0x321` seen on hardware), plus a host-supplied length in 1..16 and a buffer that must
compare equal to zeros. It then loads `ctx->crypto[idx].rest` — the session's key material —
into a SYS_DRV crypto context and performs an operation on host-supplied input:
```c
gcp_sysdrv_rpc_30(..., 128, &a1) // allocate a crypto context
v16[1] = ctx->crypto[v7].rest; // the VICTIM session's key
gcp_sysdrv_rpc_33(a1, &v16, 1) // load that key
gcp_sysdrv_rpc_1(&v17, ...); rpc_3(v17, a1); rpc_5(v17, 0, 0)
gcp_sysdrv_rpc_7(v17, v2, params->data20[20], v20) // operate on HOST input -> HOST output
```
**The attacker never has to reach state 2 themselves — the victim's live session already is
in it.** So the chain is:
1. `FE0F` with a zero query -> a handle for someone else's crypto session;
2. `FE02` with that handle -> GCP performs a crypto operation **under that session's key**,
on attacker-chosen input, returning the result to the attacker.
That is a **key-use oracle against another client's content-protection session**, which is
categorically stronger than the DoS the refcount bugs give on their own. GCP is the content
protection TA, so the asset at risk is protected-content key material, not kernel integrity.
## What is NOT established, stated plainly
* **Not demonstrated on our card.** It needs a victim session in state 2, which requires
`FE0E` key exchange to succeed, which needs the ASD/DRM material that blocks every other
gated result here. We can create state-1 sessions only.
* **The exact operation `rpc_7` performs** (decrypt, wrap, or MAC) has not been traced, so
"key-use oracle" is the correct description and "key extraction" is not.
* **Multi-client exposure is an assumption.** The attack matters if a real system has GCP
sessions belonging to different trust domains concurrently — which is the normal case for
protected playback, but we have not observed it.
* The refcount desync itself buys nothing dramatic: the decrement is guarded by `CBZ` so it
cannot underflow, and inflating it by repeated failed `FE0C` only delays an acquire.
## Verdict
The refcount bugs alone: **unprivileged cross-client DoS against protected playback**, plus
state desync — real, modest, and fully proven.
Their value is as an **enabler**: they hand out valid handles for sessions the caller does not
own, and GCP's key-using commands gate on nothing but the handle and the session's own state.
The severity of the set therefore rests on `FE02`, and the one missing link is a victim
session in state 2 — an access problem, not an analysis problem.
|