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}