fix(tool-sandbox): attribute daemonized callers to their command (cgroup on linux, verified daemon-pid on macos) - #1417
Conversation
PR Review SummarySize
Affected crates
Blast radius — ModerateThis PR touches: source code,configuration / policy files Updated automatically on each push to this PR. |
b6c3d15 to
80f01cb
Compare
80f01cb to
446435a
Compare
446435a to
e63c788
Compare
…oup on linux, verified daemon-pid on macos) A caller whose parent walk is severed by a daemonized ancestor (reparented to pid 1) previously fell back to over-broad, replayable session attribution; attribute it to the spawning command instead, or fail closed. Signed-off-by: James Carnegie <me@kipz.org>
e63c788 to
f58325c
Compare
…args2 An untrusted process can report an argc far larger than its KERN_PROCARGS2 buffer actually holds; Vec::with_capacity(argc) then drives an OOM panic on the supervisor. Cap the allocation by the parsed buffer length instead. Signed-off-by: James Carnegie <me@kipz.org>
|
I have not been following every aspect of Nono, so I might be out of the loop. Thus, I've written a lot to explain my thoughts, and the logic behind them. Here is my read from the limited info I've gathered. I think this is a solid approach to a gnarly macOS problem. While the helper direction is a bit heavy compared to Linux cgroups, it has the right shape: fail closed, never fall back to the session, and only attribute a severed daemon to a specific command when a command-specific verifier can name the same kernel-pinned pid. Thus, the abstraction boundary here makes sense. For a future, truly generic "macOS cgroup-ish" backend, I think we should look into graphing I found some general information about this here (https://www.newosxbook.com/ChangeLog.html), but we should ideally look at newer info. I saw Apple has some general docs here, so we should be OK. For the goals of this PR, the current approach is good as a per-daemon attribution mechanism. However, there are a few security and ops issues we should to fix before merging. Potential issues IMO1. Stdin timeout deadlock
I'm pretty sure macOS pipe buffers are typically 16KB. Because 2. Helper executable hardeningThe helper runs unsandboxed in the supervisor. Right now, it only has absolute-path and env-clearing hardening, which is a trust boundary. We potentially need to reuse the pinned executable/writable-path checks we use elsewhere: path, 3. Negative caching (DoS prevention)Positive attributions are cached, but repeated unmatched severed callers will repeatedly run every declared helper, each with up to a 5-second timeout (as you described above). A malicious same-user daemon could spin up a loop that rapidly forks, reparents, and sends socket requests to instantly exhaust the supervisor's thread pool. Maybe we add a short negative cache keyed by Potential fixes IMO1. Drop
|
Addresses review feedback on the severed-daemon attribution helper: - Write the JSON payload to the helper's stdin on a background thread instead of blocking before the timeout-poll loop starts. A severed daemon's argv/env is unbounded (read straight from the kernel), so the payload can exceed the pipe buffer; a helper that doesn't drain stdin before doing other work could wedge the write and skip the deadline entirely. - Pre-resolve daemon_pid_source helper binaries at plan-build time (dev/ino/size/mtime/sha256), gate them behind the same non-writable-executable trust check already applied to `exec` intercept helpers, and re-verify identity right before spawn to close the TOCTOU window. - Add a short-TTL negative cache to DaemonPidLineage, pinned by kernel identity, so a fork/reparent loop can't force a full helper sweep on every unmatched severed-daemon check. - Reject an empty daemon_pid_source.argv at profile-load time instead of silently disabling attribution for that command at runtime. Signed-off-by: James Carnegie <me@kipz.org>
|
Thanks for the detailed review — pushed a fix for all three blocking issues in 4ab94e4:
Also tightened schema validation to reject an empty On |
daemon_pid_source is only consumed by the macOS tool-sandbox module (mod macos is cfg(target_os = "macos")-gated). Mirroring exec_helpers' cfg(any(test, target_os = "linux", target_os = "macos")) left these two functions uncalled on Linux, tripping -D warnings dead-code errors in CI. Signed-off-by: James Carnegie <me@kipz.org>
Linked Issue
Closes #1412
Summary
setsid+ double-fork → reparented to pid 1) severs that walk, so a caller that legitimately descends from a session command is blocked (caller ancestry did not reach session root).daemon_pid_sourcehelper reports the daemon's pid, accepted only if it matches the walked-to daemon, pinned by kernel identity. The helper receives the daemon's own argv/env/cwd (read from the kernel) as a JSON object on stdin so it can locate or verify its server.Agent Disclosure (if applicable)
Authored by an AI agent, driven and reviewed by me. Area:
tool-sandbox/platform/{macos,linux}.rs,lineage_cgroup.rs,command_policy.rs,profile/mod.rs, the profile schema, and the Tool Sandbox docs. Complies with CLAUDE.md for the area: no unwrap/expect,NonoError, bounds-checked FFI.Test Plan
make ciclean (check, test, audit, lint-aliases, lint-docs).platform_overrides+extendsmerge; schema shape;daemon_pid_sourceserde/merge.KERN_PROCARGS2parse; helper stdin-context round-trip (verify mode); env allowlist honoured + credential-name denylist enforced.#[ignore], run with--ignored): realsetsid+double-fork daemon attributes to its command; Linux childcgroup.procswrite →EACCES.Checklist
CHANGELOG.mdif neededAgent Compliance Check (Required for AI/Automated PRs)