code wiki / _hdl_build / nx_syscall_xlate_gate.nx
nx_syscall_xlate_gate.nx source
↩ module page · 95 lines · 6533 B
1// nx_syscall_xlate_gate.nx -- RATCHET gate for the compiler's rv64->x86_64 syscall translation
2// table (x86ctx_rv64_to_x86_64_syscall in nx_x86_64_ctx.nx). The process-IDENTITY family was MISSING:
3// a const rv64 getpid(172) fell through `return num` to raw x86_64 172=iopl -> -ENOSYS (-38). That
4// silently filled a loop-singleton pidfile with -38 and the gate FAILED OPEN (two daemons raced --
5// see nx_gate_loop_register X-GETPID-XLATE). nx_signal/nx_swarm_queue/nx_rv64_sim/ml_pid_alive all
6// wanted getpid via 172 and were silently broken.
7//
8// This gate calls each identity syscall via its rv64/asm-generic CONST number (exercising the
9// const-translation path I fixed) and asserts a NON-ERROR result. A -errno (e.g. -38 ENOSYS from an
10// un-translated passthrough) is negative and fails. If ANY row is dropped from the table, this goes RED.
11// One test per row added (172/173/174/175/176/177). license_tier: ORIGINAL expect_exit:0
12import "nx_syscalls.nx"
13
14// asm-generic / rv64 identity syscall numbers (the compiler translates these to x86_64 39/110/102/107/104/108).
15const RV_GETPID: i64 = 172
16const RV_GETPPID: i64 = 173
17const RV_GETUID: i64 = 174
18const RV_GETEUID: i64 = 175
19const RV_GETGID: i64 = 176
20const RV_GETEGID: i64 = 177
21
22func w(s: *u8) -> i64 { var k:i64=0; while s[k]!=(0 as u8){k=k+1} sys_write(1,s,k); return 0 }
23func n(v: i64) -> i64 { let b:*u8=sys_mmap(24); var m:i64=v; if m<0{sys_write(1,"-" as *u8,1);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} var j:i64=0; while j<k{b[j]=t[k-1-j];j=j+1} sys_write(1,b,k); return 0 }
24
25func main() -> i64 {
26 var pass: i64 = 0
27
28 // T1: getpid (172 -> 39). A real process pid is always > 0. -ENOSYS(-38) fails.
29 let pid: i64 = __syscall(RV_GETPID, 0, 0, 0, 0, 0, 0)
30 if pid > 0 { pass = pass + 1; w("T1 getpid(172->39)=" as *u8); n(pid); w(" PASS\n" as *u8) } else { w("T1 FAIL getpid=" as *u8); n(pid); w(" (un-translated -> iopl/-ENOSYS)\n" as *u8) }
31
32 // T2: getppid (173 -> 110). Parent pid > 0 for any normally-launched process.
33 let ppid: i64 = __syscall(RV_GETPPID, 0, 0, 0, 0, 0, 0)
34 if ppid > 0 { pass = pass + 1; w("T2 getppid(173->110)=" as *u8); n(ppid); w(" PASS\n" as *u8) } else { w("T2 FAIL getppid=" as *u8); n(ppid); w("\n" as *u8) }
35
36 // T3: getuid (174 -> 102). uid >= 0 (root==0 is valid); a -errno is negative.
37 let uid: i64 = __syscall(RV_GETUID, 0, 0, 0, 0, 0, 0)
38 if uid >= 0 { pass = pass + 1; w("T3 getuid(174->102)=" as *u8); n(uid); w(" PASS\n" as *u8) } else { w("T3 FAIL getuid=" as *u8); n(uid); w("\n" as *u8) }
39
40 // T7: fcntl (25 -> 72). THE ROW THAT WAS MISSING. rv64 25 fell through `return num` to x86_64 25
41 // = mremap, so every nx_fcntl caller got -EINVAL silently -- including set_cloexec/set_nonblock,
42 // which therefore never did anything and reported a failure nobody read. F_GETFL(3) on stdout must
43 // return flags >= 0; an un-translated call returns -22.
44 let fl7: i64 = __syscall(25, 1, 3, 0, 0, 0, 0)
45 if fl7 >= 0 { pass = pass + 1; w("T7 fcntl(25->72) F_GETFL=" as *u8); n(fl7); w(" PASS\n" as *u8) } else { w("T7 FAIL fcntl=" as *u8); n(fl7); w(" (un-translated -> mremap/-EINVAL)\n" as *u8) }
46
47 // T8: shutdown (210 -> 48). On a NON-socket fd the kernel must answer -ENOTSOCK (-88). An
48 // un-translated 210 is not a syscall at all and comes back -ENOSYS (-38) -- so -88 is proof the
49 // row is live, and it is a stronger assertion than "returns non-zero".
50 let sh8: i64 = __syscall(210, 1, 2, 0, 0, 0, 0)
51 if sh8 == (0 - 88) { pass = pass + 1; w("T8 shutdown(210->48) ENOTSOCK PASS\n" as *u8) } else { w("T8 FAIL shutdown=" as *u8); n(sh8); w(" (expect -88 ENOTSOCK)\n" as *u8) }
52
53 // T9: dup (23 -> 32). Duplicating stdout must yield a fresh fd > 2.
54 // NOTE: on an UN-fixed toolchain rv64 23 falls through to x86_64 23 = select, and
55 // select(1, NULL, NULL, NULL, NULL) BLOCKS FOREVER -- this tooth hung the promote run once.
56 // Pass a zeroed timeval as arg5: select() then returns immediately, while dup() ignores it.
57 // A gate must never be able to hang the thing it is gating.
58 let tv9: *u8 = sys_mmap(32)
59 var z9: i64 = 0
60 while z9 < 16 { tv9[z9] = 0 as u8; z9 = z9 + 1 }
61 let d9: i64 = __syscall(23, 1, 0, 0, 0, tv9 as i64, 0)
62 if d9 > 2 { pass = pass + 1; w("T9 dup(23->32) fd=" as *u8); n(d9); w(" PASS\n" as *u8) } else { w("T9 FAIL dup=" as *u8); n(d9); w("\n" as *u8) }
63
64 // T10: getrandom (278 -> 318). Must report the exact byte count it filled.
65 let rb: *u8 = sys_mmap(64)
66 let g10: i64 = __syscall(278, rb as i64, 8, 0, 0, 0, 0)
67 if g10 == 8 { pass = pass + 1; w("T10 getrandom(278->318) bytes=" as *u8); n(g10); w(" PASS\n" as *u8) } else { w("T10 FAIL getrandom=" as *u8); n(g10); w("\n" as *u8) }
68
69 // T11: getsid (156 -> 124). Session id of a real process is > 0; un-translated 156 is not a
70 // syscall on x86_64 and returns -ENOSYS.
71 let sid11: i64 = __syscall(156, 0, 0, 0, 0, 0, 0)
72 if sid11 > 0 { pass = pass + 1; w("T11 getsid(156->124)=" as *u8); n(sid11); w(" PASS\n" as *u8) } else { w("T11 FAIL getsid=" as *u8); n(sid11); w("\n" as *u8) }
73
74 // T12: sched_yield (124 -> 24). Returns 0 on success. If 124 were still un-translated it would
75 // hit x86_64 getsid and return a PID (> 0), so ==0 genuinely discriminates.
76 let y12: i64 = __syscall(124, 0, 0, 0, 0, 0, 0)
77 if y12 == 0 { pass = pass + 1; w("T12 sched_yield(124->24)=0 PASS\n" as *u8) } else { w("T12 FAIL sched_yield=" as *u8); n(y12); w(" (nonzero => still hitting getsid)\n" as *u8) }
78
79 // T4: geteuid (175 -> 107).
80 let euid: i64 = __syscall(RV_GETEUID, 0, 0, 0, 0, 0, 0)
81 if euid >= 0 { pass = pass + 1; w("T4 geteuid(175->107)=" as *u8); n(euid); w(" PASS\n" as *u8) } else { w("T4 FAIL geteuid=" as *u8); n(euid); w("\n" as *u8) }
82
83 // T5: getgid (176 -> 104).
84 let gid: i64 = __syscall(RV_GETGID, 0, 0, 0, 0, 0, 0)
85 if gid >= 0 { pass = pass + 1; w("T5 getgid(176->104)=" as *u8); n(gid); w(" PASS\n" as *u8) } else { w("T5 FAIL getgid=" as *u8); n(gid); w("\n" as *u8) }
86
87 // T6: getegid (177 -> 108).
88 let egid: i64 = __syscall(RV_GETEGID, 0, 0, 0, 0, 0, 0)
89 if egid >= 0 { pass = pass + 1; w("T6 getegid(177->108)=" as *u8); n(egid); w(" PASS\n" as *u8) } else { w("T6 FAIL getegid=" as *u8); n(egid); w("\n" as *u8) }
90
91 w("NX-SYSCALL-XLATE-GATE " as *u8); n(pass); w("/12" as *u8)
92 if pass == 12 { w(" GREEN\n" as *u8); return 0 }
93 w(" RED\n" as *u8)
94 return 1
95}