code wiki / (root) / nx_path_canonicalize_test.nx

nx_path_canonicalize_test.nx source

↩ module page · 135 lines · 4956 B

1// nx_path_canonicalize_test.nx -- structural smoke + CWE-22 attack 2// corpus. 3// 4// expect_exit: 0 5// 6// license_tier: ORIGINAL 7 8import "nx_syscalls_x86_64.nx" 9import "nx_path_canonicalize.nx" 10 11func bytes_eq(a: *u8, b: *u8, n: i64) -> i64 { 12 var i: i64 = 0 13 while i < n { 14 if a[i] != b[i] { return 0 } 15 i = i + 1 16 } 17 return 1 18} 19 20// Helper: assert verdict matches expected. 21func check_v(src: *u8, src_n: i64, max_out: i64, 22 expect_v: i64, err: i64) -> i64 { 23 let buf: *u8 = sys_mmap(1024) 24 let on: *i64 = sys_mmap(8) as *i64 25 let v: i64 = nx_path_canonicalize(src, src_n, buf, max_out, on) 26 if v != expect_v { return err } 27 return 0 28} 29 30func main() -> i64 { 31 // ---- Verdict enum gate ---- 32 if nxp_verdict_is_valid(NXP_OK) != 1 { return 1 } 33 if nxp_verdict_is_valid(NXP_TRAVERSAL) != 1 { return 2 } 34 if nxp_verdict_is_valid(NXP_BAD_ARG) != 1 { return 3 } 35 if nxp_verdict_is_valid(NXP_VERDICT_N) != 0 { return 4 } 36 if nxp_verdict_is_valid(-1) != 0 { return 5 } 37 38 if bytes_eq(nxp_verdict_name(NXP_TRAVERSAL), "TRAVERSAL" as *u8, 9) != 1 { return 6 } 39 if bytes_eq(nxp_verdict_name(NXP_NUL), "NUL" as *u8, 3) != 1 { return 7 } 40 if bytes_eq(nxp_verdict_name(NXP_BACKSLASH), "BACKSLASH" as *u8, 9) != 1 { return 8 } 41 if bytes_eq(nxp_verdict_name(NXP_TOO_LONG), "TOO_LONG" as *u8, 8) != 1 { return 9 } 42 43 // ---- Empty path ---- 44 var rc: i64 = check_v("" as *u8, 0, 1024, NXP_EMPTY, 10) 45 if rc != 0 { return rc } 46 47 // ---- TOO_LONG ---- 48 rc = check_v("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" as *u8, 40, 10, NXP_TOO_LONG, 20) 49 if rc != 0 { return rc } 50 51 // ---- Valid simple path ---- 52 let buf: *u8 = sys_mmap(1024) 53 let on: *i64 = sys_mmap(8) as *i64 54 let v1: i64 = nx_path_canonicalize("audit/index.html" as *u8, 16, buf, 1024, on) 55 if v1 != NXP_OK { return 30 } 56 if on[0] != 16 { return 31 } 57 if bytes_eq(buf, "audit/index.html" as *u8, 16) != 1 { return 32 } 58 59 // ---- Valid: ..foo (filename starts with two dots, NOT traversal) ---- 60 let v2: i64 = nx_path_canonicalize("..bashrc" as *u8, 8, buf, 1024, on) 61 if v2 != NXP_OK { return 40 } 62 63 // ---- Valid: docs/..foo (segment-boundary-aware) ---- 64 let v2b: i64 = nx_path_canonicalize("docs/..foo" as *u8, 10, buf, 1024, on) 65 if v2b != NXP_OK { return 41 } 66 67 // ---- CWE-22 attack vectors ---- 68 69 // 1. classic ../../../etc/passwd 70 rc = check_v("../../../etc/passwd" as *u8, 19, 1024, NXP_TRAVERSAL, 100) 71 if rc != 0 { return rc } 72 73 // 2. ../etc/passwd (single ..) 74 rc = check_v("../etc/passwd" as *u8, 13, 1024, NXP_TRAVERSAL, 110) 75 if rc != 0 { return rc } 76 77 // 3. just .. 78 rc = check_v(".." as *u8, 2, 1024, NXP_TRAVERSAL, 120) 79 if rc != 0 { return rc } 80 81 // 4. dir/.. (trailing traversal) 82 rc = check_v("dir/.." as *u8, 6, 1024, NXP_TRAVERSAL, 130) 83 if rc != 0 { return rc } 84 85 // 5. dir/../file (middle traversal) 86 rc = check_v("dir/../file" as *u8, 11, 1024, NXP_TRAVERSAL, 140) 87 if rc != 0 { return rc } 88 89 // 6. absolute path (caller's base would be ignored) 90 rc = check_v("/etc/passwd" as *u8, 11, 1024, NXP_TRAVERSAL, 150) 91 if rc != 0 { return rc } 92 93 // 7. NUL byte truncation attack: "ok\0.png" 94 let nul_buf: *u8 = sys_mmap(16) 95 nul_buf[0] = 0x6f as u8 // o 96 nul_buf[1] = 0x6b as u8 // k 97 nul_buf[2] = 0 as u8 // NUL 98 nul_buf[3] = 0x2e as u8 // . 99 nul_buf[4] = 0x70 as u8 // p 100 nul_buf[5] = 0x6e as u8 // n 101 nul_buf[6] = 0x67 as u8 // g 102 rc = check_v(nul_buf, 7, 1024, NXP_NUL, 160) 103 if rc != 0 { return rc } 104 105 // 8. backslash (no Windows-path confusion on POSIX target) 106 rc = check_v("dir\\file" as *u8, 8, 1024, NXP_BACKSLASH, 170) 107 if rc != 0 { return rc } 108 109 // ---- BAD_ARG paths ---- 110 let bb: *u8 = sys_mmap(64) 111 let bn: *i64 = sys_mmap(8) as *i64 112 if nx_path_canonicalize(0 as *u8, 10, bb, 64, bn) != NXP_BAD_ARG { return 180 } 113 if nx_path_canonicalize("x" as *u8, 1, 0 as *u8, 64, bn) != NXP_BAD_ARG { return 181 } 114 if nx_path_canonicalize("x" as *u8, 1, bb, 64, 0 as *i64) != NXP_BAD_ARG { return 182 } 115 if nx_path_canonicalize("x" as *u8, -1, bb, 64, bn) != NXP_BAD_ARG { return 183 } 116 if nx_path_canonicalize("x" as *u8, 1, bb, 0, bn) != NXP_BAD_ARG { return 184 } 117 118 // ---- nx_path_join ---- 119 let jbuf: *u8 = sys_mmap(64) 120 let jn: *i64 = sys_mmap(8) as *i64 121 let jv: i64 = nx_path_join("/var/www" as *u8, 8, 122 "audit/index.html" as *u8, 16, 123 jbuf, 64, jn) 124 if jv != NXP_OK { return 200 } 125 if jn[0] != 25 { return 201 } 126 if bytes_eq(jbuf, "/var/www/audit/index.html" as *u8, 25) != 1 { return 202 } 127 128 // join TOO_LONG 129 let jv2: i64 = nx_path_join("/var/www" as *u8, 8, 130 "abcdef" as *u8, 6, 131 jbuf, 10, jn) 132 if jv2 != NXP_TOO_LONG { return 210 } 133 134 return 0 135}