diff --git a/docs/recorded-crashes.md b/docs/recorded-crashes.md index 14dbac8cd0..ad9296cc38 100644 --- a/docs/recorded-crashes.md +++ b/docs/recorded-crashes.md @@ -115,9 +115,10 @@ PID-directory opens and relative accesses through those handles are rejected. Failed FD-relative pathname attempts are checked across syscall variants. Legacy relative pathname calls without dirfd/cwd evidence remain unverified; the verification report declares this gap rather than establishing their absence. -The trace includes signal calls and rejects PID-targeted signals/probes and +The trace includes signal and priority calls and rejects PID-targeted priority +queries/changes, signals/probes and pidfd controls, including nonfatal signals and signal zero. These checks cover -the recorded file/process/signal syscall surfaces, not every possible kernel +the recorded file/process/signal/priority syscall surfaces, not every possible kernel interaction. The syscall trace also rejects access to the still-present source executable. The CI workflow defines Ubuntu 24.04 and Debian 13 (GDB 16) container lanes. Original inputs and host configuration remain unchanged. diff --git a/scripts/verify/recorded-crash/trace-policy.mjs b/scripts/verify/recorded-crash/trace-policy.mjs index f84394ed38..88e6b88a20 100644 --- a/scripts/verify/recorded-crash/trace-policy.mjs +++ b/scripts/verify/recorded-crash/trace-policy.mjs @@ -48,6 +48,15 @@ export function nodeInventoryThreads(traces, executable) { } const targetsHistoricalPid = (line, pid) => { + const priority = /^(?:getpriority|setpriority)\(([^,]+), (-?\d+)[,)]/u.exec( + line, + ); + if ( + priority !== null && + Number(priority[2]) === pid && + priority[1] !== "PRIO_USER" + ) + return true; const first = /^(kill|tkill|rt_sigqueueinfo|pidfd_open)\((-?\d+),/u.exec( line, ); diff --git a/scripts/verify/recorded-crash/trace.mjs b/scripts/verify/recorded-crash/trace.mjs index 87715ec2c0..f87733b679 100644 --- a/scripts/verify/recorded-crash/trace.mjs +++ b/scripts/verify/recorded-crash/trace.mjs @@ -63,7 +63,7 @@ export async function verifyCoreInspectionTrace({ "-s", "8192", "-e", - "trace=%process,%signal,%network,%file,ptrace,process_vm_readv,process_vm_writev,pidfd_open,pidfd_send_signal,pidfd_getfd", + "trace=%process,%signal,%network,%file,ptrace,process_vm_readv,process_vm_writev,pidfd_open,pidfd_send_signal,pidfd_getfd,getpriority,setpriority", "-o", prefix, process.execPath, diff --git a/tests/boundary/process/recordedCrashTracePolicy.test.ts b/tests/boundary/process/recordedCrashTracePolicy.test.ts index cd7e583262..be175e0590 100644 --- a/tests/boundary/process/recordedCrashTracePolicy.test.ts +++ b/tests/boundary/process/recordedCrashTracePolicy.test.ts @@ -136,6 +136,22 @@ it.each([ expect(() => check(101, line, live)).toThrow("non-inventory lookup"); }); +it.each([ + "getpriority(PRIO_PROCESS, 900) = 20", + "setpriority(PRIO_PROCESS, 900, 0) = 0", + "getpriority(PRIO_PGRP, 900) = 20", + "setpriority(PRIO_PGRP, 900, 0) = 0", + "getpriority(0x3 /* unknown PRIO selector */, 900) = -1 EINVAL (Invalid argument)", +])("rejects historical PID priority access: %s", (line) => { + for (const live of [true, false]) + expect(() => check(101, line, live)).toThrow("non-inventory lookup"); +}); + +it("keeps native priority UID selectors and distinct PIDs separate", () => { + expect(check(101, "getpriority(PRIO_USER, 900) = 20")).toEqual([]); + expect(check(101, "getpriority(PRIO_PROCESS, 9000) = 20")).toEqual([]); +}); + it("keeps exec-replaced threads foreign and follows acknowledged unfinished thread clones", () => { const observed = [ {