code wiki / _hdl_build / nx_cms_redirect_exceed_gate.nx
nx_cms_redirect_exceed_gate.nx source
↩ module page · 171 lines · 9175 B
1// nx_cms_redirect_exceed_gate.nx -- the FIRST W-RE-004 head-to-head EXCEED (redirects-404, safety axis).
2// Runs BOTH sides on the SAME corpus of Location values:
3// OURS = _redirect_location_is_safe (the shipped guard)
4// INCUMBENT = the documented no-guard baseline (accept any non-empty Location) -- the CWE-113 /
5// CWE-601 failure mode of redirect handlers that don't reject CR/LF/NUL in a Location
6// (a class WordPress redirect plugins have shipped CVEs for).
7// Ground truth per case: SAFE iff it contains no CR(0x0d)/LF(0x0a)/NUL(0x00). The harness nx_cms_exceed
8// COMPUTES the verdict from the measured scores; the gate also self-tests that the harness CANNOT
9// false-green (rejects an overclaim, reports PARITY/BEHIND honestly). Writes a CMSEXCEED line to
10// knowledge/status/cms_exceed.log ONLY on a measured AHEAD + referee-clean + self-tests pass. Exit 0 iff so.
11// license_tier: ORIGINAL
12import "nx_cms_exceed.nx"
13import "nx_http_resolve_redirect.nx"
14import "nx_syscalls.nx"
15
16func xg_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
17func xg_num(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;k=1}; while m>0{t[k]=48+(m%10);m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(1,bb,k); return 0 }
18func xg_cat(dst: *u8, off: i64, s: *u8) -> i64 { var o: i64=off; var k: i64=0; while s[k]!=(0 as u8){dst[o]=s[k];o=o+1;k=k+1} return o }
19func xg_catnum(dst: *u8, off: i64, v: i64) -> i64 {
20 var o: i64=off; let t: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m}; var k: i64=0
21 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}
22 var i: i64=0; while i<k {dst[o]=t[k-1-i]; o=o+1; i=i+1} return o
23}
24func xg_row(id: i64, ok: i64, what: *u8) -> i64 {
25 xg_w("XCDROW " as *u8); xg_num(id); xg_w(" " as *u8)
26 if ok==1 { xg_w("PASS " as *u8) } else { xg_w("FAIL " as *u8) }
27 xg_w(what); xg_w("\n" as *u8)
28 return ok
29}
30
31// incumbent oracle = the documented no-guard baseline: accept any non-empty Location (no CR/LF/NUL check).
32func xg_incumbent_accept(loc: *u8, n: i64) -> i64 { if n > 0 { return 1 } return 0 }
33
34// ground truth: 1 = SAFE (no header-injection bytes), 0 = malicious
35func xg_truth_safe(loc: *u8, n: i64) -> i64 {
36 if n <= 0 { return 0 }
37 var i: i64 = 0
38 while i < n {
39 let b: i64 = loc[i] as i64
40 if b == 0x0d { return 0 }
41 if b == 0x0a { return 0 }
42 if b == 0x00 { return 0 }
43 i = i + 1
44 }
45 return 1
46}
47
48func xg_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
49
50func main() -> i64 {
51 var pass: i64 = 0
52 var rows: i64 = 0
53
54 // ---- corpus: parallel arrays of (ptr, len). Clean first, then CWE-113 injections. ----
55 let ptrs: *i64 = sys_mmap(8 * 32) as *i64
56 let lens: *i64 = sys_mmap(8 * 32) as *i64
57 var nc: i64 = 0
58
59 // clean Location values (legit redirects -- both sides SHOULD accept)
60 let c0: *u8 = "/practice/estate-planning" as *u8
61 ptrs[nc]=c0 as i64; lens[nc]=xg_slen(c0); nc=nc+1
62 let c1: *u8 = "/contact" as *u8
63 ptrs[nc]=c1 as i64; lens[nc]=xg_slen(c1); nc=nc+1
64 let c2: *u8 = "/blog/post?x=1&y=2" as *u8
65 ptrs[nc]=c2 as i64; lens[nc]=xg_slen(c2); nc=nc+1
66 let c3: *u8 = "/a/b/c" as *u8
67 ptrs[nc]=c3 as i64; lens[nc]=xg_slen(c3); nc=nc+1
68
69 // CWE-113 header-injection payloads (built with raw bytes; OURS must reject all)
70 // m0: CRLF + Set-Cookie
71 let m0: *u8 = sys_mmap(64)
72 m0[0]=47; m0[1]=120; m0[2]=0x0d; m0[3]=0x0a; var o0: i64=xg_cat(m0,4,"Set-Cookie: evil=1" as *u8)
73 ptrs[nc]=m0 as i64; lens[nc]=o0; nc=nc+1
74 // m1: bare LF
75 let m1: *u8 = sys_mmap(64)
76 m1[0]=47; m1[1]=120; m1[2]=0x0a; var o1: i64=xg_cat(m1,3,"Set-Cookie: y" as *u8)
77 ptrs[nc]=m1 as i64; lens[nc]=o1; nc=nc+1
78 // m2: bare CR
79 let m2: *u8 = sys_mmap(64)
80 m2[0]=47; m2[1]=120; m2[2]=0x0d; var o2: i64=xg_cat(m2,3,"Location: http://evil" as *u8)
81 ptrs[nc]=m2 as i64; lens[nc]=o2; nc=nc+1
82 // m3: NUL truncation
83 let m3: *u8 = sys_mmap(64)
84 m3[0]=47; m3[1]=120; m3[2]=0x00; var o3: i64=xg_cat(m3,3,"/admin" as *u8)
85 ptrs[nc]=m3 as i64; lens[nc]=o3; nc=nc+1
86 // m4: leading CRLF response-splitting
87 let m4: *u8 = sys_mmap(64)
88 m4[0]=0x0d; m4[1]=0x0a; var o4: i64=xg_cat(m4,2,"HTTP/1.1 200 OK" as *u8)
89 ptrs[nc]=m4 as i64; lens[nc]=o4; nc=nc+1
90
91 // ---- run BOTH sides on the same corpus; measure ----
92 var our_correct: i64 = 0
93 var inc_correct: i64 = 0
94 var n_mal: i64 = 0
95 var safety_our: i64 = 0
96 var safety_inc: i64 = 0
97 var i: i64 = 0
98 while i < nc {
99 let p: *u8 = (ptrs[i]) as *u8
100 let ln: i64 = lens[i]
101 let truth: i64 = xg_truth_safe(p, ln)
102 let our_v: i64 = _redirect_location_is_safe(p, ln)
103 let inc_v: i64 = xg_incumbent_accept(p, ln)
104 if our_v == truth { our_correct = our_correct + 1 }
105 if inc_v == truth { inc_correct = inc_correct + 1 }
106 if truth == 0 {
107 n_mal = n_mal + 1
108 if our_v == 0 { safety_our = safety_our + 1 }
109 if inc_v == 0 { safety_inc = safety_inc + 1 }
110 }
111 i = i + 1
112 }
113
114 let verdict: i64 = xcd_verdict(our_correct, inc_correct)
115
116 xg_w("HEAD-TO-HEAD redirects-404 safety: ours=" as *u8); xg_num(our_correct)
117 xg_w("/" as *u8); xg_num(nc); xg_w(" incumbent=" as *u8); xg_num(inc_correct); xg_w("/" as *u8); xg_num(nc)
118 xg_w(" injections-blocked ours=" as *u8); xg_num(safety_our); xg_w("/" as *u8); xg_num(n_mal)
119 xg_w(" incumbent=" as *u8); xg_num(safety_inc); xg_w("/" as *u8); xg_num(n_mal)
120 xg_w(" verdict=" as *u8); xg_w(xcd_vname(verdict)); xg_w("\n" as *u8)
121
122 // R0: OURS is fully correct (blocks every injection AND keeps every legit redirect)
123 var ok: i64 = 0; if our_correct == nc { ok = 1 }
124 rows=rows+1; pass=pass+xg_row(0, ok, "ours fully correct (all injections blocked, no legit redirect broken)" as *u8)
125
126 // R1: the incumbent no-guard baseline is NOT fully correct (it accepts the injections)
127 ok = 0; if inc_correct < nc { ok = 1 }
128 rows=rows+1; pass=pass+xg_row(1, ok, "incumbent no-guard baseline fails (accepts CWE-113 injections)" as *u8)
129
130 // R2: the measured verdict is AHEAD
131 ok = 0; if verdict == XCD_AHEAD { ok = 1 }
132 rows=rows+1; pass=pass+xg_row(2, ok, "measured verdict = AHEAD (ours strictly beats incumbent)" as *u8)
133
134 // R3: safety axis is fully won: ours blocks all injections, incumbent blocks none
135 ok = 0; if safety_our == n_mal { if safety_inc == 0 { if n_mal > 0 { ok = 1 } } }
136 rows=rows+1; pass=pass+xg_row(3, ok, "safety axis: ours blocks all injections, incumbent blocks 0" as *u8)
137
138 // R4: REFEREE accepts this honest AHEAD claim (real measurement + ours fully correct)
139 ok = 0; if xcd_referee_ok(XCD_AHEAD, our_correct, nc) == 1 { ok = 1 }
140 rows=rows+1; pass=pass+xg_row(4, ok, "referee accepts honest AHEAD claim" as *u8)
141
142 // R5 (anti-false-green): referee REJECTS an overclaim (AHEAD while still failing a case)
143 ok = 0; if xcd_referee_ok(XCD_AHEAD, nc - 1, nc) == 0 { if xcd_referee_ok(XCD_AHEAD, 1, 0) == 0 { ok = 1 } }
144 rows=rows+1; pass=pass+xg_row(5, ok, "referee rejects overclaim (less-wrong != ahead; no-measurement != win)" as *u8)
145
146 // R6 (anti-false-green): harness reports non-wins honestly (PARITY when equal, BEHIND when worse)
147 ok = 0; if xcd_verdict(5, 5) == XCD_PARITY { if xcd_verdict(3, 7) == XCD_BEHIND { ok = 1 } }
148 rows=rows+1; pass=pass+xg_row(6, ok, "harness reports PARITY/BEHIND honestly (cannot only-ever-win)" as *u8)
149
150 xg_w("CMS-REDIRECT-EXCEED-GATE rows=" as *u8); xg_num(rows); xg_w(" pass=" as *u8); xg_num(pass); xg_w("\n" as *u8)
151
152 // honest gate: record only if measured AHEAD + referee clean + self-tests all pass
153 if pass == rows {
154 if verdict == XCD_AHEAD {
155 if xcd_referee_ok(XCD_AHEAD, our_correct, nc) == 1 {
156 let line: *u8 = sys_mmap(256)
157 var lo: i64 = xg_cat(line, 0, "CMSEXCEED feature=redirects-404 axis=safety cwe=CWE-113/601 ours=" as *u8)
158 lo = xg_catnum(line, lo, our_correct); lo = xg_cat(line, lo, "/" as *u8); lo = xg_catnum(line, lo, nc)
159 lo = xg_cat(line, lo, " incumbent=" as *u8); lo = xg_catnum(line, lo, inc_correct); lo = xg_cat(line, lo, "/" as *u8); lo = xg_catnum(line, lo, nc)
160 lo = xg_cat(line, lo, " injections-blocked=" as *u8); lo = xg_catnum(line, lo, safety_our); lo = xg_cat(line, lo, "/" as *u8); lo = xg_catnum(line, lo, n_mal)
161 lo = xg_cat(line, lo, " verdict=AHEAD\n" as *u8)
162 let gf: i64 = sys_openat_append("knowledge/status/cms_exceed.log" as *u8, 0x1a4)
163 if gf >= 0 { sys_write(gf, line, lo); sys_close(gf) }
164 xg_w("CMS-REDIRECT-EXCEED-GATE verdict=AHEAD -- measured EXCEED recorded in cms_exceed.log\n" as *u8)
165 sys_exit(0); return 0
166 }
167 }
168 }
169 xg_w("CMS-REDIRECT-EXCEED-GATE verdict=NOT-RECORDED (no fake-green: needs measured AHEAD + referee + self-tests)\n" as *u8)
170 sys_exit(1); return 1
171}