code wiki / (root) / nx_toolreg_reap_gate.nx

nx_toolreg_reap_gate.nx source

↩ module page · 135 lines · 6666 B

1// nx_toolreg_reap_gate.nx -- proof that the reaper removes what it should and REFUSES what it must not. 2// 3// The teeth that matter are the NEGATIVE ones. A reaper that removes everything asked of it is a 4// registry-deletion oracle; the whole safety claim is that it discriminates by TARGET SHAPE, so T2 5// (a live .elf row survives an explicit reap request) and T4 (unrelated rows byte-preserved) are what 6// make T1 mean anything. T5 checks the no-op path writes NOTHING -- rewriting a shared conf to change 7// nothing is how a concurrent reader gets a truncated read for no reason. 8// license_tier: ORIGINAL expect_exit: 0 9import "nx_syscalls.nx" 10 11func rg_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 12func rg_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 13func rg_wn(v: i64) -> i64 { 14 let b: *u8=sys_mmap(32); var x: i64=v; var i: i64=31 15 if x==0 { b[i]=48 as u8; i=i-1 } 16 while x>0 { b[i]=(48+x%10) as u8; x=x/10; i=i-1 } 17 sys_write(1, ((b as i64)+i+1) as *u8, 31-i); return 0 18} 19func rg_wfile(path: *u8, content: *u8) -> i64 { 20 let fd: i64=sys_openat_wr(path, 0x1a4) 21 if fd<0 { return 0-1 } 22 sys_write(fd, content, rg_slen(content)) 23 sys_close(fd) 24 return 0 25} 26func rg_read(path: *u8, buf: *u8, cap: i64) -> i64 { 27 let fd: i64=sys_openat_rd(path) 28 if fd<0 { return 0-1 } 29 var n: i64=0 30 var go: i64=1 31 while go==1 { 32 let r: i64=sys_read(fd, ((buf as i64)+n) as *u8, cap-n) 33 if r<=0 { go=0 } else { n=n+r } 34 if n>=cap { go=0 } 35 } 36 sys_close(fd) 37 return n 38} 39func rg_has(b: *u8, n: i64, s: *u8) -> i64 { 40 let sl: i64=rg_slen(s) 41 if sl==0 { return 1 } 42 var i: i64=0 43 while i+sl<=n { 44 var m: i64=1; var j: i64=0 45 while j<sl { if b[i+j]!=s[j] { m=0; j=sl } else { j=j+1 } } 46 if m==1 { return 1 } 47 i=i+1 48 } 49 return 0 50} 51// run the reaper from `dir` with up to two names 52func rg_run(elf: *u8, dir: *u8, a1: *u8, a2: *u8) -> i64 { 53 let pid: i64=sys_fork() 54 if pid<0 { return 201 } 55 if pid==0 { 56 sys_chdir(dir) 57 let av: *i64=sys_mmap(64) as *i64 58 av[0]=elf as i64 59 av[1]=a1 as i64 60 if (a2 as i64)==0 { av[2]=0 } else { av[2]=a2 as i64; av[3]=0 } 61 sys_execve(elf, av, 0 as *i64) 62 sys_exit(127) 63 return 127 64 } 65 let stp: *i64=sys_mmap(16) as *i64 66 sys_wait4(pid, stp, 0) 67 return (stp[0]>>8)&255 68} 69 70func main(argc: i64, argv: *i64) -> i64 { 71 rg_w("=== nx_toolreg_reap_gate: reaps scaffolds, REFUSES live tools ===\n" as *u8) 72 var reaper: *u8 = "/volume1/homes/elderwesto/nishihost/nx_toolreg_reap.elf\x00" as *u8 73 if argc>=2 { reaper = argv[1] as *u8 } 74 rg_w("reaper-under-test: " as *u8); rg_w(reaper); rg_w("\n" as *u8) 75 var fails: i64=0 76 77 sys_mkdir("/tmp/trx\x00" as *u8, 0x1ed) 78 // A fixture registry: one scaffold (staged .new), one LIVE tool, one staged row we never name, 79 // and a row whose name is a strict PREFIX of the scaffold's -- the exact-match trap. 80 let conf: *u8 = "nx_keepme\t/volume1/x/nx_keepme.elf\tGREEN\nnx_scaffold_r11\t/volume1/x/nx_thing.sov.elf.new\tGREEN\nnx_scaffold_r1\t/volume1/x/nx_other.sov.elf.new\tGREEN\nnx_livetool\t/volume1/x/nx_livetool.elf\tGREEN\nnx_pinned\t/volume1/x/nx_pinned.elf\tGREEN\tsub arg\n\x00" as *u8 81 rg_wfile("/tmp/trx/tool_allowlist.conf\x00" as *u8, conf) 82 83 // T1 the scaffold goes 84 let rc1: i64 = rg_run(reaper, "/tmp/trx\x00" as *u8, "nx_scaffold_r11\x00" as *u8, 0 as *u8) 85 let b: *u8 = sys_mmap(65536) 86 var n: i64 = rg_read("/tmp/trx/tool_allowlist.conf\x00" as *u8, b, 65530) 87 var t1: i64=0 88 if rc1==0 { if n>0 { if rg_has(b, n, "nx_scaffold_r11\t\x00" as *u8)==0 { t1=1 } } } 89 if t1==1 { rg_w(" [PASS] " as *u8) } else { fails=fails+1; rg_w(" [FAIL] " as *u8) } 90 rg_w("T1 a staged .new scaffold row is REMOVED (rc=" as *u8); rg_wn(rc1); rg_w(")\n" as *u8) 91 92 // T2 THE TOOTH: the prefix-named sibling must SURVIVE -- exact field-0 match, never a prefix match 93 var t2: i64=0 94 if rg_has(b, n, "nx_scaffold_r1\t\x00" as *u8)==1 { t2=1 } 95 if t2==1 { rg_w(" [PASS] " as *u8) } else { fails=fails+1; rg_w(" [FAIL] " as *u8) } 96 rg_w("T2 TOOTH nx_scaffold_r1 SURVIVES reaping nx_scaffold_r11 (exact match, not prefix)\n" as *u8) 97 98 // T3 THE SAFETY TOOTH: an explicit request to reap a LIVE .elf row is REFUSED and the row stays 99 let rc3: i64 = rg_run(reaper, "/tmp/trx\x00" as *u8, "nx_livetool\x00" as *u8, 0 as *u8) 100 n = rg_read("/tmp/trx/tool_allowlist.conf\x00" as *u8, b, 65530) 101 var t3: i64=0 102 if rc3==0 { if rg_has(b, n, "nx_livetool\t\x00" as *u8)==1 { t3=1 } } 103 if t3==1 { rg_w(" [PASS] " as *u8) } else { fails=fails+1; rg_w(" [FAIL] " as *u8) } 104 rg_w("T3 TOOTH a promoted .elf row is REFUSED even when named explicitly -- cannot unregister a live tool\n" as *u8) 105 106 // T4 every unrelated row survives, INCLUDING the 4-field pinned-args row 107 var t4: i64=0 108 if rg_has(b, n, "nx_keepme\t\x00" as *u8)==1 { 109 if rg_has(b, n, "nx_pinned\t/volume1/x/nx_pinned.elf\tGREEN\tsub arg\x00" as *u8)==1 { t4=1 } } 110 if t4==1 { rg_w(" [PASS] " as *u8) } else { fails=fails+1; rg_w(" [FAIL] " as *u8) } 111 rg_w("T4 unrelated rows survive byte-for-byte, including a 4-field pinned-args row\n" as *u8) 112 113 // T5 an unknown name is a NO-OP that writes nothing (rewriting a shared conf to change nothing 114 // is how a concurrent reader gets a torn read for free) 115 let rc5: i64 = rg_run(reaper, "/tmp/trx\x00" as *u8, "nx_does_not_exist\x00" as *u8, 0 as *u8) 116 let b2: *u8 = sys_mmap(65536) 117 let n2: i64 = rg_read("/tmp/trx/tool_allowlist.conf\x00" as *u8, b2, 65530) 118 var t5: i64=0 119 if rc5==0 { if n2==n { t5=1 } } 120 if t5==1 { rg_w(" [PASS] " as *u8) } else { fails=fails+1; rg_w(" [FAIL] " as *u8) } 121 rg_w("T5 an unknown name is a NO-OP, byte count unchanged (" as *u8); rg_wn(n2); rg_w(")\n" as *u8) 122 123 // T6 fail-closed: no allowlist at all = exit 1, never a silent empty write 124 sys_mkdir("/tmp/trx_bare\x00" as *u8, 0x1ed) 125 let rc6: i64 = rg_run(reaper, "/tmp/trx_bare\x00" as *u8, "nx_anything\x00" as *u8, 0 as *u8) 126 var t6: i64=0 127 if rc6==1 { t6=1 } 128 if t6==1 { rg_w(" [PASS] " as *u8) } else { fails=fails+1; rg_w(" [FAIL] " as *u8) } 129 rg_w("T6 no allowlist = RED exit 1, never a silent empty write (rc=" as *u8); rg_wn(rc6); rg_w(")\n" as *u8) 130 131 if fails==0 { rg_w("TOOLREG-REAP GREEN 6/6 -- removes scaffolds, refuses live tools, no-ops safely\n" as *u8); sys_exit(0); return 0 } 132 rg_w("TOOLREG-REAP RED fails=" as *u8); rg_wn(fails); rg_w("\n" as *u8) 133 sys_exit(1) 134 return 1 135}