nx_json_adversarial_test.nx source
↩ module page · 99 lines · 3325 B
1// nx_json_adversarial_test.nx -- Phase A5 of S-class hardening.
2//
3// Adversarial fuzzing of nx_json_next, the tokenizer the substrate
4// uses to parse Moonraker HTTP responses + any other JSON-bearing
5// input. Even though Moonraker is on the LAN, defense-in-depth: a
6// malformed JSON byte stream must not crash the tokenizer or read
7// past the buffer.
8//
9// expect_exit: 0
10// license_tier: ORIGINAL
11
12import "nx_syscalls.nx"
13import "nx_json.nx"
14
15// Drain a tokenizer: advance until EOF or ERROR. Returns:
16// 1 if tokenizer reached EOF cleanly
17// 2 if tokenizer hit ERROR
18// 3 if more than 1024 iterations (would indicate infinite loop)
19func drain_tok(t: *NxJsonTok) -> i64 {
20 var iters: i64 = 0
21 while iters < 1024 {
22 let k: i64 = nx_json_next(t)
23 if k == NX_JSON_EOF { return 1 }
24 if k == NX_JSON_ERROR { return 2 }
25 iters = iters + 1
26 }
27 return 3 // possible infinite loop
28}
29
30func main() -> i64 {
31 // ===== (a) Empty input -> reaches EOF immediately =====
32 let empty: *u8 = sys_mmap(4)
33 let t_empty: *NxJsonTok = nx_json_new(empty, 0)
34 let r_empty: i64 = drain_tok(t_empty)
35 if r_empty != 1 { return 10 }
36
37 // ===== (b) All NUL bytes -> EOF or ERROR (NOT infinite loop) =====
38 let nul_buf: *u8 = sys_mmap(64)
39 let t_nul: *NxJsonTok = nx_json_new(nul_buf, 64)
40 let r_nul: i64 = drain_tok(t_nul)
41 if r_nul == 3 { return 20 } // infinite-loop guard
42
43 // ===== (c) All 0xFF bytes -> EOF or ERROR (NOT infinite) =====
44 let ff_buf: *u8 = sys_mmap(64)
45 var fi: i64 = 0
46 while fi < 64 {
47 ff_buf[fi] = 0xff
48 fi = fi + 1
49 }
50 let t_ff: *NxJsonTok = nx_json_new(ff_buf, 64)
51 let r_ff: i64 = drain_tok(t_ff)
52 if r_ff == 3 { return 30 }
53
54 // ===== (d) Valid JSON object -> drains without ERROR =====
55 let good: *u8 = sys_mmap(64)
56 let s: *u8 = "{\"a\":1,\"b\":true,\"c\":null}"
57 var n: i64 = 0
58 while s[n] != 0 { n = n + 1 }
59 var k: i64 = 0
60 while k < n { good[k] = s[k]; k = k + 1 }
61 let t_good: *NxJsonTok = nx_json_new(good, n)
62 let r_good: i64 = drain_tok(t_good)
63 if r_good != 1 { return 40 }
64
65 // ===== (e) Unclosed string -> ERROR (NOT infinite) =====
66 let unclosed: *u8 = sys_mmap(64)
67 let s_u: *u8 = "\"never closed"
68 var nu: i64 = 0
69 while s_u[nu] != 0 { nu = nu + 1 }
70 var ku: i64 = 0
71 while ku < nu { unclosed[ku] = s_u[ku]; ku = ku + 1 }
72 let t_unclosed: *NxJsonTok = nx_json_new(unclosed, nu)
73 let r_unclosed: i64 = drain_tok(t_unclosed)
74 if r_unclosed == 3 { return 50 } // not infinite
75
76 // ===== (f) Lone garbage chars -> EOF or ERROR =====
77 let junk: *u8 = sys_mmap(64)
78 junk[0] = 0x40 // '@'
79 junk[1] = 0x23 // '#'
80 junk[2] = 0x25 // '%'
81 junk[3] = 0x5E // '^'
82 let t_junk: *NxJsonTok = nx_json_new(junk, 4)
83 let r_junk: i64 = drain_tok(t_junk)
84 if r_junk == 3 { return 60 }
85
86 // ===== (g) Deeply nested array -- shouldn't blow up tokenizer =====
87 // (Tokenizer is stateless; parser/validator handles depth.)
88 let deep: *u8 = sys_mmap(256)
89 var di: i64 = 0
90 while di < 100 {
91 deep[di] = 0x5B // '['
92 di = di + 1
93 }
94 let t_deep: *NxJsonTok = nx_json_new(deep, 100)
95 let r_deep: i64 = drain_tok(t_deep)
96 if r_deep == 3 { return 70 }
97
98 return 0
99}