code wiki / _hdl_build / nx_hr_serve3_slot_gate.nx

nx_hr_serve3_slot_gate.nx source

↩ module page · 210 lines · 9296 B

1// nx_hr_serve3_slot_gate.nx -- GATE for hr_serve3_slot (universal ad-slot injection at the file server). 2// Proves on REAL files in a hermetic /tmp docroot: (T1) html gets the slot immediately before the LAST 3// </body> with a CORRECT Content-Length; (T2) non-html untouched; (T3) html without </body> untouched; 4// (T4) nx-ad-optout page untouched; (T5) slot_n==0 -> BYTE-IDENTICAL to hr_serve3 (the do-no-harm law); 5// (T6) canonical 301 path identical in both; (T7) helper detectors FIRE on planted vectors. 6// expect_exit: 0 license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "_hdl_build/nx_host_router.nx" 9 10func hg_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 11func hg_putn(v: i64) -> i64 { var m: i64 = v; if m < 0 { hg_puts("-" as *u8); m = 0 - m } let t: *u8 = sys_mmap(24); 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 } let o: *u8 = sys_mmap(24); var i: i64 = 0; while i < k { o[i] = t[k - 1 - i]; i = i + 1 } sys_write(1, o, k); return 0 } 12func hg_cat(dst: *u8, off: i64, s: *u8) -> i64 { var o: i64 = off; var i: i64 = 0; while s[i] != (0 as u8) { dst[o] = s[i]; o = o + 1; i = i + 1 } return o } 13 14func hg_has(hay: *u8, n: i64, needle: *u8) -> i64 { 15 var nl: i64 = 0 16 while needle[nl] != (0 as u8) { nl = nl + 1 } 17 if nl == 0 { return 0 } 18 var i: i64 = 0 19 while i + nl <= n { 20 var j: i64 = 0 21 var eq: i64 = 1 22 while j < nl { if hay[i + j] != needle[j] { eq = 0; break } j = j + 1 } 23 if eq == 1 { return 1 } 24 i = i + 1 25 } 26 return 0 27} 28 29func hg_memeq(a: *u8, b: *u8, n: i64) -> i64 { 30 var i: i64 = 0 31 while i < n { if a[i] != b[i] { return 0 } i = i + 1 } 32 return 1 33} 34 35func hg_wfile(path: *u8, content: *u8) -> i64 { 36 let fd: i64 = sys_openat_wr(path, 0x1A4) 37 if fd < 0 { return 0 } 38 var n: i64 = 0 39 while content[n] != (0 as u8) { n = n + 1 } 40 sys_write(fd, content, n) 41 sys_close(fd) 42 return 1 43} 44 45// parse "Content-Length: <N>" out of resp; then verify bytes after CRLFCRLF == N. 1 = coherent. 46func hg_cl_coherent(resp: *u8, n: i64) -> i64 { 47 var cl: i64 = 0 - 1 48 var i: i64 = 0 49 while i + 16 <= n { 50 if resp[i] == (67 as u8) { 51 if hg_memeq(((resp as i64 + i) as *u8), "Content-Length: " as *u8, 16) == 1 { 52 var v: i64 = 0 53 var k: i64 = i + 16 54 while k < n { let c: u8 = resp[k]; if c < (48 as u8) { break } if c > (57 as u8) { break } v = v * 10 + ((c as i64) - 48); k = k + 1 } 55 cl = v 56 break 57 } 58 } 59 i = i + 1 60 } 61 if cl < 0 { return 0 } 62 var hoff: i64 = 0 - 1 63 i = 0 64 while i + 4 <= n { 65 if resp[i] == (13 as u8) { 66 if resp[i + 1] == (10 as u8) { if resp[i + 2] == (13 as u8) { if resp[i + 3] == (10 as u8) { hoff = i + 4; break } } } 67 } 68 i = i + 1 69 } 70 if hoff < 0 { return 0 } 71 if n - hoff == cl { return 1 } 72 return 0 73} 74 75func hg_req(dst: *u8, path: *u8) -> i64 { 76 var o: i64 = 0 77 o = hg_cat(dst, o, "GET " as *u8) 78 o = hg_cat(dst, o, path) 79 o = hg_cat(dst, o, " HTTP/1.1\r\nHost: nishifamily.com\r\nAccept: text/html\r\n\r\n" as *u8) 80 return o 81} 82 83func main() -> i64 { 84 hg_puts("=== nx_hr_serve3_slot_gate ===\n" as *u8) 85 var pass: i64 = 0 86 var fail: i64 = 0 87 88 sys_mkdir("/tmp/hrslot_root" as *u8, 0x1ED) 89 var wok: i64 = 0 90 wok = wok + hg_wfile("/tmp/hrslot_root/index.html" as *u8, "<html><head><title>T</title></head><body><p>Hello</p></body></html>" as *u8) 91 wok = wok + hg_wfile("/tmp/hrslot_root/style.css" as *u8, "body{color:red}" as *u8) 92 wok = wok + hg_wfile("/tmp/hrslot_root/noclose.html" as *u8, "<html><body><p>no close tag here" as *u8) 93 wok = wok + hg_wfile("/tmp/hrslot_root/optout.html" as *u8, "<html><body><span>nx-ad-optout</span><p>quiet page</p></body></html>" as *u8) 94 if wok == 4 { pass = pass + 1 } else { fail = fail + 1; hg_puts("SETUP FAIL files\n" as *u8) } 95 96 let cfg: *u8 = sys_mmap(256) 97 var cfgn: i64 = 0 98 cfgn = hg_cat(cfg, cfgn, "nishifamily.com /tmp/hrslot_root" as *u8) 99 cfg[cfgn] = 10 as u8 100 cfgn = cfgn + 1 101 102 let req: *u8 = sys_mmap(1024) 103 let outA: *u8 = sys_mmap(262144) 104 let outB: *u8 = sys_mmap(262144) 105 let nA: *i64 = (sys_mmap(8)) as *i64 106 let nB: *i64 = (sys_mmap(8)) as *i64 107 let inj: *i64 = (sys_mmap(8)) as *i64 108 let slot: *u8 = "<aside class=nx-ad-slot>AD HERE</aside>" as *u8 109 let slotn: i64 = hr_slen(slot) 110 111 // T1 inject into html + correct Content-Length + slot sits right before </body> 112 let rq1: i64 = hg_req(req, "/" as *u8) 113 let v1: i64 = hr_serve3_slot(cfg, cfgn, req, rq1, outB, 262144, nB, slot, slotn, inj) 114 var t1: i64 = 1 115 if v1 != HR_S2_OK { t1 = 0 } 116 if inj[0] != 1 { t1 = 0 } 117 if hg_has(outB, nB[0], "AD HERE</aside></body>" as *u8) == 0 { t1 = 0 } 118 if hg_cl_coherent(outB, nB[0]) == 0 { t1 = 0 } 119 if t1 == 1 { pass = pass + 1 } else { fail = fail + 1; hg_puts("T1 FAIL html inject\n" as *u8) } 120 121 // T2 css untouched (no injection, still OK, CL coherent) 122 let rq2: i64 = hg_req(req, "/style.css" as *u8) 123 let v2: i64 = hr_serve3_slot(cfg, cfgn, req, rq2, outB, 262144, nB, slot, slotn, inj) 124 var t2: i64 = 1 125 if v2 != HR_S2_OK { t2 = 0 } 126 if inj[0] != 0 { t2 = 0 } 127 if hg_has(outB, nB[0], "nx-ad-slot" as *u8) == 1 { t2 = 0 } 128 if hg_cl_coherent(outB, nB[0]) == 0 { t2 = 0 } 129 if t2 == 1 { pass = pass + 1 } else { fail = fail + 1; hg_puts("T2 FAIL css untouched\n" as *u8) } 130 131 // T3 html without </body> untouched 132 let rq3: i64 = hg_req(req, "/noclose" as *u8) 133 let v3: i64 = hr_serve3_slot(cfg, cfgn, req, rq3, outB, 262144, nB, slot, slotn, inj) 134 var t3: i64 = 1 135 if v3 != HR_S2_OK { t3 = 0 } 136 if inj[0] != 0 { t3 = 0 } 137 if hg_has(outB, nB[0], "AD HERE" as *u8) == 1 { t3 = 0 } 138 if t3 == 1 { pass = pass + 1 } else { fail = fail + 1; hg_puts("T3 FAIL noclose untouched\n" as *u8) } 139 140 // T4 optout page untouched 141 let rq4: i64 = hg_req(req, "/optout" as *u8) 142 let v4: i64 = hr_serve3_slot(cfg, cfgn, req, rq4, outB, 262144, nB, slot, slotn, inj) 143 var t4: i64 = 1 144 if v4 != HR_S2_OK { t4 = 0 } 145 if inj[0] != 0 { t4 = 0 } 146 if hg_has(outB, nB[0], "AD HERE" as *u8) == 1 { t4 = 0 } 147 if t4 == 1 { pass = pass + 1 } else { fail = fail + 1; hg_puts("T4 FAIL optout untouched\n" as *u8) } 148 149 // T5 do-no-harm: slot_n==0 -> BYTE-IDENTICAL to hr_serve3 (html + css + optout) 150 var t5: i64 = 1 151 let rq5: i64 = hg_req(req, "/" as *u8) 152 let va: i64 = hr_serve3(cfg, cfgn, req, rq5, outA, 262144, nA) 153 let vb: i64 = hr_serve3_slot(cfg, cfgn, req, rq5, outB, 262144, nB, slot, 0, inj) 154 if va != vb { t5 = 0 } 155 if nA[0] != nB[0] { t5 = 0 } 156 if hg_memeq(outA, outB, nA[0]) == 0 { t5 = 0 } 157 if inj[0] != 0 { t5 = 0 } 158 let rq5b: i64 = hg_req(req, "/style.css" as *u8) 159 let va2: i64 = hr_serve3(cfg, cfgn, req, rq5b, outA, 262144, nA) 160 let vb2: i64 = hr_serve3_slot(cfg, cfgn, req, rq5b, outB, 262144, nB, slot, 0, inj) 161 if va2 != vb2 { t5 = 0 } 162 if nA[0] != nB[0] { t5 = 0 } 163 if hg_memeq(outA, outB, nA[0]) == 0 { t5 = 0 } 164 if t5 == 1 { pass = pass + 1 } else { fail = fail + 1; hg_puts("T5 FAIL byte-identical control\n" as *u8) } 165 166 // T6 canonical 301 identical in both (slot never touches redirects) 167 var t6: i64 = 1 168 let rq6: i64 = hg_req(req, "/index.html" as *u8) 169 let vc: i64 = hr_serve3(cfg, cfgn, req, rq6, outA, 262144, nA) 170 let vd: i64 = hr_serve3_slot(cfg, cfgn, req, rq6, outB, 262144, nB, slot, slotn, inj) 171 if vc != HR_S2_REDIR { t6 = 0 } 172 if vd != HR_S2_REDIR { t6 = 0 } 173 if nA[0] != nB[0] { t6 = 0 } 174 if hg_memeq(outA, outB, nA[0]) == 0 { t6 = 0 } 175 if inj[0] != 0 { t6 = 0 } 176 if t6 == 1 { pass = pass + 1 } else { fail = fail + 1; hg_puts("T6 FAIL redirect identical\n" as *u8) } 177 178 // T7 detectors fire (anti-false-green) 179 var t7: i64 = 1 180 let ob: *u8 = "abc nx-ad-optout xyz" as *u8 181 if hr_has_optout(ob, 20) == 0 { t7 = 0 } 182 let cb: *u8 = "no close body here at all" as *u8 183 let fcb: i64 = hr_find_close_body(cb, 25) 184 if fcb >= 0 { t7 = 0 } 185 let hb: *u8 = "<html><body>x</body>" as *u8 186 let fcb2: i64 = hr_find_close_body(hb, 20) 187 if fcb2 != 13 { t7 = 0 } 188 if hr_ct_is_html("text/css" as *u8) == 1 { t7 = 0 } 189 if hr_ct_is_html("text/html; charset=utf-8" as *u8) == 0 { t7 = 0 } 190 if t7 == 1 { pass = pass + 1 } else { fail = fail + 1; hg_puts("T7 FAIL detectors\n" as *u8) } 191 192 hg_puts("pass=" as *u8) 193 hg_putn(pass) 194 hg_puts(" fail=" as *u8) 195 hg_putn(fail) 196 hg_puts("\n" as *u8) 197 198 let log: *u8 = sys_mmap(256) 199 var lo: i64 = 0 200 if fail == 0 { lo = hg_cat(log, lo, "HRSLOTGATE authored=organ verdict=GREEN" as *u8) } else { lo = hg_cat(log, lo, "HRSLOTGATE authored=organ verdict=RED" as *u8) } 201 log[lo] = 10 as u8 202 lo = lo + 1 203 let fd: i64 = sys_openat_wr("knowledge/status/hr_serve3_slot.log" as *u8, 0x1A4) 204 if fd >= 0 { sys_write(fd, log, lo); sys_close(fd) } 205 206 if fail == 0 { hg_puts("=== HR-SERVE3-SLOT-GATE verdict=GREEN ===\n" as *u8); sys_exit(0); return 0 } 207 hg_puts("=== HR-SERVE3-SLOT-GATE verdict=RED ===\n" as *u8) 208 sys_exit(1) 209 return 1 210}