code wiki / (root) / nx_content_get_gate.nx

nx_content_get_gate.nx source

↩ module page · 326 lines · 15714 B

1// nx_content_get_gate.nx -- THE GATE FOR THE NAS->LAPTOP DOOR, 2026-09-03. 2// 3// SUBJECT: the BUILT nx_content_get elf, forked end-to-end. Its verbs are the whole contract, so an 4// in-process gate could not test the thing that matters (argv parsing, exit codes, the wire receipt). 5// argv[1] overrides the subject path so nx_gate_bite can hand it a mutant. 6// 7// THE TEETH THAT CARRY THE CLAIM ARE T4/T5 AND T10, and each is a law this estate has been bitten by: 8// T4 IS A FIXTURE ASSERTION, NOT AN OUTCOME. It proves the big fixture actually forced nchunks>1 9// BEFORE T5 judges reassembly. Without it, a subject that fits in one chunk would let T5 pass 10// while the multi-chunk path -- the only path that can corrupt -- was never executed. The 11// single-chunk case looks identical to a working transfer from the outside. 12// T10 IS THE POSITIVE CONTROL FOR THE REFUSALS. T7/T8/T9 all assert a REFUSAL, and a guard that 13// refuses EVERYTHING passes every one of them. T10 demands a legitimate path be ACCEPTED, so 14// the deny-tests can only pass on a guard that actually discriminates. 15// 16// T3 uses the gate's OWN one-shot sha256_digest against the tool's STREAMING sha256_update path -- 17// genuinely different code, so it is a cross-check rather than the subject grading itself. 18// T2 re-reads chunk_raw FROM THE PROBE rather than re-deriving it here: re-deriving would install a 19// second ruler that drifts the moment the reserve changes. 20// 21// Teeth, in order: 22// T1 the probe partition RECONCILES: skel+pathcap+digits+shahex == reserve. 23// T2 chunk_raw is positive and an exact multiple of 3 (so base64 emits no interior padding). 24// T3 begin's whole-file digest equals an INDEPENDENTLY computed digest of the same bytes. 25// T4 FIXTURE ASSERTION: the large fixture forces nchunks > 1. 26// T5 multi-chunk reassembly is byte-identical to the original. 27// T6 the partition SUMS: the per-chunk raw sizes total exactly total_bytes. 28// T7 NEG-CONTROL: a path-traversal source is REFUSED (exit 4). 29// T8 NEG-CONTROL: a source outside the allowlist is REFUSED (exit 4). 30// T9 NEG-CONTROL: credential material is REFUSED (exit 4). 31// T10 POSITIVE CONTROL: an allowlisted source is ACCEPTED -- without this T7/T9 pass on a guard 32// that refuses everything. 33// T11 an index past end of file is a RANGE refusal (exit 5), distinct from a source refusal. 34// MEASURED 11/11 GREEN 2026-09-03 on the laptop, bite-proven killed=1 with the source and the 35// deployed subject both restored byte-identical (12665 / 40212 bytes). 36// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 37import "nx_syscalls.nx" 38import "nx_gate_verdict.nx" 39import "nx_tool_run.nx" 40import "nx_base64.nx" 41import "nx_sha256.nx" 42 43// THE SUBJECT PATH IS RESOLVED BY STAT, NEVER ASSUMED. The same build lands at a different relative 44// path depending on the CWD of whoever forks the gate -- the estate measured that hidden variable 45// giving one command opposite effects. So every candidate is probed and the one taken is ANNOUNCED. 46// If none exists the gate ABSTAINS: a fork of a missing elf exits 127, which is indistinguishable 47// from a subject that ran and failed, and convicting a subject you could not reach indicts the wrong 48// thing. "I could not look" is not "it is broken". 49const CGG_SUBJECT: *u8 = "buildroot/_build/nx_content_get.sov.elf" as *u8 50const CGG_SUBJ_B: *u8 = "_build/nx_content_get.sov.elf" as *u8 51const CGG_SUBJ_C: *u8 = "_offc/nx_content_get.elf" as *u8 52const CGG_SUBJ_D: *u8 = "nx_content_get.elf" as *u8 53const CGG_DIR: *u8 = "/tmp/cgget" as *u8 54const CGG_SMALL: *u8 = "/tmp/cgget/small.bin" as *u8 55const CGG_BIG: *u8 = "/tmp/cgget/big.bin" as *u8 56const CGG_CAP: i64 = 220000 57const CGG_DIGEST: i64 = 32 58const CGG_SHAHEX: i64 = 64 59const CGG_SMALL_N: i64 = 4096 60const CGG_BIG_EXTRA: i64 = 3000 61const CGG_MODE: i64 = 420 62 63func cgg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 64 65// find `needle` in buf[0..n); returns index just past it, or -1. Loop exits on a FLAG, never by 66// clobbering the cursor -- the eol-sentinel defect this estate wrote four times in one day. 67func cgg_find(buf: *u8, n: i64, needle: *u8) -> i64 { 68 let m: i64 = cgg_slen(needle) 69 if m == 0 { return 0 - 1 } 70 var i: i64 = 0 71 var hit: i64 = 0 - 1 72 while i + m <= n { 73 var j: i64 = 0 74 var same: i64 = 1 75 while j < m { 76 if buf[i + j] != needle[j] { same = 0; j = m } else { j = j + 1 } 77 } 78 if same == 1 { if hit < 0 { hit = i + m } } 79 i = i + 1 80 } 81 return hit 82} 83func cgg_int_after(buf: *u8, n: i64, key: *u8) -> i64 { 84 let p: i64 = cgg_find(buf, n, key) 85 if p < 0 { return 0 - 1 } 86 var i: i64 = p 87 var v: i64 = 0 88 var got: i64 = 0 89 var go: i64 = 1 90 while go == 1 { 91 if i >= n { go = 0 } else { 92 let c: i64 = buf[i] as i64 93 if c < 48 { go = 0 } else { 94 if c > 57 { go = 0 } else { v = v * 10 + (c - 48); got = 1; i = i + 1 } 95 } 96 } 97 } 98 if got == 0 { return 0 - 1 } 99 return v 100} 101func cgg_hex_into(d: *u8, out: *u8) -> i64 { 102 var i: i64 = 0 103 while i < CGG_DIGEST { 104 let v: i64 = d[i] as i64 105 let hi: i64 = (v >> 4) & 15 106 let lo: i64 = v & 15 107 if hi < 10 { out[i * 2] = (48 + hi) as u8 } else { out[i * 2] = (87 + hi) as u8 } 108 if lo < 10 { out[i * 2 + 1] = (48 + lo) as u8 } else { out[i * 2 + 1] = (87 + lo) as u8 } 109 i = i + 1 110 } 111 out[CGG_SHAHEX] = 0 as u8 112 return 0 113} 114// compare the 64 hex chars at buf[pos..] against `hex` 115func cgg_hex_eq(buf: *u8, n: i64, pos: i64, hex: *u8) -> i64 { 116 if pos < 0 { return 0 } 117 if pos + CGG_SHAHEX > n { return 0 } 118 var i: i64 = 0 119 while i < CGG_SHAHEX { 120 if buf[pos + i] != hex[i] { return 0 } 121 i = i + 1 122 } 123 return 1 124} 125 126func cgg_write_file(path: *u8, buf: *u8, n: i64) -> i64 { 127 let fd: i64 = sys_openat_wr(path, CGG_MODE) 128 if fd < 0 { return 0 - 1 } 129 var off: i64 = 0 130 var go: i64 = 1 131 while go == 1 { 132 if off >= n { go = 0 } else { 133 let w: i64 = sys_write(fd, (buf as i64 + off) as *u8, n - off) 134 if w <= 0 { go = 0 } else { off = off + w } 135 } 136 } 137 sys_close(fd) 138 return off 139} 140 141func cgg_exists(path: *u8) -> i64 { 142 let fd: i64 = sys_openat_rd(path) 143 if fd < 0 { return 0 } 144 sys_close(fd) 145 return 1 146} 147func cgg_resolve() -> *u8 { 148 if cgg_exists(CGG_SUBJECT) == 1 { return CGG_SUBJECT } 149 if cgg_exists(CGG_SUBJ_B) == 1 { return CGG_SUBJ_B } 150 if cgg_exists(CGG_SUBJ_C) == 1 { return CGG_SUBJ_C } 151 if cgg_exists(CGG_SUBJ_D) == 1 { return CGG_SUBJ_D } 152 return 0 as *u8 153} 154 155func cgg_run(subj: *u8, a1: *u8, a2: *u8, a3: *u8, out: *u8, ol: *i64) -> i64 { 156 let av: *i64 = sys_mmap(64) as *i64 157 av[0] = subj as i64 158 av[1] = a1 as i64 159 var k: i64 = 2 160 if a2 as i64 != 0 { av[2] = a2 as i64; k = 3 } 161 if a3 as i64 != 0 { av[3] = a3 as i64; k = 4 } 162 av[k] = 0 163 return tr_run_capture(subj, av, out, CGG_CAP, ol) 164} 165 166func main(argc: i64, argv: *i64) -> i64 { 167 let ctr: *i64 = gv_ctr() 168 gv_head("nx_content_get gate -- the NAS->laptop door: the multi-chunk path, the partition, and a guard that must not refuse everything" as *u8) 169 170 var subj: *u8 = cgg_resolve() 171 if argc > 1 { subj = argv[1] as *u8 } 172 if subj as i64 == 0 { 173 gv_need("a-built-nx_content_get-artifact-on-any-known-path" as *u8, 0, ctr) 174 return gv_verdict("content_get" as *u8, ctr, "ABSTAINED: no built subject found on any candidate path, so nothing was measured -- a fork of a missing elf exits 127 and would have convicted a subject that never ran" as *u8) 175 } 176 gv_puts(" subject resolved by stat: " as *u8); gv_puts(subj); gv_puts("\n" as *u8) 177 178 sys_mkdir(CGG_DIR, 0x1ff) 179 let out: *u8 = sys_mmap(CGG_CAP + 16) 180 let ol: *i64 = sys_mmap(16) as *i64 181 182 // ---- T1 the probe partition reconciles ---- 183 let rc0: i64 = cgg_run(subj, "probe" as *u8, 0 as *u8, 0 as *u8, out, ol) 184 let n0: i64 = *ol 185 let skel: i64 = cgg_int_after(out, n0, "skel_measured=" as *u8) 186 let pcap: i64 = cgg_int_after(out, n0, "pathcap=" as *u8) 187 let digf: i64 = cgg_int_after(out, n0, "digit_fields=" as *u8) 188 let shex: i64 = cgg_int_after(out, n0, "shahex=" as *u8) 189 let resv: i64 = cgg_int_after(out, n0, "reserve=" as *u8) 190 let craw: i64 = cgg_int_after(out, n0, "chunk_raw=" as *u8) 191 gv_puts(" [T1] skel=" as *u8); gv_num(skel) 192 gv_puts(" pathcap=" as *u8); gv_num(pcap) 193 gv_puts(" digits=" as *u8); gv_num(digf) 194 gv_puts(" shahex=" as *u8); gv_num(shex) 195 gv_puts(" reserve=" as *u8); gv_num(resv) 196 gv_puts(" sum=" as *u8); gv_num(skel + pcap + digf + shex); gv_puts("\n" as *u8) 197 var t1: i64 = 0 198 if resv > 0 { if skel + pcap + digf + shex == resv { t1 = 1 } } 199 gv_check("the-probe-partition-RECONCILES-skel-plus-pathcap-plus-digits-plus-shahex-equals-reserve" as *u8, t1, ctr) 200 201 // ---- T2 chunk_raw positive and a multiple of 3 (read FROM the probe, never re-derived here) ---- 202 gv_puts(" [T2] chunk_raw=" as *u8); gv_num(craw) 203 gv_puts(" mod3=" as *u8); if craw > 0 { gv_num(craw % 3) } else { gv_num(0 - 1) } 204 gv_puts("\n" as *u8) 205 var t2: i64 = 0 206 if craw > 0 { if craw % 3 == 0 { t2 = 1 } } 207 gv_check("chunk_raw-is-positive-and-an-exact-multiple-of-3 (so base64 emits no interior padding)" as *u8, t2, ctr) 208 209 // ---- build fixtures ---- 210 let sbuf: *u8 = sys_mmap(CGG_SMALL_N + 16) 211 var i: i64 = 0 212 while i < CGG_SMALL_N { sbuf[i] = (65 + (i % 26)) as u8; i = i + 1 } 213 cgg_write_file(CGG_SMALL, sbuf, CGG_SMALL_N) 214 215 var bign: i64 = CGG_SMALL_N 216 if craw > 0 { bign = craw + CGG_BIG_EXTRA } 217 let bbuf: *u8 = sys_mmap(bign + 16) 218 var b: i64 = 0 219 while b < bign { bbuf[b] = ((b * 7 + 13) % 251) as u8; b = b + 1 } 220 cgg_write_file(CGG_BIG, bbuf, bign) 221 222 // ---- T3 begin's digest vs an INDEPENDENT one-shot digest ---- 223 let rc1: i64 = cgg_run(subj, "begin" as *u8, CGG_SMALL, 0 as *u8, out, ol) 224 let n1: i64 = *ol 225 let d: *u8 = sys_mmap(CGG_DIGEST + 8) 226 sha256_digest(sbuf, CGG_SMALL_N, d) 227 let myhex: *u8 = sys_mmap(CGG_SHAHEX + 8) 228 cgg_hex_into(d, myhex) 229 let hp: i64 = cgg_find(out, n1, "sha256=" as *u8) 230 let tot1: i64 = cgg_int_after(out, n1, "total_bytes=" as *u8) 231 gv_puts(" [T3] independent=" as *u8); gv_puts(myhex) 232 gv_puts(" total_bytes=" as *u8); gv_num(tot1); gv_puts("\n" as *u8) 233 var t3: i64 = 0 234 if rc1 == 0 { if tot1 == CGG_SMALL_N { if cgg_hex_eq(out, n1, hp, myhex) == 1 { t3 = 1 } } } 235 gv_check("begin-whole-file-digest-equals-an-INDEPENDENTLY-computed-digest (one-shot here vs streaming there)" as *u8, t3, ctr) 236 237 // ---- T4 FIXTURE ASSERTION: the big fixture forces more than one chunk ---- 238 let rc2: i64 = cgg_run(subj, "begin" as *u8, CGG_BIG, 0 as *u8, out, ol) 239 let n2: i64 = *ol 240 let nch: i64 = cgg_int_after(out, n2, "nchunks=" as *u8) 241 let totb: i64 = cgg_int_after(out, n2, "total_bytes=" as *u8) 242 sha256_digest(bbuf, bign, d) 243 let bighex: *u8 = sys_mmap(CGG_SHAHEX + 8) 244 cgg_hex_into(d, bighex) 245 gv_puts(" [T4] fixture_bytes=" as *u8); gv_num(bign) 246 gv_puts(" total_bytes=" as *u8); gv_num(totb) 247 gv_puts(" nchunks=" as *u8); gv_num(nch); gv_puts("\n" as *u8) 248 var t4: i64 = 0 249 if nch > 1 { if totb == bign { t4 = 1 } } 250 gv_check("FIXTURE-REACHED-THE-CONDITION-the-large-fixture-forces-nchunks-above-one (without this T5 judges a path that never ran)" as *u8, t4, ctr) 251 252 // ---- T5 + T6 reassemble every chunk, and check the sizes SUM ---- 253 let acc: *u8 = sys_mmap(bign + 64) 254 let dec: *u8 = sys_mmap(CGG_CAP + 16) 255 var accn: i64 = 0 256 var sumraw: i64 = 0 257 var ok5: i64 = 1 258 var ix: i64 = 0 259 let ibuf: *u8 = sys_mmap(32) 260 while ix < nch { 261 var m: i64 = ix 262 var q: i64 = 31 263 if m == 0 { q = q - 1; ibuf[q] = 48 as u8 } 264 while m > 0 { q = q - 1; ibuf[q] = (48 + (m % 10)) as u8; m = m / 10 } 265 ibuf[31] = 0 as u8 266 let rcx: i64 = cgg_run(subj, "chunk" as *u8, CGG_BIG, (ibuf as i64 + q) as *u8, out, ol) 267 let nx: i64 = *ol 268 if rcx != 0 { ok5 = 0 } else { 269 let rawn: i64 = cgg_int_after(out, nx, " raw=" as *u8) 270 if rawn > 0 { sumraw = sumraw + rawn } 271 let bp: i64 = cgg_find(out, nx, "b64=" as *u8) 272 if bp < 0 { ok5 = 0 } else { 273 var e: i64 = bp 274 var go: i64 = 1 275 while go == 1 { 276 if e >= nx { go = 0 } else { 277 if out[e] == (10 as u8) { go = 0 } else { e = e + 1 } 278 } 279 } 280 let dn: i64 = b64_decode((out as i64 + bp) as *u8, e - bp, dec) 281 var c: i64 = 0 282 while c < dn { acc[accn + c] = dec[c]; c = c + 1 } 283 accn = accn + dn 284 } 285 } 286 ix = ix + 1 287 } 288 sha256_digest(acc, accn, d) 289 let acchex: *u8 = sys_mmap(CGG_SHAHEX + 8) 290 cgg_hex_into(d, acchex) 291 gv_puts(" [T5] reassembled_bytes=" as *u8); gv_num(accn) 292 gv_puts(" digest=" as *u8); gv_puts(acchex); gv_puts("\n" as *u8) 293 gv_puts(" original_digest=" as *u8); gv_puts(bighex); gv_puts("\n" as *u8) 294 var t5: i64 = 0 295 if ok5 == 1 { if accn == bign { if cgg_hex_eq(acchex, CGG_SHAHEX, 0, bighex) == 1 { t5 = 1 } } } 296 gv_check("multi-chunk-reassembly-is-byte-identical-to-the-original" as *u8, t5, ctr) 297 298 gv_puts(" [T6] sum_of_chunk_raw=" as *u8); gv_num(sumraw) 299 gv_puts(" total_bytes=" as *u8); gv_num(totb); gv_puts("\n" as *u8) 300 gv_check("the-partition-SUMS-per-chunk-raw-sizes-total-exactly-total_bytes" as *u8, (sumraw == totb) as i64, ctr) 301 302 // ---- T7/T8/T9 the refusals ---- 303 let rc7: i64 = cgg_run(subj, "begin" as *u8, "buildroot/runtime/../../etc/passwd" as *u8, 0 as *u8, out, ol) 304 gv_puts(" [T7] traversal -> exit=" as *u8); gv_num(rc7); gv_puts("\n" as *u8) 305 gv_check("neg-control-a-path-traversal-source-is-REFUSED" as *u8, (rc7 == 4) as i64, ctr) 306 307 let rc8: i64 = cgg_run(subj, "begin" as *u8, "_offc/nx_cc.elf" as *u8, 0 as *u8, out, ol) 308 gv_puts(" [T8] outside allowlist -> exit=" as *u8); gv_num(rc8); gv_puts("\n" as *u8) 309 gv_check("neg-control-a-source-outside-the-allowlist-is-REFUSED" as *u8, (rc8 == 4) as i64, ctr) 310 311 let rc9: i64 = cgg_run(subj, "begin" as *u8, "knowledge/seat.cap" as *u8, 0 as *u8, out, ol) 312 gv_puts(" [T9] credential material -> exit=" as *u8); gv_num(rc9); gv_puts("\n" as *u8) 313 gv_check("neg-control-credential-material-is-REFUSED-by-name" as *u8, (rc9 == 4) as i64, ctr) 314 315 // ---- T10 THE POSITIVE CONTROL for T7/T8/T9 ---- 316 let rc10: i64 = cgg_run(subj, "begin" as *u8, CGG_SMALL, 0 as *u8, out, ol) 317 gv_puts(" [T10] allowlisted source -> exit=" as *u8); gv_num(rc10); gv_puts("\n" as *u8) 318 gv_check("POSITIVE-CONTROL-an-allowlisted-source-is-ACCEPTED (a guard that refused everything would pass T7 T8 and T9)" as *u8, (rc10 == 0) as i64, ctr) 319 320 // ---- T11 range is a DISTINCT refusal from a source refusal ---- 321 let rc11: i64 = cgg_run(subj, "chunk" as *u8, CGG_SMALL, "9999" as *u8, out, ol) 322 gv_puts(" [T11] index past end -> exit=" as *u8); gv_num(rc11); gv_puts("\n" as *u8) 323 gv_check("an-index-past-end-of-file-is-a-RANGE-refusal-distinct-from-a-source-refusal" as *u8, (rc11 == 5) as i64, ctr) 324 325 return gv_verdict("content_get" as *u8, ctr, "the NAS->laptop door proven across the multi-chunk boundary its fixture is asserted to reach, with the partition summing, the digest cross-checked against an independent implementation, and every refusal carrying a positive control" as *u8) 326}