35 lines
1.7 KiB
JavaScript
35 lines
1.7 KiB
JavaScript
// No real process is signalled. These hostile kernel-boundary controls expose
|
|
// a new session reusing the old SID after the original leader disappears.
|
|
import {test} from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {readFileSync} from 'node:fs';
|
|
import {spawnSync} from 'node:child_process';
|
|
for(const name of ['case1-accept.sh','case2-unit.sh'])for(const mode of ['already-dead','dies-before-signal'])test(`${name}: ${mode} original session never signals a recycled SID`,()=>{
|
|
const source=readFileSync(new URL(`../../../scripts/${name}`,import.meta.url),'utf8');
|
|
const program=/\/usr\/bin\/python3 -I -S -c '\n([\s\S]*?)\n' "\$child"/.exec(source)?.[1];
|
|
assert.ok(program,'the shipped cleanup program exists');
|
|
const anchor='\ntry:\n';assert.equal(program.split(anchor).length,2);
|
|
const control=`
|
|
import atexit, json
|
|
from types import SimpleNamespace
|
|
attempts = []
|
|
checks = 0
|
|
atexit.register(lambda: print(json.dumps(attempts)))
|
|
def observed(pid):
|
|
global checks
|
|
if pid == "self/fd/42":
|
|
checks += 1
|
|
return (b"T", session) if ${mode==='already-dead'?'False':'checks < 3'} else None
|
|
return (b"R", session)
|
|
def send(fd, sig):
|
|
attempts.append([fd, sig])
|
|
raise PermissionError("never signal a real task")
|
|
fields = observed
|
|
os = SimpleNamespace(listdir=lambda path: ["999"], pidfd_open=lambda pid: 17 if pid == session else 99, close=lambda fd: None)
|
|
signal = SimpleNamespace(SIGKILL=9, SIGCONT=18, pidfd_send_signal=send)
|
|
`;
|
|
const r=spawnSync('/usr/bin/python3',['-I','-S','-c',program.replace(anchor,'\n'+control+anchor),'424242','42'],{encoding:'utf8'});
|
|
assert.equal(r.status,1,r.stderr);assert.equal(r.stderr,'');
|
|
assert.deepEqual(JSON.parse(r.stdout),[],'a stale SID must never authorize a signal');
|
|
});
|