48 lines
1.6 KiB
JavaScript
48 lines
1.6 KiB
JavaScript
// usage: node probe.mjs <bus-src> <cliPath> (run by a debug spike, not by the packet's results)
|
|
// Finds a live human-cli on the host /proc, then walks its ancestry the way verifyHuman
|
|
// does and prints each step's readProcess result (and the exact error if one fails), so a
|
|
// refusal can be traced to the field that caused it.
|
|
import { pathToFileURL } from 'node:url';
|
|
import { join } from 'node:path';
|
|
import { readdirSync, readFileSync, lstatSync } from 'node:fs';
|
|
const [src, cli] = process.argv.slice(2);
|
|
const { readProcess } = await import(pathToFileURL(join(src, 'human.mjs')).href);
|
|
console.log(`probe uid=${process.getuid()} pid=${process.pid}`);
|
|
let target = null;
|
|
for (const d of readdirSync('/proc')) {
|
|
if (!/^\d+$/.test(d)) continue;
|
|
try {
|
|
const a = readFileSync(`/proc/${d}/cmdline`, 'utf8').split('\0');
|
|
if (a[1] === cli) target = Number(d);
|
|
} catch {}
|
|
}
|
|
console.log('target', target);
|
|
let pid = target;
|
|
for (let i = 0; pid && i < 12; i++) {
|
|
let raw = {};
|
|
for (const f of ['stat', 'environ', 'cmdline']) {
|
|
try {
|
|
readFileSync(`/proc/${pid}/${f}`, 'utf8');
|
|
raw[f] = 'ok';
|
|
} catch (e) {
|
|
raw[f] = e.code;
|
|
}
|
|
}
|
|
try {
|
|
raw.lstatUid = lstatSync(`/proc/${pid}`).uid;
|
|
} catch (e) {
|
|
raw.lstatUid = e.code;
|
|
}
|
|
let p;
|
|
try {
|
|
p = readProcess(pid);
|
|
console.log(
|
|
`pid=${pid} ppid=${p.ppid} uid=${p.uid} env=${p.env === null ? 'null' : Object.keys(p.env).join(',') || '{}'} argv=${JSON.stringify(p.argv).slice(0, 110)} raw=${JSON.stringify(raw)}`,
|
|
);
|
|
} catch (e) {
|
|
console.log(`pid=${pid} readProcess REFUSED raw=${JSON.stringify(raw)}`);
|
|
break;
|
|
}
|
|
pid = p.ppid;
|
|
}
|