code wiki / (root) / nx_proc_spawn.nx

nx_proc_spawn.nx source

↩ module page · 166 lines · 7651 B

1// nx_proc_spawn.nx -- HIGH-LEVEL spawn-with-capability-gate layer above 2// the FULLY_WIRED nx_proc.nx primitive (fork/exec/wait4 syscall wrappers). 3// 4// AUDIT-FIRST CORRECTION (2026-05-20, post-creation): user caught that I 5// built this without checking for existing prior art. nx_proc.nx already 6// ships with nx_proc_fork / nx_proc_execve / nx_proc_wait4 / wait-status 7// inspectors. This primitive does NOT duplicate those -- it adds the 8// capability-token + priv-class + log-redirect layer ABOVE them. When 9// graduated, nx_proc_spawn_execute will CALL nx_proc_fork + nx_proc_execve 10// internally; it is the supervised wrapper, not a competing implementation. 11// Per feedback-no-temporary-third-party-scaffolding-when-substrate-arc-exists 12// audit-first rule: ls nxc2/runtime/ before authoring new primitives. 13// 14// Composes with the existing nx_supervisor state-machine primitive (which 15// decides what to do); THIS primitive does the actual process management. 16// 17// module: nishi-core.ops.proc_spawn 18// depends: nishi-core.perception.profile + nishi-core.ops.supervisor + 19// nishi-core.io.syscalls 20// disk_kb: 5 21// capability: OPS 22// wired_status: PARTIAL_WIRED 23// 24// MISSING_CAPABILITIES: 25// - FORK_EXEC_SETSID (sys_fork + sys_execve + sys_setsid; sys_fork is 26// proven via nishi_video_room.nx, sys_execve glue needed) 27// - CAPABILITY_TOKEN_VERIFY (content-addressed capability proof that 28// replaces /etc/sudoers.d/* NOPASSWD entries with cryptographic 29// capability bearer tokens; composes with nx_ed25519 + nx_blake2b 30// which are FULLY_WIRED per status doc) 31// - PRIV_DROP (after fork, child drops privilege per NX_SUPV_PRIV_* 32// declared class before execve) 33// - FD_HYGIENE (close-on-exec all inherited fds except declared ones) 34// - STDIO_REDIRECT (per-child stdout/stderr to substrate-managed log files) 35// 36// license_tier: PUBLIC_NISHI_SUBSTRATE 37// genealogy_id: feedback-no-temporary-third-party-scaffolding-when-substrate-arc-exists_2026 + 38// feedback-substrate-does-heavy-lifting-user-is-partner-not-gate + 39// nx_supervisor (existing state-machine primitive) + 40// nx_daemon_health_audit 41// 42// SCAFFOLDING_REPLACED_BY: this primitive replaces: 43// - nohup spawn pattern in install-video.sh + install-voxels.sh + every 44// other install-NAME.sh 45// - Synology DSM init-script daemon launch 46// - /etc/sudoers.d/nishi-engine-deploy NOPASSWD blanket entries (replaced 47// by per-capability-class tokens) 48// - bench/ops/run_if_dead.sh pattern when it exists 49// 50// Reuse set: every nx_* daemon spawn + every install-NAME.sh executor + 51// dog toy embedded firmware boot + livestock-gateway service startup + 52// every production deployment in any Nishi product. 53 54import "nx_syscalls.nx" 55import "nx_perceptual_profile.nx" 56import "nx_supervisor.nx" 57 58// ===== Spawn verdicts ============================================ 59 60const NX_PSPAWN_OK: i64 = 0 61const NX_PSPAWN_SPAWNED: i64 = 1 62const NX_PSPAWN_FAIL_FORK: i64 = 2 63const NX_PSPAWN_FAIL_EXEC: i64 = 3 64const NX_PSPAWN_FAIL_BAD_BINARY: i64 = 4 // path missing / not exec 65const NX_PSPAWN_FAIL_CAPABILITY_REFUSED: i64 = 5 // requested priv exceeds 66 // declared class 67const NX_PSPAWN_FAIL_PRIV_DROP: i64 = 6 // child couldn't drop priv 68const NX_PSPAWN_FAIL_DEPENDENCY_MISSING: i64 = 7 // PARTIAL_WIRED default 69 70func nx_pspawn_verdict_name(v: i64) -> *u8 { 71 if v == NX_PSPAWN_OK { return "OK" } 72 if v == NX_PSPAWN_SPAWNED { return "SPAWNED" } 73 if v == NX_PSPAWN_FAIL_FORK { return "FAIL_FORK" } 74 if v == NX_PSPAWN_FAIL_EXEC { return "FAIL_EXEC" } 75 if v == NX_PSPAWN_FAIL_BAD_BINARY { return "FAIL_BAD_BINARY" } 76 if v == NX_PSPAWN_FAIL_CAPABILITY_REFUSED { return "FAIL_CAPABILITY_REFUSED" } 77 if v == NX_PSPAWN_FAIL_PRIV_DROP { return "FAIL_PRIV_DROP" } 78 if v == NX_PSPAWN_FAIL_DEPENDENCY_MISSING { return "FAIL_DEPENDENCY_MISSING" } 79 return "UNKNOWN_PSPAWN_VERDICT" 80} 81 82// ===== Privilege class (matches nx_supervisor sealed enum) ======= 83 84const NX_PSPAWN_PRIV_USER: i64 = 1 85const NX_PSPAWN_PRIV_NET_BIND_LOW_PORT: i64 = 2 86const NX_PSPAWN_PRIV_FS_WRITE_PROTECTED: i64 = 3 87const NX_PSPAWN_PRIV_DEVICE_ACCESS: i64 = 4 88const NX_PSPAWN_PRIV_ROOT_FULL: i64 = 5 // audit-gate 89 90func nx_pspawn_priv_class_name(p: i64) -> *u8 { 91 if p == NX_PSPAWN_PRIV_USER { return "USER" } 92 if p == NX_PSPAWN_PRIV_NET_BIND_LOW_PORT { return "NET_BIND_LOW_PORT" } 93 if p == NX_PSPAWN_PRIV_FS_WRITE_PROTECTED { return "FS_WRITE_PROTECTED" } 94 if p == NX_PSPAWN_PRIV_DEVICE_ACCESS { return "DEVICE_ACCESS" } 95 if p == NX_PSPAWN_PRIV_ROOT_FULL { return "ROOT_FULL" } 96 return "UNKNOWN_PRIV" 97} 98 99// ===== Spawn request struct ====================================== 100 101struct NxPSpawnRequest { 102 binary_path_ptr: *u8 103 binary_path_len: i64 104 argv_serialized_ptr: *u8 // NUL-separated argv vector 105 argv_serialized_len: i64 106 envp_serialized_ptr: *u8 // NUL-separated KEY=VAL env 107 envp_serialized_len: i64 108 declared_priv_class: i64 // NX_PSPAWN_PRIV_* 109 capability_token_ptr: *u8 // ed25519-signed capability proof 110 capability_token_len: i64 111 cwd_path_ptr: *u8 112 cwd_path_len: i64 113 stdout_log_path_ptr: *u8 114 stdout_log_path_len: i64 115 stderr_log_path_ptr: *u8 116 stderr_log_path_len: i64 117 detach_session: i64 // 0/1; 1 = setsid for daemon 118} 119 120// ===== Top-level entry stubs ===================================== 121 122// nx_pspawn_execute -- spawn one process per request. Returns child PID 123// on success (positive), error verdict on failure (negative or zero). 124 125func nx_pspawn_execute(req_ptr: *NxPSpawnRequest) -> i64 { 126 if req_ptr == 0 as *NxPSpawnRequest { return NX_PSPAWN_FAIL_BAD_BINARY } 127 // PARTIAL_WIRED: capability verify + fork + priv-drop + exec queued. 128 return NX_PSPAWN_FAIL_DEPENDENCY_MISSING 129} 130 131// nx_pspawn_kill_pid -- TERM with grace fallback to KILL. Composes with 132// nx_supervisor restart-policy decisions. 133 134func nx_pspawn_kill_pid(pid: i64, grace_seconds: i64) -> i64 { 135 if pid <= 0 { return NX_PSPAWN_FAIL_BAD_BINARY } 136 if grace_seconds < 0 { return NX_PSPAWN_FAIL_BAD_BINARY } 137 return NX_PSPAWN_FAIL_DEPENDENCY_MISSING 138} 139 140// nx_pspawn_pid_is_alive -- inspector. 141 142func nx_pspawn_pid_is_alive(pid: i64) -> i64 { 143 if pid <= 0 { return 0 } 144 return 0 145} 146 147// nx_pspawn_verify_capability_token -- check a capability token grants 148// the declared priv class. Replaces /etc/sudoers.d/* lookups with 149// cryptographic verification. 150 151func nx_pspawn_verify_capability_token(token_ptr: *u8, token_len: i64, 152 requested_priv_class: i64, 153 binary_path_hash_ptr: *u8, 154 binary_path_hash_len: i64) -> i64 { 155 if token_len <= 0 { return 0 } 156 if binary_path_hash_len != 32 { return 0 } 157 if requested_priv_class < NX_PSPAWN_PRIV_USER { return 0 } 158 if requested_priv_class > NX_PSPAWN_PRIV_ROOT_FULL { return 0 } 159 return 0 160} 161 162// nx_pspawn_get_last_verdict -- inspector. 163 164func nx_pspawn_get_last_verdict() -> i64 { 165 return NX_PSPAWN_FAIL_DEPENDENCY_MISSING 166}