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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! Regression guard: a Plex count read from the wire must never drive an
//! unbounded allocation.
//!
//! Found by the CI fuzz run. AddressSanitizer aborted the `rdd29` target with:
//!
//! ```text
//! ==5560==ERROR: AddressSanitizer: out of memory:
//! allocator is trying to allocate 0x37cbb80000 bytes
//! ```
//!
//! `0x37cbb80000` is 239.8 GB. `ATMOSFrame.SubElementCount` is a Plex field
//! read straight from the input, so it is attacker-controlled and effectively
//! unbounded — Plex escalates 8 → 16 → 32 bits, so twelve bytes encode a count
//! of `0x7FFF_FFFF`. `Vec::with_capacity` then reserved that many elements.
//!
//! Every sub-element consumes at least one byte of the body, so the count can
//! never legitimately exceed the bytes remaining, so the parser **rejects** an
//! impossible count outright rather than capping the reserve -- capping is
//! untestable here, because `Vec::with_capacity(2^31)` succeeds under ordinary
//! overcommit and only a sanitizer notices. `BedDefinition1.ChannelCount` had
//! the identical hazard and the identical fix, with its own ceiling of
//! `remaining_bits / 15` (a channel description costs at least 15 bits).
//!
//! These inputs are malformed and must fail to parse — the point is that they
//! fail *without attempting the allocation first*. A test process that
//! survives is the assertion.
use Parse;
use ;
/// The exact shape the fuzzer found, reconstructed from the format rather than
/// copied from a crash artifact.
///
/// ```text
/// 08 ElementID = ATMOSFrame
/// 0a ElementSize = 10 (the body below)
/// 00 ATMOSVersion
/// 00 SampleRate | BitDepth | FrameRate
/// 00 MaxRendered = 0
/// ff ff ff 7f ff ff ff SubElementCount: Plex escalates 8 -> 16 -> 32,
/// decoding to 0x7FFF_FFFF = 2_147_483_647
/// ```
///
/// At ~112 bytes per `AnyElement` that reserve is ~240 GB, matching the
/// sanitizer's figure.
///
/// MUTATION VERIFIED: reverting `atmos_frame.rs` to
/// `Vec::with_capacity(sub_element_count as usize)` makes this test fail —
/// the reserve succeeds under overcommit, the parse loop hits the first
/// (absent) sub-element, and the error is a `Bits` out-of-bounds on
/// `ElementID` rather than the expected `InvalidValue` on `SubElementCount`.
/// The same hazard reached through the arbitrary short inputs the fuzzer
/// actually explores, including every prefix of the crafted frame above —
/// with **real** assertions, not just "the process survived" (which only a
/// sanitizer could ever fail). Every prefix of the crafted frame is
/// malformed (truncated before the huge count's terminal 32-bit value), so it
/// must all return `Err` — none may parse successfully, because a success
/// would mean the huge `SubElementCount` was accepted and the body reserve
/// driven from it.
/// `BedDefinition1.ChannelCount` has the identical Plex hazard as
/// `ATMOSFrame.SubElementCount`, but the fix is a **tight** provable ceiling:
/// each channel consumes at least 15 bits (Plex(4) `ChannelID` + Plex(8)
/// `AudioDataID` + 3 reserved bits), so `remaining_bits / 15` — not
/// `remaining_bits` — is the most channels the element can possibly hold.
///
/// This input declares 8 channels in a 112-bit element. After the 13-bit
/// header (Plex(8) MetaID = 0x00, 1 reserved bit, Plex(4) ChannelCount = 8)
/// there are 99 bits left, whose provable ceiling is `99 / 15 = 6`. The count
/// 8 sits strictly between that ceiling and the raw remaining bits (8 <= 99),
/// so:
///
/// * the `/ 15` bound REJECTS it as `InvalidValue` (this test's assertion), and
/// * a **loose** `remaining_bits` bound lets it through — the parser then reads
/// the 8 channels from only 99 bits and fails mid-loop with an unrelated bit
/// error (or, for a genuinely huge Plex count that the loose bound also
/// admits when the element is large, reserves unboundedly).
///
/// MUTATION VERIFIED, recorded verbatim: reverting `bed_definition.rs` to
/// `channel_count > remaining_bits` (the loose first-round bound) makes this
/// test FAIL with:
///
/// 8 channels in a 112-bit element (provable ceiling 6) must be rejected as an invalid ChannelCount, got Err(Bits { what: "BedDefinition1.AudioDataID", source: OutOfBounds { needed_bits: 8, remaining_bits: 5 } })
///
/// — the parser runs past the impossible reserve and dies mid-channel with an
/// unrelated bit error instead of rejecting the count by name. Restoring
/// `/ 15` (and a `touch`) makes it pass again.