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
|
# Command-sequence / state-confusion audit — HDCP
Investigated the state/ordering axis the two confirmed bugs open up. Result: a
real LOGIC bug found and characterised, but no memory-corruption primitive.
## Command map (hdcp_invoke_entry @0x4013B4)
cmd 1 open ; 2 close/FREE (sub_4019D4 memclr) ; 3 rx-info ; 4 ; 5 ; 6 ; 7 ;
9 FREE (sub_401F6C memclr) ; 0xB ; 0xC ; 0xE open/BYPASS ; 0xF subcmd dispatch ;
0x10 ; 0x11 ; 0x12 (->ASD 0x308) ; 0x13.
## Structural facts established
* All 4 session-table base globals (dword_401D44/4020DC/40237C/4034DC) resolve to
the SAME table 0x407000 -> no base/aliasing confusion. cmd 0xE's negative-offset
addressing is just compiler codegen, same table.
* Scan for a session field used as a POINTER deref or a memcpy SIZE: EMPTY. The
session struct has no pointer fields and no cross-command length field
(rx_count is set and consumed only inside subcmd12). So there is nothing to
"confuse" into a wild pointer or oversized copy across commands.
* Free path sub_4019D4 tears down ASD state by DEVID: sub_4043D2 -> ASD 0x189(devid),
sub_4046D8 -> ASD 0x160(devid); plus sub_4044BE -> ASD 0x18F(&slot+0x40). Open
sets up via ASD 0x180-0x184 / 0x1A0. ASD topology is keyed by devid.
## The logic bug: duplicate devid + asymmetric ASD teardown
Neither cmd 1 nor cmd 0xE checks devid uniqueness -- both just scan for a slot
with active==0. So the SAME devid can occupy multiple HDCP slots, while ASD keeps
one devid-keyed entry. Freeing one slot (cmd 2) tears down that shared ASD entry,
leaving the other slot(s) referencing torn-down ASD state.
Confirmed on hardware (probe_stateconf.py):
open devid=0x66 -> slotA=2
open devid=0x66 -> slotB=3 (duplicate accepted, distinct slot)
close slotA=2 -> ret=1 (frees + ASD 0x189/0x160 teardown for devid 0x66)
subcmd12(slotB) -> ret=17 sub=109 (== the control; NO change)
double-free slotA -> ret=1 (no crash)
crash oracle all-zero, sOS alive throughout.
## Why no corruption materialised
* The surviving slot behaves identically to a control slot: the ASD teardown of
devid D returns an error to the survivor's later ASD RPCs rather than
dereferencing freed memory -- ASD uses FIXED BSS tables (entry-clearing, not a
heap free), so a torn-down devid is a zeroed/absent entry, handled as
"not found", not a dangling pointer.
* Without a real HDCP receiver the opens return 17 (topology query fails); the
sessions never fully establish, so the ASD-state-dependent paths in subcmd12
(asd_rpc_1a2 at line 65, gated by flag_24d; asd_rpc_1a3 at line 167, gated by
f40/f44) are not exercised on the survivor. Reaching them would need the
branch-B chain (set flag_24d, then subcmd12), whose expected outcome is still an
ASD "device not found" error, not corruption.
## Net
The bypass genuinely opens the subcommand+ASD parser tree, and there IS a
state-machine bug (duplicate devid, asymmetric teardown, missing uniqueness
check, no-op double-free). But it does not convert to memory corruption: the
session has no cross-command pointer/length state to confuse, and the ASD side
is fixed-table (no heap UAF). This axis is exhausted for memory-corruption; the
duplicate-devid issue stands as a logic/robustness bug only.
|