Skip to content

fix: compare getppid() against actual parent pid, not hardcoded 1#53

Merged
congwang-mk merged 1 commit into
multikernel:devfrom
mrsimpson:fix/container-getppid
May 19, 2026
Merged

fix: compare getppid() against actual parent pid, not hardcoded 1#53
congwang-mk merged 1 commit into
multikernel:devfrom
mrsimpson:fix/container-getppid

Conversation

@mrsimpson
Copy link
Copy Markdown
Contributor

Summary

Fixes Sandbox.run() failure in containerized server processes (e.g. uvicorn running as PID 1). The child's confine_child checked getppid() == 1 to detect parent death, but in containers the entrypoint process commonly runs as PID 1 itself — causing a false positive and silent child exit with read notif fd from child: pipe closed before 4 bytes read.

Root cause

context.rs line 788: if unsafe { libc::getppid() } == 1 { fail!("parent died before confinement"); }

When the server process is PID 1 (container entrypoint), any forked child legitimately has getppid() == 1. Sandlock interprets this as "parent was reparented to init" and aborts the child.

Fix

Capture the actual parent PID with getpid() before the fork and pass it through ChildSpawnArgs. The child compares against that value instead of hardcoded 1.

Testing

  • Verified on k3s pod with Kubernetes RuntimeDefault seccomp, Landlock ABI v7, uvicorn running as PID 1
  • Sandbox.run() now succeeds directly from the uvicorn process without any subprocess workaround
  • Multiple consecutive tool calls confirmed working

Related

The check 'getppid() == 1' intends to detect parent death (where the
child is reparented to init/PID 1). In containers the entrypoint process
commonly runs as PID 1 itself, so a child forked from it legitimately
has getppid() == 1 — causing a false positive and silent child exit.

Fix: capture getpid() in the parent before fork and pass it through
ChildSpawnArgs so the child compares against the actual parent pid.

Fixes: sandlock running from within a containerized server process (e.g.
uvicorn as PID 1) where direct Sandbox.run() calls always failed with
'read notif fd from child: pipe closed before 4 bytes read'.
@congwang-mk
Copy link
Copy Markdown
Contributor

Oops, thanks for catching it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants