nx_proc_ctl_cmdl.nx source
↩ module page · 67 lines · 3800 B
1// nx_proc_ctl.nx -- canonical sovereign process control: kill by FULL /proc/<pid>/cmdline. THE one true copy that
2// replaces (a) nx_proc_kill.nx's /proc/<pid>/comm match -- the 15-char-TRUNCATED field that silently matched nothing
3// for long names = the 2026-06-29 gallery-login disaster -- and (b) the buried-in-nx_hostctl hc_kill_by_cmdline.
4// IMPORTABLE (no main, no self-test). Matches "/"+name -> the binary PATH, never an arg mention (so it can't kill its
5// own command line); signal is a parameter (9=SIGKILL, 15=SIGTERM); returns the HONEST killed count (0 => nothing
6// matched => the op did nothing). Bounded reader (fixed reused buffers; no sys_read_file 4GiB-per-call leak).
7// license_tier: ORIGINAL
8import "nx_syscalls.nx"
9const K_MAGIC_65536: i64 = 65536
10const K_MAGIC_8192: i64 = 8192
11const K_MAGIC_8191: i64 = 8191
12
13// 1 iff buf[0..n) contains "/" + name (NUL-term). "/path/name" matches; "restart name" (arg mention) does NOT.
14func nx_pctl_cmdl_has(buf: *u8, n: i64, name: *u8) -> i64 {
15 var nl: i64 = 0; while name[nl] != (0 as u8) { nl = nl + 1 }
16 if nl == 0 { return 0 }
17 var i: i64 = 0
18 while i + 1 + nl <= n {
19 if (buf[i] as i64) == 47 {
20 var j: i64 = 0; var ok: i64 = 1
21 while j < nl { if buf[i+1+j] != name[j] { ok = 0; j = nl } else { j = j + 1 } }
22 if ok == 1 { return 1 }
23 }
24 i = i + 1
25 }
26 return 0
27}
28
29// scan /proc and send signal `sig` to every process whose /proc/<pid>/cmdline contains "/"+name. Honest killed count.
30func nx_pctl_kill_by_cmdline(name: *u8, sig: i64) -> i64 {
31 let fd: i64 = sys_openat_rd("/proc" as *u8)
32 if fd < 0 { return 0 }
33 let self_pid: i64 = __syscall(172, 0, 0, 0, 0, 0, 0) // getpid -- a kill-by-cmdline must NEVER kill its caller.
34 // rv64 getpid=172. This was raw x86 39, which IS an RV64 KEY (umount2) that the backend
35 // translated to ioctl(16), returning -ENOTTY. So self_pid was -25 and the self-exclusion
36 // comparison NEVER MATCHED -- this guard could kill its own caller (debt idx 2277).
37 let gbuf: *u8 = sys_mmap(K_MAGIC_65536); let path: *u8 = sys_mmap(256); let cmdl: *u8 = sys_mmap(K_MAGIC_8192)
38 var killed: i64 = 0; var go: i64 = 1
39 while go == 1 {
40 let n: i64 = sys_getdents64(fd, gbuf, K_MAGIC_65536)
41 if n <= 0 { go = 0 } else {
42 var off: i64 = 0
43 while off < n {
44 let rec: *u8 = ((gbuf as i64) + off) as *u8
45 let reclen: i64 = dirent_reclen(rec)
46 let pname: *u8 = dirent_name(rec)
47 var pid: i64 = 0; var valid: i64 = 1; var di: i64 = 0
48 if pname[0] == (0 as u8) { valid = 0 }
49 while pname[di] != (0 as u8) { let c: i64 = pname[di] as i64; if c < 48 { valid = 0 } else { if c > 57 { valid = 0 } else { pid = pid*10 + (c-48) } } di = di + 1 }
50 if valid == 1 { if pid > 0 { if pid != self_pid {
51 var po: i64 = 0; let pf: *u8 = "/proc/" as *u8; while pf[po] != (0 as u8) { path[po]=pf[po]; po=po+1 }
52 var ni: i64 = 0; while pname[ni] != (0 as u8) { path[po]=pname[ni]; po=po+1; ni=ni+1 }
53 let sf: *u8 = "/cmdline" as *u8; var si: i64 = 0; while sf[si] != (0 as u8) { path[po]=sf[si]; po=po+1; si=si+1 }
54 path[po] = 0 as u8
55 let cfd: i64 = sys_openat_rd(path)
56 if cfd >= 0 {
57 let r: i64 = sys_read(cfd, cmdl, K_MAGIC_8191); sys_close(cfd)
58 if r > 0 { if nx_pctl_cmdl_has(cmdl, r, name) == 1 { nx_kill(pid, sig); killed = killed + 1 } }
59 }
60 } } }
61 if reclen <= 0 { off = n } else { off = off + reclen }
62 }
63 }
64 }
65 sys_close(fd)
66 return killed
67}