nx_syscall_sanity_kat.nx source
↩ module page · 67 lines · 2998 B
1// nx_syscall_sanity_kat.nx -- T11 class: the SYSCALL-NUMBER COLLISION gate that
2// would have caught the whole class. The x86 backend feeds const syscall numbers
3// through an RV64->x86_64 translator; an x86_64 number that collides with an RV64
4// key was silently mistranslated (clone56->openat, execve59->pipe, wait4 61->
5// getdents, socket41->unshare, kill62->lseek). Each miscompile produces WRONG
6// RUNTIME BEHAVIOR, so exercising every collision-prone wrapper and asserting a
7// sane result catches any regression. Self-checking: exit 0 == all correct.
8// See reference-syscall-number-rv64-x86-collision-2026-07-16.
9// license_tier: ORIGINAL No hw writes (Rule 26).
10import "nx_syscalls_x86_64.nx"
11
12func main() -> i64 {
13 // socket (was 41->unshare): a real AF_INET stream socket returns a fd >= 0.
14 let fd: i64 = sys_socket(2, 1, 0)
15 if fd < 0 { return 1 }
16 sys_close(fd)
17
18 // pipe2 (293, control -- must not have regressed): returns 0 + two fds. ⚠PACKED-INT32: the kernel
19 // writes BOTH int32 fds into fds[0] (read=low half, write=HIGH half); fds[1] is never written.
20 // The old form read fds[1] and false-passed on the -1 sentinel's low bits (2026-07-16 fix, caught
21 // by nx_syscalls_gate K8 hanging on the garbage write fd). Behavioral: close must SUCCEED on both.
22 let fds: *i64 = sys_mmap(16) as *i64
23 fds[0] = 0 - 1; fds[1] = 0 - 1
24 let pr: i64 = sys_pipe2(fds, 0)
25 if pr != 0 { return 2 }
26 let rfd: i64 = (fds[0]) & 0xffffffff
27 let wfd: i64 = ((fds[0]) / 4294967296) & 0xffffffff
28 if rfd < 0 { return 3 }
29 if wfd < 0 { return 4 }
30 if sys_close(rfd) != 0 { return 3 }
31 if sys_close(wfd) != 0 { return 4 }
32
33 // getuid/getgid (102/104, control): non-negative.
34 if sys_getuid() < 0 { return 5 }
35 if sys_getgid() < 0 { return 6 }
36
37 // clone(220)+wait4(260): fork a child that exits 7; the parent must capture 7.
38 // A clone->openat miscompile makes fork return -14 (EFAULT); a wait4->getdents
39 // miscompile makes the captured code garbage.
40 let pid: i64 = sys_fork()
41 if pid < 0 { return 7 }
42 if pid == 0 { sys_exit(7) }
43 let st: *i64 = sys_mmap(16) as *i64
44 *st = 0
45 sys_wait4(pid, st, 0)
46 let code: i64 = (*st >> 8) & 0xFF
47 if code != 7 { return 8 }
48
49 // execve(221): fork a child that execs /bin/true (exit 0); parent captures 0.
50 // execve->pipe miscompile makes the child NOT exec (falls through, wrong exit).
51 let pid2: i64 = sys_fork()
52 if pid2 < 0 { return 9 }
53 if pid2 == 0 {
54 let ep: *u8 = "/bin/true" as *u8
55 let av: *i64 = sys_mmap(16) as *i64
56 av[0] = ep as i64; av[1] = 0
57 sys_execve(ep, av, 0 as *i64)
58 sys_exit(42) // only reached if execve FAILED (or was miscompiled to pipe)
59 }
60 let st2: *i64 = sys_mmap(16) as *i64
61 *st2 = 0
62 sys_wait4(pid2, st2, 0)
63 let code2: i64 = (*st2 >> 8) & 0xFF
64 if code2 != 0 { return 10 } // /bin/true exits 0; 42 means execve did not exec
65
66 return 0
67}