Skip to content

Fix supervisor hang on child exit#27

Merged
jserv merged 1 commit intomainfrom
fix
Mar 27, 2026
Merged

Fix supervisor hang on child exit#27
jserv merged 1 commit intomainfrom
fix

Conversation

@jserv
Copy link
Contributor

@jserv jserv commented Mar 27, 2026

Commit 6080aad changed the supervisor poll timeout from 100ms to -1 and removed the per-iteration check_child(), relying solely on POLLHUP from the seccomp listener FD to detect child exit. This hangs when the child exits without a pending notification.

This replaces the single-FD poll with two-FD poll: the seccomp listener plus a signalfd for SIGCHLD. The kernel delivers SIGCHLD the instant the child exits, waking poll() without any per-iteration waitpid overhead.

Signal mask lifecycle:

  • Block SIGCHLD before fork() (race-free: no window to lose the signal)
  • Save/restore the caller's original mask on all parent return paths
  • Restore in the child before exec() (guest sees clean signal state)

The signalfd is owned by supervise_loop with a single goto-cleanup exit path; the mask is owned by kbox_run_supervisor.

Also pin AUTO syscall mode to seccomp on all architectures: the aarch64 rewrite fast path hangs for dynamically-linked binaries (separate bug in the rewrite runtime's interpreter dispatch).
--syscall-mode=rewrite remains available for explicit use.

Close #24

Change-Id: I09bccef6e2ca7a08a34c86b075f3ca9cdfa29b9c


Summary by cubic

Fixes a supervisor hang when the child exits without a pending seccomp notification by waking poll() with SIGCHLD. Also pins AUTO syscall mode to seccomp to avoid rewrite-path hangs; --syscall-mode=rewrite remains available. Closes #24.

  • Bug Fixes

    • Poll both the seccomp listener and a signalfd for SIGCHLD to wake immediately on child exit, avoiding per-iteration waitpid().
    • Block SIGCHLD before fork(), then restore the original signal mask in both parent and child; own and clean up the signalfd in the supervisor loop.
  • Migration

    • AUTO now maps to seccomp on all architectures.
    • Use --syscall-mode=rewrite to force the rewrite path when needed.

Written for commit 9cc4b97. Summary will update on new commits.

Commit 6080aad changed the supervisor poll timeout from 100ms to -1 and
removed the per-iteration check_child(), relying solely on POLLHUP from
the seccomp listener FD to detect child exit. This hangs when the child
exits without a pending notification.

This replaces the single-FD poll with two-FD poll: the seccomp listener
plus a signalfd for SIGCHLD. The kernel delivers SIGCHLD the instant the
child exits, waking poll() without any per-iteration waitpid overhead.

Signal mask lifecycle:
- Block SIGCHLD before fork() (race-free: no window to lose the signal)
- Save/restore the caller's original mask on all parent return paths
- Restore in the child before exec() (guest sees clean signal state)

The signalfd is owned by supervise_loop with a single goto-cleanup exit
path; the mask is owned by kbox_run_supervisor.

Also pin AUTO syscall mode to seccomp on all architectures: the aarch64
rewrite fast path hangs for dynamically-linked binaries (separate bug in
the rewrite runtime's interpreter dispatch).
--syscall-mode=rewrite remains available for explicit use.

Close #24

Change-Id: I09bccef6e2ca7a08a34c86b075f3ca9cdfa29b9c
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

@jserv jserv merged commit 74fbac6 into main Mar 27, 2026
4 checks passed
@jserv jserv deleted the fix branch March 27, 2026 04:24
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.

Commit 6080aad "Add syscall binary rewriting infrastructure" leads to kbox hang

1 participant