code wiki / _hdl_build / nx_pkg_gate.nx
nx_pkg_gate.nx source
↩ module page · 494 lines · 27328 B
1// nx_pkg_gate.nx -- THE GATE FOR THE CONTENT-ADDRESSED PACKAGE LANE (LR3 of /compare/lang).
2//
3// Subject: the DEPLOYED nx_pkg binary (fork-style end-to-end; argv[1] overrides the subject path so a
4// mutation bite can aim at a staged mutant without touching live). Every fixture is assembled AT
5// RUNTIME in /tmp/nx_pkg_gate/ -- nothing is checked in, so a source scanner can never find this gate's
6// own bad inputs, and setup is idempotent so a rerun cannot inherit a prior run's artifacts.
7//
8// WHAT IT PROVES, AND WHY EACH TOOTH EXISTS:
9// A GUARD THAT REFUSES EVERYTHING PASSES EVERY NEGATIVE TEST. So every refusal tooth here is paired
10// with a POSITIVE CONTROL that MUST be allowed, and every refusal asserts WHICH RULE FIRED -- both
11// the rule name on stdout and the distinct exit code. A suite that only asks `was it refused?` is
12// blind by construction, and this estate has already shipped that exact defect once (four SSRF deny
13// tests green while the guard refused every url).
14//
15// ZERO INSTALL-TIME EXECUTION is proven MECHANICALLY, never asserted. The module fixture carries a
16// real would-be install hook, and the gate first RUNS that hook itself to prove it genuinely produces
17// an observable marker (the anti-vacuity control -- otherwise `the marker is absent` proves only that
18// the marker was never producible). The marker is then cleared, the same module resolved through the
19// subject, and the marker asserted ABSENT while the resolve itself SUCCEEDED.
20//
21// NOT ROSTER-ADMITTED BY DEFAULT: it forks the subject ~25 times. Run via nx_job_run or /api/gate_run.
22// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
23import "nx_syscalls.nx"
24import "nx_gate_verdict.nx"
25import "nx_sha256.nx"
26
27const PG_SUBJECT_DEFAULT: *u8 = "./nx_pkg.elf" as *u8
28const PG_DIR: *u8 = "/tmp/nx_pkg_gate" as *u8
29const PG_STORE: *u8 = "/tmp/nx_pkg_gate/store" as *u8
30const PG_CONF: *u8 = "/tmp/nx_pkg_gate/pkg_cas.conf" as *u8
31const PG_CONF_BAD: *u8 = "/tmp/nx_pkg_gate/bad_missing_key.conf" as *u8
32const PG_LOCK: *u8 = "/tmp/nx_pkg_gate/pkg.lock" as *u8
33const PG_JRNL: *u8 = "/tmp/nx_pkg_gate/pkgcas.jrnl" as *u8
34const PG_OUT: *u8 = "/tmp/nx_pkg_gate/capture.txt" as *u8
35const PG_MOD_HOOK: *u8 = "/tmp/nx_pkg_gate/mod_with_install_hook.nx" as *u8
36const PG_MOD_SQUAT: *u8 = "/tmp/nx_pkg_gate/mod_typosquat.nx" as *u8
37const PG_PWN_CONF: *u8 = "/tmp/nx_pkg_gate/pwn_conf.conf" as *u8
38const PG_PWN_PAYLOAD: *u8 = "/tmp/nx_pkg_gate/pwn_payload.txt" as *u8
39const PG_PWN_MARKER: *u8 = "/tmp/nx_pkg_gate/PWNED" as *u8
40const PG_PWN_LOCK: *u8 = "/tmp/nx_pkg_gate/pwn.lock" as *u8
41const PG_PWN_STORE: *u8 = "/tmp/nx_pkg_gate/pwnstore" as *u8
42const PG_DEST_OK: *u8 = "/tmp/nx_pkg_gate/resolved_hook.nx" as *u8
43const PG_DEST_GOOD: *u8 = "/tmp/nx_pkg_gate/resolved_pinned.nx" as *u8
44const PG_DEST_SQUAT: *u8 = "/tmp/nx_pkg_gate/resolved_squat.nx" as *u8
45const PG_DEST_MISMATCH: *u8 = "/tmp/nx_pkg_gate/resolved_mismatch.nx" as *u8
46const PG_DEST_OUTSIDE: *u8 = "/etc/nx_pkg_gate_should_never_appear" as *u8
47// the legitimate logical name, and the lookalike an attacker would publish beside it
48const PG_NAME_REAL: *u8 = "nx_syscalls" as *u8
49const PG_NAME_SQUAT: *u8 = "nx_sysca11s" as *u8
50
51const PG_SHAHEX: i64 = 64
52const PG_DIGEST_BYTES: i64 = 32
53const PG_NL: i64 = 10
54const PG_BAR: i64 = 124
55const PG_ASCII_0: i64 = 48
56const PG_ASCII_9: i64 = 57
57const PG_SCRATCH: i64 = 4096
58const PG_MODE_X: i64 = 493
59// distinct exit codes the subject promises; asserted individually so a refusal for the WRONG reason
60// cannot score as a pass (a red for the wrong reason is not evidence)
61const PG_EXIT_USAGE: i64 = 3
62const PG_EXIT_CONF: i64 = 4
63const PG_EXIT_MALFORMED: i64 = 5
64const PG_EXIT_ABSENT: i64 = 6
65const PG_EXIT_MISMATCH: i64 = 7
66const PG_EXIT_DEST: i64 = 8
67const PG_EXIT_NOTPINNED: i64 = 9
68const PG_EXIT_PINCONFLICT: i64 = 10
69const PG_EXIT_CHAIN: i64 = 11
70const PG_EXIT_PINAMBIG: i64 = 13
71
72func pg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
73func pg_mkdir(path: *u8) -> i64 {
74 let nbox: *i64 = sys_mmap(16) as *i64
75 nbox[0] = 258
76 let rc: i64 = __syscall(nbox[0], 0 - 100, path as i64, 0x1ed, 0, 0, 0)
77 sys_munmap(nbox as *u8, 16)
78 return rc
79}
80func pg_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 }
81func pg_cat(d: *u8, o: i64, s: *u8) -> i64 { var p: i64 = o; var i: i64 = 0; while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } d[p] = 0 as u8; return p }
82func pg_write(path: *u8, buf: *u8, n: i64) -> i64 {
83 let fd: i64 = sys_openat_wr(path, MODE_0644)
84 if fd < 0 { return 0 - 1 }
85 var w: i64 = 0
86 while w < n {
87 let r: i64 = sys_write(fd, ((buf as i64) + w) as *u8, n - w)
88 if r <= 0 { sys_close(fd); return 0 - 1 }
89 w = w + r
90 }
91 sys_close(fd)
92 return n
93}
94func pg_write_str(path: *u8, s: *u8) -> i64 { return pg_write(path, s, pg_slen(s)) }
95func pg_find(hay: *u8, n: i64, needle: *u8) -> i64 {
96 let m: i64 = pg_slen(needle)
97 if m == 0 { return 0 - 1 }
98 var i: i64 = 0
99 while i + m <= n {
100 var j: i64 = 0
101 var ok: i64 = 1
102 while j < m { if hay[i + j] != needle[j] { ok = 0; j = m } else { j = j + 1 } }
103 if ok == 1 { return i }
104 i = i + 1
105 }
106 return 0 - 1
107}
108func pg_num_after(hay: *u8, n: i64, key: *u8) -> i64 {
109 let at: i64 = pg_find(hay, n, key)
110 if at < 0 { return 0 - 1 }
111 var i: i64 = at + pg_slen(key)
112 var v: i64 = 0
113 var seen: i64 = 0
114 while i < n {
115 let c: i64 = hay[i] as i64
116 if c < PG_ASCII_0 { break }
117 if c > PG_ASCII_9 { break }
118 v = v * 10 + (c - PG_ASCII_0)
119 seen = 1
120 i = i + 1
121 }
122 if seen == 0 { return 0 - 1 }
123 return v
124}
125func pg_hex_into(dig: *u8, out: *u8) -> i64 {
126 let h: *u8 = "0123456789abcdef" as *u8
127 var i: i64 = 0
128 while i < PG_DIGEST_BYTES { let v: i64 = dig[i] as i64; out[i*2] = h[(v >> 4) & 15]; out[i*2+1] = h[v & 15]; i = i + 1 }
129 out[PG_SHAHEX] = 0 as u8
130 return PG_SHAHEX
131}
132// independent digest of a file ON DISK -- the gate hashes the RESULT itself rather than believing the
133// subject's own receipt. Returns byte count, or -1 when absent.
134func pg_file_sha(path: *u8, outhex: *u8) -> i64 {
135 let lp: *i64 = sys_mmap(16) as *i64
136 let b: *u8 = sys_read_file(path, lp)
137 if (b as i64) == 0 { outhex[0] = 0 as u8; return 0 - 1 }
138 let d: *u8 = sys_mmap(PG_DIGEST_BYTES + 8)
139 sha256_digest(b, lp[0], d)
140 pg_hex_into(d, outhex)
141 let n: i64 = lp[0]
142 sys_free_file(b, n)
143 return n
144}
145// fork the subject with up to 4 args; stdout+stderr captured to PG_OUT; returns the exit code
146func pg_run(subject: *u8, a1: *u8, a2: *u8, a3: *u8, a4: *u8, nargs: i64) -> i64 {
147 let arr: *i64 = sys_mmap(64) as *i64
148 arr[0] = subject as i64
149 if nargs >= 1 { arr[1] = a1 as i64 }
150 if nargs >= 2 { arr[2] = a2 as i64 }
151 if nargs >= 3 { arr[3] = a3 as i64 }
152 if nargs >= 4 { arr[4] = a4 as i64 }
153 arr[nargs + 1] = 0
154 let env: *i64 = sys_mmap(16) as *i64
155 env[0] = 0
156 let pid: i64 = sys_fork()
157 if pid == 0 {
158 let fd: i64 = sys_openat_wr(PG_OUT, MODE_0644)
159 if fd >= 0 { sys_dup3(fd, 1, 0); sys_dup3(fd, 2, 0) }
160 sys_execve(subject, arr, env)
161 sys_exit(127)
162 }
163 let st: *i64 = sys_mmap(16) as *i64
164 sys_wait4(pid, st, 0)
165 return wait_status_rc(st[0])
166}
167func pg_read_out(lp: *i64) -> *u8 {
168 let b: *u8 = sys_read_file(PG_OUT, lp)
169 if (b as i64) == 0 { lp[0] = 0; return sys_mmap(16) }
170 return b
171}
172// did the last capture name THIS rule? Both the rule name and the exit code are asserted by callers.
173func pg_saw_rule(rule: *u8) -> i64 {
174 let lp: *i64 = sys_mmap(16) as *i64
175 let b: *u8 = pg_read_out(lp)
176 let need: i64 = pg_slen(rule) + 8
177 let pat: *u8 = sys_mmap(need)
178 var o: i64 = pg_cat(pat, 0, "rule=" as *u8)
179 o = pg_cat(pat, o, rule)
180 var hit: i64 = 0
181 if pg_find(b, lp[0], pat) >= 0 { hit = 1 }
182 sys_munmap(pat, need)
183 return hit
184}
185
186func main(argc: i64, argv: *i64) -> i64 {
187 let ctr: *i64 = gv_ctr()
188 gv_head("nx_pkg_gate -- content-addressed resolution, a typosquat that cannot resolve, and zero install-time execution proven by an absent side effect" as *u8)
189 var subject: *u8 = PG_SUBJECT_DEFAULT
190 if argc >= 2 { subject = argv[1] as *u8 }
191 gv_puts(" subject: " as *u8); gv_puts(subject); gv_puts("\n" as *u8)
192
193 // ---- SETUP: idempotent, runtime-assembled ---------------------------------------------------
194 pg_mkdir(PG_DIR)
195 pg_mkdir(PG_STORE)
196 sys_unlinkat(PG_LOCK)
197 sys_unlinkat(PG_JRNL)
198 sys_unlinkat(PG_PWN_MARKER)
199 sys_unlinkat(PG_PWN_LOCK)
200 sys_unlinkat(PG_DEST_OK)
201 sys_unlinkat(PG_DEST_GOOD)
202 sys_unlinkat(PG_DEST_SQUAT)
203 sys_unlinkat(PG_DEST_MISMATCH)
204 sys_unlinkat(PG_DEST_OUTSIDE)
205
206 let cbuf: *u8 = sys_mmap(PG_SCRATCH)
207 var co: i64 = pg_cat(cbuf, 0, "store_root=" as *u8)
208 co = pg_cat(cbuf, co, PG_STORE)
209 co = pg_cat(cbuf, co, "\nlock_path=" as *u8)
210 co = pg_cat(cbuf, co, PG_LOCK)
211 co = pg_cat(cbuf, co, "\nlog_path=" as *u8)
212 co = pg_cat(cbuf, co, PG_JRNL)
213 co = pg_cat(cbuf, co, "\n" as *u8)
214 pg_write(PG_CONF, cbuf, co)
215
216 // a conf missing log_path -- an absent key must REFUSE, never default
217 var bo: i64 = pg_cat(cbuf, 0, "store_root=" as *u8)
218 bo = pg_cat(cbuf, bo, PG_STORE)
219 bo = pg_cat(cbuf, bo, "\nlock_path=" as *u8)
220 bo = pg_cat(cbuf, bo, PG_LOCK)
221 bo = pg_cat(cbuf, bo, "\n" as *u8)
222 pg_write(PG_CONF_BAD, cbuf, bo)
223
224 // the would-be install hook: a SEPARATE conf whose journal path IS the marker, so running the hook
225 // command creates exactly one observable file that a single probe can settle.
226 var po: i64 = pg_cat(cbuf, 0, "store_root=" as *u8)
227 po = pg_cat(cbuf, po, PG_PWN_STORE)
228 po = pg_cat(cbuf, po, "\nlock_path=" as *u8)
229 po = pg_cat(cbuf, po, PG_PWN_LOCK)
230 po = pg_cat(cbuf, po, "\nlog_path=" as *u8)
231 po = pg_cat(cbuf, po, PG_PWN_MARKER)
232 po = pg_cat(cbuf, po, "\n" as *u8)
233 pg_write(PG_PWN_CONF, cbuf, po)
234 pg_write_str(PG_PWN_PAYLOAD, "payload bytes the hook would install\n" as *u8)
235 pg_mkdir(PG_PWN_STORE)
236
237 // THE MODULE UNDER TEST: ordinary-looking source that carries a live install hook in its body.
238 var mo: i64 = pg_cat(cbuf, 0, "// module fixture: this file carries a WORKING install hook\npostinstall=" as *u8)
239 mo = pg_cat(cbuf, mo, subject)
240 mo = pg_cat(cbuf, mo, " cas_put " as *u8)
241 mo = pg_cat(cbuf, mo, PG_PWN_PAYLOAD)
242 mo = pg_cat(cbuf, mo, " " as *u8)
243 mo = pg_cat(cbuf, mo, PG_PWN_CONF)
244 mo = pg_cat(cbuf, mo, "\nfunc hookmod_id() -> i64 { return 1 }\n" as *u8)
245 pg_write(PG_MOD_HOOK, cbuf, mo)
246 let hooklen: i64 = mo
247
248 // the typosquat's payload: different bytes, same intent to be mistaken for the real module
249 pg_write_str(PG_MOD_SQUAT, "// TYPOSQUAT: lookalike name, attacker-chosen bytes\nfunc syscalls_init() -> i64 { return 0 - 1 }\n" as *u8)
250
251 let lp: *i64 = sys_mmap(16) as *i64
252 var rc: i64 = 0
253 var ob: *u8 = sys_mmap(16)
254 var onn: i64 = 0
255
256 // the population this run actually examined: two distinct modules through the whole lane
257 gv_subjects("modules driven end-to-end through the CAS lane" as *u8, 2, ctr)
258
259 // ---- T1 the fixture genuinely contains a live install hook ------------------------------------
260 let hb: *u8 = sys_read_file(PG_MOD_HOOK, lp)
261 var t1: i64 = 0
262 if (hb as i64) != 0 { if pg_find(hb, lp[0], "postinstall=" as *u8) >= 0 { if lp[0] == hooklen { t1 = 1 } } }
263 gv_puts(" fixture module bytes=" as *u8); gv_num(hooklen); gv_puts("\n" as *u8)
264 gv_check("fixture-module-really-carries-an-install-hook-line (the condition, asserted before any outcome)" as *u8, t1 == 1, ctr)
265
266 // ---- T2 ANTI-VACUITY: the hook is genuinely executable and produces the marker ----------------
267 // Without this, `the marker is absent` would prove only that the marker was never producible.
268 sys_unlinkat(PG_PWN_MARKER)
269 let before_hook: i64 = pg_exists(PG_PWN_MARKER)
270 pg_run(subject, "cas_put" as *u8, PG_PWN_PAYLOAD, PG_PWN_CONF, 0 as *u8, 3)
271 let after_hook: i64 = pg_exists(PG_PWN_MARKER)
272 gv_puts(" hook control: marker before=" as *u8); gv_num(before_hook)
273 gv_puts(" after_running_the_hook=" as *u8); gv_num(after_hook); gv_puts("\n" as *u8)
274 gv_bite("neg-control-the-planted-install-hook-DOES-fire-when-executed (bad=marker appears, good=absent after reset)" as *u8, after_hook, before_hook, ctr)
275
276 // reset, and PROVE the reset landed before measuring the thing under test
277 sys_unlinkat(PG_PWN_MARKER)
278 gv_check("marker-cleared-before-the-resolve-under-test (a stale marker would make the next tooth lie)" as *u8, pg_exists(PG_PWN_MARKER) == 0, ctr)
279
280 // ---- T3 put the hook-carrying module into the store ------------------------------------------
281 rc = pg_run(subject, "cas_put" as *u8, PG_MOD_HOOK, PG_CONF, 0 as *u8, 3)
282 ob = pg_read_out(lp); onn = lp[0]
283 let dig_hook: *u8 = sys_mmap(PG_SHAHEX + 8)
284 var dh: i64 = pg_find(ob, onn, "digest=" as *u8)
285 var t3: i64 = 0
286 if rc == 0 { if dh >= 0 {
287 var i: i64 = 0
288 while i < PG_SHAHEX { dig_hook[i] = ob[dh + 7 + i]; i = i + 1 }
289 dig_hook[PG_SHAHEX] = 0 as u8
290 t3 = 1
291 } }
292 // the gate re-derives the digest itself: the subject's receipt is never the oracle
293 let own_hook: *u8 = sys_mmap(PG_SHAHEX + 8)
294 let ownn: i64 = pg_file_sha(PG_MOD_HOOK, own_hook)
295 var t3b: i64 = 0
296 if t3 == 1 { if ownn == hooklen { var same: i64 = 1; var i2: i64 = 0; while i2 < PG_SHAHEX { if dig_hook[i2] != own_hook[i2] { same = 0; i2 = PG_SHAHEX } else { i2 = i2 + 1 } } t3b = same } }
297 gv_puts(" cas_put rc=" as *u8); gv_num(rc); gv_puts(" digest=" as *u8); gv_puts(dig_hook); gv_puts("\n" as *u8)
298 gv_check("cas-put-digest-equals-the-gate-s-own-independent-sha256-of-the-file (not the subject's receipt)" as *u8, t3b == 1, ctr)
299
300 // ---- T4 THE CENTRAL CLAIM: resolve SUCCEEDS and executes nothing ------------------------------
301 rc = pg_run(subject, "cas_resolve" as *u8, dig_hook, PG_DEST_OK, PG_CONF, 4)
302 let marker_after_resolve: i64 = pg_exists(PG_PWN_MARKER)
303 let resolved_present: i64 = pg_exists(PG_DEST_OK)
304 gv_puts(" cas_resolve rc=" as *u8); gv_num(rc)
305 gv_puts(" dest_present=" as *u8); gv_num(resolved_present)
306 gv_puts(" install_marker_present=" as *u8); gv_num(marker_after_resolve); gv_puts("\n" as *u8)
307 var t4: i64 = 0
308 if rc == 0 { if resolved_present == 1 { if marker_after_resolve == 0 { t4 = 1 } } }
309 gv_check("ZERO-INSTALL-EXECUTION: a hook-carrying module RESOLVES SUCCESSFULLY and the hook's side effect is absent (rc, dest and marker all bound in the condition)" as *u8, t4 == 1, ctr)
310
311 // ---- T5 the resolved bytes hash to the digest that was ASKED FOR ------------------------------
312 let got: *u8 = sys_mmap(PG_SHAHEX + 8)
313 let gotn: i64 = pg_file_sha(PG_DEST_OK, got)
314 var t5: i64 = 0
315 if gotn == hooklen { var same2: i64 = 1; var i3: i64 = 0; while i3 < PG_SHAHEX { if got[i3] != dig_hook[i3] { same2 = 0; i3 = PG_SHAHEX } else { i3 = i3 + 1 } } t5 = same2 }
316 gv_puts(" resolved bytes=" as *u8); gv_num(gotn); gv_puts(" sha=" as *u8); gv_puts(got); gv_puts("\n" as *u8)
317 gv_check("resolved-file-re-hashes-to-the-requested-digest (the STATE is the oracle, not the message)" as *u8, t5 == 1, ctr)
318
319 // ---- T6 POSITIVE CONTROL: a legitimately pinned name RESOLVES ---------------------------------
320 // Without this every refusal below is satisfied by a resolver that refuses everything.
321 rc = pg_run(subject, "pin" as *u8, PG_NAME_REAL, dig_hook, PG_CONF, 4)
322 let pin_rc: i64 = rc
323 rc = pg_run(subject, "resolve" as *u8, PG_NAME_REAL, PG_DEST_GOOD, PG_CONF, 4)
324 var t6: i64 = 0
325 if pin_rc == 0 { if rc == 0 { if pg_exists(PG_DEST_GOOD) == 1 { t6 = 1 } } }
326 gv_puts(" pin rc=" as *u8); gv_num(pin_rc); gv_puts(" resolve-by-name rc=" as *u8); gv_num(rc); gv_puts("\n" as *u8)
327 gv_check("neg-control-POSITIVE: a legitimately pinned name RESOLVES (a resolver that refused everything would fail HERE)" as *u8, t6 == 1, ctr)
328
329 // ---- T7 THE TYPOSQUAT: a lookalike name cannot resolve ----------------------------------------
330 // The attacker even gets their bytes INTO the store first -- the squat still cannot be reached,
331 // because resolution is exact-pin then digest, with no near-name search and no `latest`.
332 pg_run(subject, "cas_put" as *u8, PG_MOD_SQUAT, PG_CONF, 0 as *u8, 3)
333 rc = pg_run(subject, "resolve" as *u8, PG_NAME_SQUAT, PG_DEST_SQUAT, PG_CONF, 4)
334 let squat_rule: i64 = pg_saw_rule("name-not-pinned" as *u8)
335 let squat_file: i64 = pg_exists(PG_DEST_SQUAT)
336 gv_puts(" typosquat rc=" as *u8); gv_num(rc)
337 gv_puts(" named_rule=" as *u8); gv_num(squat_rule)
338 gv_puts(" wrote_a_file=" as *u8); gv_num(squat_file); gv_puts("\n" as *u8)
339 var t7: i64 = 0
340 if rc == PG_EXIT_NOTPINNED { if squat_rule == 1 { if squat_file == 0 { t7 = 1 } } }
341 gv_check("TYPOSQUAT-CANNOT-RESOLVE: a lookalike name refuses with rule=name-not-pinned, the named exit code, and writes NO file" as *u8, t7 == 1, ctr)
342
343 // ---- T8 A POISONED STORE serves a refusal, never different code -------------------------------
344 // Overwrite the blob AT the legitimate digest with the typosquat's bytes. The path is a hint; the
345 // hash is the identity. Bite-proven in both directions: poisoned refuses, restored resolves.
346 let bp: *u8 = sys_mmap(PG_SCRATCH)
347 var bpo: i64 = pg_cat(bp, 0, PG_STORE)
348 bpo = pg_cat(bp, bpo, "/" as *u8)
349 bpo = pg_cat(bp, bpo, dig_hook)
350 let orig: *u8 = sys_read_file(bp, lp)
351 let orign: i64 = lp[0]
352 pg_write_str(bp, "ATTACKER BYTES SUBSTITUTED AT THE LEGITIMATE DIGEST PATH\n" as *u8)
353 rc = pg_run(subject, "cas_resolve" as *u8, dig_hook, PG_DEST_MISMATCH, PG_CONF, 4)
354 let mm_rule: i64 = pg_saw_rule("digest-mismatch" as *u8)
355 let mm_file: i64 = pg_exists(PG_DEST_MISMATCH)
356 var poisoned_refused: i64 = 0
357 if rc == PG_EXIT_MISMATCH { if mm_rule == 1 { if mm_file == 0 { poisoned_refused = 1 } } }
358 pg_write(bp, orig, orign)
359 sys_unlinkat(PG_DEST_MISMATCH)
360 let rc_restored: i64 = pg_run(subject, "cas_resolve" as *u8, dig_hook, PG_DEST_MISMATCH, PG_CONF, 4)
361 var restored_ok: i64 = 1
362 if rc_restored == 0 { restored_ok = 0 }
363 gv_puts(" poisoned rc=" as *u8); gv_num(rc)
364 gv_puts(" restored rc=" as *u8); gv_num(rc_restored); gv_puts("\n" as *u8)
365 gv_bite("neg-control-THE-PATH-IS-A-HINT-THE-HASH-IS-THE-IDENTITY: a substituted blob refuses digest-mismatch, the restored blob resolves" as *u8, poisoned_refused, restored_ok, ctr)
366
367 // ---- T9 an unparseable digest fails CLOSED ----------------------------------------------------
368 let short_dig: *u8 = sys_mmap(PG_SHAHEX + 8)
369 var si: i64 = 0
370 while si < PG_SHAHEX - 1 { short_dig[si] = dig_hook[si]; si = si + 1 }
371 short_dig[PG_SHAHEX - 1] = 0 as u8
372 let rc_short: i64 = pg_run(subject, "cas_resolve" as *u8, short_dig, PG_DEST_SQUAT, PG_CONF, 4)
373 let r_short: i64 = pg_saw_rule("malformed-digest" as *u8)
374 let rc_nonhex: i64 = pg_run(subject, "cas_resolve" as *u8, "zzzz611184eed3163d3ff8b059045c777b2c3fad3a6db3b8b5a5128c45504ca9" as *u8, PG_DEST_SQUAT, PG_CONF, 4)
375 let r_nonhex: i64 = pg_saw_rule("malformed-digest" as *u8)
376 let rc_upper: i64 = pg_run(subject, "cas_resolve" as *u8, "2990611184EED3163D3FF8B059045C777B2C3FAD3A6DB3B8B5A5128C45504CA9" as *u8, PG_DEST_SQUAT, PG_CONF, 4)
377 let r_upper: i64 = pg_saw_rule("malformed-digest" as *u8)
378 var t9: i64 = 0
379 if rc_short == PG_EXIT_MALFORMED { if rc_nonhex == PG_EXIT_MALFORMED { if rc_upper == PG_EXIT_MALFORMED {
380 if r_short == 1 { if r_nonhex == 1 { if r_upper == 1 { if pg_exists(PG_DEST_SQUAT) == 0 { t9 = 1 } } } } } } }
381 gv_puts(" malformed rc short=" as *u8); gv_num(rc_short)
382 gv_puts(" nonhex=" as *u8); gv_num(rc_nonhex)
383 gv_puts(" uppercase=" as *u8); gv_num(rc_upper); gv_puts("\n" as *u8)
384 gv_check("UNPARSEABLE-INPUT-FAILS-CLOSED: short, non-hex and uppercase digests each refuse malformed-digest and write nothing" as *u8, t9 == 1, ctr)
385
386 // ---- T10 an absent digest refuses -------------------------------------------------------------
387 let rc_abs: i64 = pg_run(subject, "cas_resolve" as *u8, "0000000000000000000000000000000000000000000000000000000000000000" as *u8, PG_DEST_SQUAT, PG_CONF, 4)
388 var t10: i64 = 0
389 if rc_abs == PG_EXIT_ABSENT { if pg_saw_rule("digest-absent" as *u8) == 1 { if pg_exists(PG_DEST_SQUAT) == 0 { t10 = 1 } } }
390 gv_check("absent-digest-refuses-rule=digest-absent-and-writes-nothing" as *u8, t10 == 1, ctr)
391
392 // ---- T11 a destination outside the allowlist refuses ------------------------------------------
393 let rc_dest: i64 = pg_run(subject, "cas_resolve" as *u8, dig_hook, PG_DEST_OUTSIDE, PG_CONF, 4)
394 var t11: i64 = 0
395 if rc_dest == PG_EXIT_DEST { if pg_saw_rule("dest-refused" as *u8) == 1 { if pg_exists(PG_DEST_OUTSIDE) == 0 { t11 = 1 } } }
396 gv_check("dest-outside-the-safe-root-allowlist-refuses-rule=dest-refused-and-creates-no-file" as *u8, t11 == 1, ctr)
397
398 // ---- T12 an unrecognised verb refuses, it does not fall through -------------------------------
399 let rc_verb: i64 = pg_run(subject, "cas_reslove" as *u8, dig_hook, PG_DEST_SQUAT, PG_CONF, 4)
400 let verb_rule: i64 = pg_saw_rule("unknown-verb" as *u8)
401 var t12: i64 = 0
402 if rc_verb == PG_EXIT_USAGE { if verb_rule == 1 { if pg_exists(PG_DEST_SQUAT) == 0 { t12 = 1 } } }
403 gv_puts(" unknown verb rc=" as *u8); gv_num(rc_verb); gv_puts(" named_rule=" as *u8); gv_num(verb_rule); gv_puts("\n" as *u8)
404 gv_check("UNKNOWN-VERB-FAILS-CLOSED naming rule=unknown-verb (a typo must not report as a CONFIGURATION fault -- the refusal names the conjunct that fired)" as *u8, t12 == 1, ctr)
405
406 // ---- T13 an absent conf key refuses, it does not default -------------------------------------
407 let rc_conf: i64 = pg_run(subject, "cas_resolve" as *u8, dig_hook, PG_DEST_SQUAT, PG_CONF_BAD, 4)
408 var t13: i64 = 0
409 if rc_conf == PG_EXIT_CONF { if pg_saw_rule("conf-missing-key" as *u8) == 1 { if pg_exists(PG_DEST_SQUAT) == 0 { t13 = 1 } } }
410 gv_check("absent-conf-key-refuses-rule=conf-missing-key (config is data; a missing row never silently defaults)" as *u8, t13 == 1, ctr)
411
412 // ---- T14 pin conflict and pin ambiguity both refuse -------------------------------------------
413 let squat_dig: *u8 = sys_mmap(PG_SHAHEX + 8)
414 pg_file_sha(PG_MOD_SQUAT, squat_dig)
415 let rc_conflict: i64 = pg_run(subject, "pin" as *u8, PG_NAME_REAL, squat_dig, PG_CONF, 4)
416 var t14: i64 = 0
417 if rc_conflict == PG_EXIT_PINCONFLICT { if pg_saw_rule("pin-conflict" as *u8) == 1 { t14 = 1 } }
418 gv_puts(" re-pin to a different digest rc=" as *u8); gv_num(rc_conflict); gv_puts("\n" as *u8)
419 gv_check("re-pinning-a-name-to-a-DIFFERENT-digest-refuses-rule=pin-conflict (a pin is not silently movable)" as *u8, t14 == 1, ctr)
420
421 // hand-append a duplicate row: a declaration file that permits two answers for one key is a coin
422 // flip wearing a schema, so the reader must REFUSE rather than pick first-match or last-match.
423 let dupfd: i64 = sys_openat_append(PG_LOCK, MODE_0644)
424 if dupfd >= 0 {
425 var duo: i64 = pg_cat(cbuf, 0, PG_NAME_REAL)
426 cbuf[duo] = PG_BAR as u8; duo = duo + 1
427 duo = pg_cat(cbuf, duo, squat_dig)
428 cbuf[duo] = PG_NL as u8; duo = duo + 1
429 sys_write(dupfd, cbuf, duo)
430 sys_close(dupfd)
431 }
432 sys_unlinkat(PG_DEST_GOOD)
433 let rc_ambig: i64 = pg_run(subject, "resolve" as *u8, PG_NAME_REAL, PG_DEST_GOOD, PG_CONF, 4)
434 var t15: i64 = 0
435 if rc_ambig == PG_EXIT_PINAMBIG { if pg_saw_rule("pin-ambiguous" as *u8) == 1 { if pg_exists(PG_DEST_GOOD) == 0 { t15 = 1 } } }
436 gv_puts(" duplicate pin row rc=" as *u8); gv_num(rc_ambig); gv_puts("\n" as *u8)
437 gv_check("DUPLICATE-PIN-ROW-REFUSES-rule=pin-ambiguous rather than choosing first-match or last-match" as *u8, t15 == 1, ctr)
438
439 // ---- T16 the transparency journal verifies, and a tampered row breaks it ----------------------
440 let rc_log: i64 = pg_run(subject, "logverify" as *u8, PG_CONF, 0 as *u8, 0 as *u8, 2)
441 ob = pg_read_out(lp); onn = lp[0]
442 let entries: i64 = pg_num_after(ob, onn, "entries=" as *u8)
443 var t16: i64 = 0
444 if rc_log == 0 { if entries > 0 { if pg_find(ob, onn, "chain=OK" as *u8) >= 0 { t16 = 1 } } }
445 gv_puts(" journal entries=" as *u8); gv_num(entries); gv_puts(" logverify rc=" as *u8); gv_num(rc_log); gv_puts("\n" as *u8)
446 gv_check("journal-chain-verifies-with-the-entry-count-BOUND-IN-THE-CONDITION (a zero-row journal cannot pass)" as *u8, t16 == 1, ctr)
447
448 // tamper one byte inside row 0's digest field, then restore
449 let jb: *u8 = sys_read_file(PG_JRNL, lp)
450 let jn: i64 = lp[0]
451 var tampered_break: i64 = 0
452 var tampered_at: i64 = 0 - 1
453 var append_refused: i64 = 0
454 if (jb as i64) != 0 { if jn > 0 {
455 let copy: *u8 = sys_mmap(jn + 16)
456 var ci: i64 = 0
457 while ci < jn { copy[ci] = jb[ci]; ci = ci + 1 }
458 // second '|' of the first line starts the digest field
459 var bars: i64 = 0
460 var k: i64 = 0
461 var digoff: i64 = 0 - 1
462 while k < jn {
463 if (copy[k] as i64) == PG_BAR { bars = bars + 1; if bars == 2 { digoff = k + 1; k = jn } }
464 if (copy[k] as i64) == PG_NL { k = jn }
465 k = k + 1
466 }
467 if digoff > 0 {
468 let old: i64 = copy[digoff] as i64
469 var nw: i64 = PG_ASCII_0
470 if old == PG_ASCII_0 { nw = PG_ASCII_0 + 1 }
471 copy[digoff] = nw as u8
472 pg_write(PG_JRNL, copy, jn)
473 let rc_t: i64 = pg_run(subject, "logverify" as *u8, PG_CONF, 0 as *u8, 0 as *u8, 2)
474 ob = pg_read_out(lp); onn = lp[0]
475 tampered_at = pg_num_after(ob, onn, "chain=BREAK at=" as *u8)
476 if rc_t == PG_EXIT_CHAIN { if tampered_at == 0 { if pg_saw_rule("chain-break" as *u8) == 1 { tampered_break = 1 } } }
477 // and an append onto a broken chain must REFUSE rather than extend it
478 sys_unlinkat(PG_DEST_MISMATCH)
479 let rc_ap: i64 = pg_run(subject, "cas_resolve" as *u8, dig_hook, PG_DEST_MISMATCH, PG_CONF, 4)
480 if rc_ap == PG_EXIT_CHAIN { append_refused = 1 }
481 // restore the banked bytes
482 pg_write(PG_JRNL, jb, jn)
483 }
484 } }
485 let rc_log2: i64 = pg_run(subject, "logverify" as *u8, PG_CONF, 0 as *u8, 0 as *u8, 2)
486 var restored_log_bad: i64 = 1
487 if rc_log2 == 0 { restored_log_bad = 0 }
488 gv_puts(" tampered chain break_at=" as *u8); gv_num(tampered_at)
489 gv_puts(" restored logverify rc=" as *u8); gv_num(rc_log2); gv_puts("\n" as *u8)
490 gv_bite("neg-control-TAMPER-EVIDENCE: editing one byte of a past row breaks the chain AT THE NAMED INDEX, and the restored journal verifies" as *u8, tampered_break, restored_log_bad, ctr)
491 gv_check("an-append-onto-a-BROKEN-chain-is-REFUSED-not-extended (you cannot grow a tampered journal)" as *u8, append_refused == 1, ctr)
492
493 return gv_verdict("PKG-CAS" as *u8, ctr, "content-addressed resolution with no name lookup at the digest layer, an exact-pin lane whose unpinned names fail closed, and a hash-chained journal" as *u8)
494}