nx_container_rootless_test.nx source
↩ module page · 50 lines · 2076 B
1// nx_container_rootless_test.nx -- proof that nx_container runs a process in a
2// FULLY ROOTLESS container: CLONE_NEWUSER + uid/gid map (host id -> 0 inside)
3// THEN unshare(mount|pid|uts|ipc), NO sudo, NO CAP_SYS_ADMIN. This is the
4// oracle-container lane (bench/racing_crew/vendor/ORACLES.md v2): the racing
5// suites run in sovereign nx_container jails that spin up/down as any user.
6// The entrypoint (nx_exit42) returns 42; a rootless container that captures 42
7// proves the whole unprivileged namespace stack + the sovereign fork/exec/wait
8// path (clone/execve/wait4 rv64-number fix). expect_exit: 0.
9// license_tier: ORIGINAL No hw writes (Rule 26).
10import "nx_syscalls_x86_64.nx"
11import "nx_container.nx"
12
13const CLONE_NEWNS: i64 = 0x00020000
14const CLONE_NEWUTS: i64 = 0x04000000
15const CLONE_NEWIPC: i64 = 0x08000000
16
17func main() -> i64 {
18 let ep: *u8 = "/tmp/nx_exit42.sov.elf" as *u8
19 var epl: i64 = 0
20 while ep[epl] != (0 as u8) { epl = epl + 1 }
21
22 let argv: *i64 = sys_mmap(16) as *i64
23 argv[0] = ep as i64
24 argv[1] = 0
25
26 let host: *u8 = sys_mmap(64)
27 host[0]=110 as u8; host[1]=105 as u8; host[2]=115 as u8; host[3]=104 as u8
28 host[4]=105 as u8; host[5]=45 as u8; host[6]=114 as u8; host[7]=108 as u8
29 host[8]=115 as u8; host[9]=0 as u8
30
31 let spec: *ContainerSpec = sys_mmap(128) as *ContainerSpec
32 spec.rootfs_path = "/" as *u8
33 spec.rootfs_path_len = 1
34 spec.entry_path = ep
35 spec.entry_path_len = epl
36 spec.argv = argv
37 spec.hostname = host
38 // mount + uts + ipc, all unprivileged BECAUSE rootless=1 enters the user
39 // namespace first (PID omitted: CLONE_NEWPID needs a fork-after-unshare to
40 // actually enter, out of scope for this single-exec proof).
41 spec.namespace_flags = CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWNS
42 spec.rootless = 1
43
44 let res: *ContainerResult = sys_mmap(64) as *ContainerResult
45 nx_container_run(spec, res)
46
47 // proof: the rootless container executed our process and captured exit 42.
48 if res.exit_code != 42 { return 50 + res.verdict }
49 return 0
50}