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}