nx_proc_ctl_rt.nx source
↩ module page · 61 lines · 3499 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"
9
10// 1 iff buf[0..n) contains "/" + name (NUL-term). "/path/name" matches; "restart name" (arg mention) does NOT.
11func nx_pctl_cmdl_has(buf: *u8, n: i64, name: *u8) -> i64 {
12 var nl: i64 = 0; while name[nl] != (0 as u8) { nl = nl + 1 }
13 if nl == 0 { return 0 }
14 var i: i64 = 0
15 while i + 1 + nl <= n {
16 if (buf[i] as i64) == 47 {
17 var j: i64 = 0; var ok: i64 = 1
18 while j < nl { if buf[i+1+j] != name[j] { ok = 0; j = nl } else { j = j + 1 } }
19 if ok == 1 { return 1 }
20 }
21 i = i + 1
22 }
23 return 0
24}
25
26// scan /proc and send signal `sig` to every process whose /proc/<pid>/cmdline contains "/"+name. Honest killed count.
27func nx_pctl_kill_by_cmdline(name: *u8, sig: i64) -> i64 {
28 let fd: i64 = sys_openat_rd("/proc" as *u8)
29 if fd < 0 { return 0 }
30 let self_pid: i64 = __syscall(172, 0, 0, 0, 0, 0, 0) // getpid (x86_64) -- a kill-by-cmdline must NEVER kill its caller // rv64 getpid=172 (was raw x86 39, which the backend translates to ioctl -- debt idx 2277)
31 let gbuf: *u8 = sys_mmap(65536); let path: *u8 = sys_mmap(256); let cmdl: *u8 = sys_mmap(8192)
32 var killed: i64 = 0; var go: i64 = 1
33 while go == 1 {
34 let n: i64 = sys_getdents64(fd, gbuf, 65536)
35 if n <= 0 { go = 0 } else {
36 var off: i64 = 0
37 while off < n {
38 let rec: *u8 = ((gbuf as i64) + off) as *u8
39 let reclen: i64 = dirent_reclen(rec)
40 let pname: *u8 = dirent_name(rec)
41 var pid: i64 = 0; var valid: i64 = 1; var di: i64 = 0
42 if pname[0] == (0 as u8) { valid = 0 }
43 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 }
44 if valid == 1 { if pid > 0 { if pid != self_pid {
45 var po: i64 = 0; let pf: *u8 = "/proc/" as *u8; while pf[po] != (0 as u8) { path[po]=pf[po]; po=po+1 }
46 var ni: i64 = 0; while pname[ni] != (0 as u8) { path[po]=pname[ni]; po=po+1; ni=ni+1 }
47 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 }
48 path[po] = 0 as u8
49 let cfd: i64 = sys_openat_rd(path)
50 if cfd >= 0 {
51 let r: i64 = sys_read(cfd, cmdl, 8191); sys_close(cfd)
52 if r > 0 { if nx_pctl_cmdl_has(cmdl, r, name) == 1 { nx_kill(pid, sig); killed = killed + 1 } }
53 }
54 } } }
55 if reclen <= 0 { off = n } else { off = off + reclen }
56 }
57 }
58 }
59 sys_close(fd)
60 return killed
61}