code wiki / _hdl_build / nx_vc_fecrx_fuzz_gate.nx
nx_vc_fecrx_fuzz_gate.nx source
↩ module page · 245 lines · 12966 B
1// nx_vc_fecrx_fuzz_gate.nx -- ADVERSARIAL memory-safety proof for vc_fecrx_add, the FEC reassembly parser
2// on the LIVE family-video path (operator: "s class exceed ... permanent gains require pain"). Every shard
3// header field (block_id/idx/k/m/flen) is ATTACKER-CONTROLLED (a peer's bytes over the content-blind relay).
4// A green build shipping an exploitable parse is worse than none -> this PROVES no hostile shard can write
5// outside the caller regions. Method: allocate st/scratchA/scratchSh/out at the EXACT deployed-client sizes,
6// wrap each in 0xAA CANARY guard bands, throw 60000 hostile inputs + boundary cases + a real accumulate,
7// and assert EVERY guard byte is pristine after EVERY call. NEG-control proves the detector isn't tautological
8// (a deliberate guard poke MUST read as breached). Evidence -> knowledge/status/vc_fecrx_fuzz.log.
9// expect_exit: 0 license_tier: ORIGINAL
10import "nx_syscalls.nx"
11import "nx_video_client_wasm.nx"
12
13const GUARD: i64 = 8192
14const USABLE: i64 = 65536 // the deployed client's per-region size (0x10000 slots)
15const OUTCAP: i64 = 65280 // the client passes B(0xFF00); n*S bound -> S<=6528, flen<=52224
16
17func fp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
18func fn(v: i64) -> i64 {
19 let b: *u8=sys_mmap(28); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m}
20 let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}
21 var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
22func lcg(s: *i64) -> i64 { s[0]=(s[0]*1103515245+12345) & 0x7fffffff; return s[0] }
23
24// allocate GUARD | USABLE | GUARD; fill both guards with 0xAA; g[0]=lo-guard addr, g[1]=hi-guard addr.
25// returns the USABLE base address.
26func galloc(usable: i64, g: *i64) -> i64 {
27 let total: i64 = GUARD + usable + GUARD
28 let base: i64 = sys_mmap(total) as i64
29 let lo: *u8 = base as *u8
30 var i: i64 = 0
31 while i < GUARD { lo[i] = 0xAA as u8; i = i + 1 }
32 let hi: *u8 = (base + GUARD + usable) as *u8
33 i = 0
34 while i < GUARD { hi[i] = 0xAA as u8; i = i + 1 }
35 g[0] = base
36 g[1] = base + GUARD + usable
37 return base + GUARD
38}
39// 1 iff both guard bands are still all-0xAA.
40func gok(g: *i64) -> i64 {
41 let lo: *u8 = g[0] as *u8
42 let hi: *u8 = g[1] as *u8
43 var i: i64 = 0
44 while i < GUARD { if (lo[i] as i64) != 0xAA { return 0 } if (hi[i] as i64) != 0xAA { return 0 } i = i + 1 }
45 return 1
46}
47
48func main() -> i64 {
49 fp("=== nx_vc_fecrx_fuzz_gate: adversarial memory-safety of the LIVE FEC reassembly parser ===\n" as *u8)
50 let tbl: *i64 = sys_mmap(8 * 900) as *i64
51 vc_fec_init(tbl)
52
53 let g_st: *i64 = sys_mmap(16) as *i64
54 let g_sa: *i64 = sys_mmap(16) as *i64
55 let g_ss: *i64 = sys_mmap(16) as *i64
56 let g_out: *i64 = sys_mmap(16) as *i64
57 let st: *i64 = galloc(USABLE, g_st) as *i64
58 let scratchA: *i64 = galloc(USABLE, g_sa) as *i64
59 let scratchSh: *u8 = galloc(USABLE, g_ss) as *u8
60 let out: *u8 = galloc(USABLE, g_out) as *u8
61 let payload: *u8 = sys_mmap(70000)
62 let seed: *i64 = sys_mmap(16) as *i64
63 seed[0] = 20260702
64
65 var breaches: i64 = 0
66 var wild_rc: i64 = 0
67 var accepts: i64 = 0
68 var rejects: i64 = 0
69 var completes: i64 = 0
70 var iters: i64 = 0
71 vc_fecrx_reset(st)
72 while iters < 60000 {
73 if (lcg(seed) % 13) == 0 { vc_fecrx_reset(st) }
74 var i: i64 = 0
75 while i < 16 { payload[i] = (lcg(seed) & 0xff) as u8; i = i + 1 }
76 if (lcg(seed) % 3) == 0 { payload[6] = 8 as u8; payload[7] = 2 as u8 } // sometimes force k/m valid -> deeper paths
77 var plen: i64 = lcg(seed) % 4300
78 i = 16
79 while i < plen { if i < 70000 { payload[i] = (lcg(seed) & 0xff) as u8 } i = i + 1 }
80 let rc: i64 = vc_fecrx_add(st, tbl, payload, plen, scratchA, scratchSh, out, OUTCAP)
81 if rc == (0 - 1) { rejects = rejects + 1 } else { if rc == 0 { accepts = accepts + 1 } else { completes = completes + 1 } }
82 if rc < (0 - 1) { wild_rc = wild_rc + 1 }
83 if rc > 65536 { wild_rc = wild_rc + 1 }
84 if gok(g_st) == 0 { breaches = breaches + 1 }
85 if gok(g_sa) == 0 { breaches = breaches + 1 }
86 if gok(g_ss) == 0 { breaches = breaches + 1 }
87 if gok(g_out) == 0 { breaches = breaches + 1 }
88 iters = iters + 1
89 }
90 fp(" rand-fuzz: iters="); fn(iters); fp(" rejects="); fn(rejects); fp(" pending="); fn(accepts); fp(" complete="); fn(completes)
91 fp(" wild_rc="); fn(wild_rc); fp(" guard_breaches="); fn(breaches); fp("\n" as *u8)
92
93 // ---- STORE-PATH fuzz: VALID headers with adversarial idx/S pushed to the bounds, so store[idx*S+c] is
94 // actually exercised at every (idx in 0..9) x (S in 1..4096) incl the max corner. idx sometimes >=n
95 // (tests that reject too). This is the write the random fuzz never reached. ----
96 var s_accepts: i64 = 0
97 var s_iters: i64 = 0
98 seed[0] = 424242
99 vc_fecrx_reset(st)
100 while s_iters < 40000 {
101 if (lcg(seed) % 7) == 0 { vc_fecrx_reset(st) }
102 let SS: i64 = 1 + (lcg(seed) % 6528) // target S in 1..6528 (the new n*S<=65280 ceiling)
103 let flen2: i64 = 8 * SS - (lcg(seed) % 8) // flen s.t. (flen+7)/8 == SS (>0 for SS>=1)
104 let idx2: i64 = lcg(seed) % 12 // 0..11 -> exercises idx>=n reject too
105 var i2: i64 = 0
106 while i2 < 4 { payload[i2] = (lcg(seed) & 0xff) as u8; i2 = i2 + 1 } // random block_id
107 payload[4] = idx2 as u8
108 payload[5] = 0 as u8
109 payload[6] = 8 as u8
110 payload[7] = 2 as u8
111 payload[8] = (flen2 & 0xff) as u8
112 payload[9] = ((flen2 >> 8) & 0xff) as u8
113 payload[10] = ((flen2 >> 16) & 0xff) as u8
114 payload[11] = ((flen2 >> 24) & 0xff) as u8
115 payload[12] = 0 as u8; payload[13] = 0 as u8; payload[14] = 0 as u8; payload[15] = 0 as u8
116 let pl2: i64 = 16 + SS
117 i2 = 16
118 while i2 < pl2 { if i2 < 70000 { payload[i2] = (lcg(seed) & 0xff) as u8 } i2 = i2 + 1 }
119 let rc2: i64 = vc_fecrx_add(st, tbl, payload, pl2, scratchA, scratchSh, out, OUTCAP)
120 if rc2 != (0 - 1) { s_accepts = s_accepts + 1 }
121 if rc2 < (0 - 1) { wild_rc = wild_rc + 1 }
122 if gok(g_st) == 0 { breaches = breaches + 1 }
123 if gok(g_sa) == 0 { breaches = breaches + 1 }
124 if gok(g_ss) == 0 { breaches = breaches + 1 }
125 if gok(g_out) == 0 { breaches = breaches + 1 }
126 s_iters = s_iters + 1
127 }
128 fp(" store-fuzz: iters="); fn(s_iters); fp(" accepted(store-written)="); fn(s_accepts); fp(" guard_breaches="); fn(breaches); fp("\n" as *u8)
129
130 // ---- MAX-FRAME decode at the exact deployed ceiling: flen=32768 -> S=4096 -> k*S==outcap, n*S=40960.
131 // Feeds 8 shards -> the decode writes scratchSh up to 40959 + out up to 32767. If a guard survives here,
132 // the deployed 64KB scratch is safe at the largest possible frame (the corner an undersized caller breaks). ----
133 let mflen: i64 = 52224
134 let mS: i64 = vc_fecs_shard_size(mflen) // 6528 (n*S=65280==outcap, the exact ceiling)
135 let mframe: *u8 = sys_mmap(mflen + 64)
136 var mf: i64 = 0
137 while mf < mflen { mframe[mf] = ((mf * 97 + 13) & 255) as u8; mf = mf + 1 }
138 let msd: *u8 = sys_mmap(8 * mS + 64)
139 let mss: *u8 = sys_mmap(10 * mS + 64)
140 let mshards: *u8 = sys_mmap(10 * (16 + mS) + 128)
141 let mslot: i64 = vc_fecs_pack(tbl, mframe, mflen, 9001, msd, mss, mshards)
142 vc_fecrx_reset(st)
143 var mdone: i64 = 0
144 var msi: i64 = 0
145 while msi < 8 {
146 let mr: i64 = vc_fecrx_add(st, tbl, ((mshards as i64) + msi * mslot) as *u8, mslot, scratchA, scratchSh, out, OUTCAP)
147 if mr > 0 { mdone = mr }
148 if gok(g_st) == 0 { breaches = breaches + 1 }
149 if gok(g_ss) == 0 { breaches = breaches + 1 }
150 if gok(g_out) == 0 { breaches = breaches + 1 }
151 msi = msi + 1
152 }
153 var mexact: i64 = 0
154 if mdone == mflen { mexact = 1; var mq: i64 = 0; while mq < mflen { if out[mq] != mframe[mq] { mexact = 0; mq = mflen } else { mq = mq + 1 } } }
155 fp(" max-frame(S=4096): reconstructed="); fn(mdone); fp(" byte_exact="); fn(mexact); fp(" guard_breaches="); fn(breaches); fp("\n" as *u8)
156
157 // ---- boundary cases (deterministic) ----
158 var bad: i64 = 0
159 // helper inline via repeated pattern: set a clean header then tweak
160 // S=4096 boundary (flen 32761..32768 -> S=4096; k*S=32768==outcap, allowed) needs 8 valid shards to reach decode.
161 // here we only check single-shard SAFETY + return code, then the accumulate test proves the decode path.
162 // idx out of range
163 var j: i64 = 0
164 while j < 16 { payload[j] = 0 as u8; j = j + 1 }
165 payload[6] = 8 as u8; payload[7] = 2 as u8
166 payload[8] = 80 as u8 // flen = 80 -> S=10, plen must be 26
167 payload[4] = 255 as u8 // idx = 255
168 vc_fecrx_reset(st)
169 if vc_fecrx_add(st, tbl, payload, 26, scratchA, scratchSh, out, OUTCAP) != (0 - 1) { bad = bad + 1 }
170 if gok(g_st) == 0 { breaches = breaches + 1 }
171 // flen=0
172 payload[4] = 0 as u8; payload[8] = 0 as u8
173 vc_fecrx_reset(st)
174 if vc_fecrx_add(st, tbl, payload, 16, scratchA, scratchSh, out, OUTCAP) != (0 - 1) { bad = bad + 1 }
175 // S too big (flen=56000 -> S=7000 -> n*S=70000 > 65280 -> reject); plen matches 16+7000
176 payload[8] = (56000 & 0xff) as u8; payload[9] = ((56000 >> 8) & 0xff) as u8 // flen=56000 -> S=7000
177 vc_fecrx_reset(st)
178 if vc_fecrx_add(st, tbl, payload, 16 + 7000, scratchA, scratchSh, out, OUTCAP) != (0 - 1) { bad = bad + 1 }
179 if gok(g_ss) == 0 { breaches = breaches + 1 }
180 // plen mismatch (flen=80 -> S=10 -> need plen 26, send 40)
181 payload[8] = 80 as u8; payload[9] = 0 as u8
182 vc_fecrx_reset(st)
183 if vc_fecrx_add(st, tbl, payload, 40, scratchA, scratchSh, out, OUTCAP) != (0 - 1) { bad = bad + 1 }
184 fp(" boundary: unexpected_accepts="); fn(bad); fp("\n" as *u8)
185
186 // ---- happy path: real frame -> 8 of 10 shards -> byte-exact reconstruct (proves decode path safe + correct) ----
187 let flen: i64 = 11731
188 let frame: *u8 = sys_mmap(flen + 64)
189 var f: i64 = 0
190 while f < flen { frame[f] = ((f * 131 + 55) & 255) as u8; f = f + 1 }
191 let S: i64 = vc_fecs_shard_size(flen)
192 let sd: *u8 = sys_mmap(8 * S + 64)
193 let ss: *u8 = sys_mmap(10 * S + 64)
194 let shards: *u8 = sys_mmap(10 * (16 + S) + 64)
195 let slot: i64 = vc_fecs_pack(tbl, frame, flen, 7001, sd, ss, shards)
196 vc_fecrx_reset(st)
197 var done_flen: i64 = 0
198 var si: i64 = 0
199 while si < 8 { // feed first 8 shards (0..7) -> exactly k, reconstructs
200 let r: i64 = vc_fecrx_add(st, tbl, ((shards as i64) + si * slot) as *u8, slot, scratchA, scratchSh, out, OUTCAP)
201 if r > 0 { done_flen = r }
202 if gok(g_st) == 0 { breaches = breaches + 1 }
203 if gok(g_ss) == 0 { breaches = breaches + 1 }
204 if gok(g_out) == 0 { breaches = breaches + 1 }
205 si = si + 1
206 }
207 var exact: i64 = 0
208 if done_flen == flen {
209 exact = 1
210 var q: i64 = 0
211 while q < flen { if out[q] != frame[q] { exact = 0; q = flen } else { q = q + 1 } }
212 }
213 fp(" happy-path: reconstructed_flen="); fn(done_flen); fp(" byte_exact="); fn(exact); fp("\n" as *u8)
214
215 // ---- NEG-control: the canary detector MUST catch a real corruption (not tautological) ----
216 let lo: *u8 = g_st[0] as *u8
217 lo[10] = 0 as u8
218 var neg: i64 = 0
219 if gok(g_st) == 0 { neg = 1 }
220 lo[10] = 0xAA as u8 // restore
221 fp(" neg-control: detector_fires_on_poke="); fn(neg); fp("\n" as *u8)
222
223 var green: i64 = 1
224 if breaches != 0 { green = 0 }
225 if wild_rc != 0 { green = 0 }
226 if bad != 0 { green = 0 }
227 if exact != 1 { green = 0 }
228 if mexact != 1 { green = 0 } // max-frame corner reconstructed
229 if s_accepts < 1000 { green = 0 } // the store-path fuzz MUST have actually exercised the write path
230 if neg != 1 { green = 0 }
231
232 let lf: i64 = sys_openat_append("knowledge/status/vc_fecrx_fuzz.log" as *u8, 420)
233 if lf >= 0 {
234 fp("VCFECRXFUZZ iters=60000 breaches="); // also to log
235 let w: i64 = lf
236 sys_write(w, "VCFECRXFUZZ iters=60000 breaches=" as *u8, 33)
237 let nb: *u8=sys_mmap(28); var mm: i64=breaches; var kk: i64=0; if mm==0{nb[0]=48 as u8;kk=1} while mm>0{nb[kk]=(48+(mm%10)) as u8;mm=mm/10;kk=kk+1} var zz: i64=0; let ob: *u8=sys_mmap(28); while zz<kk{ob[zz]=nb[kk-1-zz];zz=zz+1} sys_write(w, ob, kk)
238 if green==1 { sys_write(w, " exact=1 neg=1 verdict=GREEN\n" as *u8, 28) } else { sys_write(w, " verdict=RED\n" as *u8, 12) }
239 sys_close(lf)
240 }
241 fp("VC-FECRX-FUZZ-GATE breaches="); fn(breaches); fp(" wild="); fn(wild_rc); fp(" boundary_bad="); fn(bad)
242 if green==1 { fp(" verdict=GREEN -- no hostile shard escaped the caller regions; deployed config memory-safe\n" as *u8); return 0 }
243 fp(" verdict=RED -- a hostile input breached a guard OR the happy path broke\n" as *u8)
244 return 1
245}