Skip to content

1.1.11 — graceful jail stop via new signal_jail verb#206

Merged
click0 merged 1 commit into
mainfrom
claude/release-1.1.11
May 23, 2026
Merged

1.1.11 — graceful jail stop via new signal_jail verb#206
click0 merged 1 commit into
mainfrom
claude/release-1.1.11

Conversation

@click0
Copy link
Copy Markdown
Owner

@click0 click0 commented May 23, 2026

Summary

Fixes a crate stop UX regression under rootless. lib/lifecycle.cpp sent SIGTERM (then SIGKILL after timeout) to jail processes via jexec <jid> /bin/kill. Under 1.0.0+ rootless those EACCES'd, the SIGTERM never landed, and every stop waited the FULL stopTimeout before falling through to forced destroy_jail — turning a 1-second graceful stop into a 10-second (default) hang.

New verb: signal_jail

Wraps jexec <jid> /bin/kill -<signal> -1. Signal whitelisted to TERM, KILL, HUP, INT — rejects numbers, SIG-prefix, and dangerous signals like STOP. Wire taxonomy grows from 28 to 29 verbs.

Behaviour restored

Mode crate stop graceful path
Pre-1.1.11 rootless SIGTERM EACCES → full timeout → forced destroy
1.1.11 rootless SIGTERM via verb → processes exit → fast stop
Legacy setuid unchanged (direct jexec)

Remaining bare-shell calls — flagged for 1.2.0 design pass

Two remain, both needing a design decision (not just verb-wiring):

  1. chroot run-hooks (lib/run.cpp:732,1752) — chroot <jailPath> /bin/sh -c <operator-cmd>. A verb here is "run arbitrary command as root in this chroot" — acceptable only if the daemon enforces <jailPath> belongs to the getpeereid uid (else alice execs into bob's jail). Needs path-ownership checking.

  2. zfs send (lib/backup.cpp:86, lib/replicate.cpp:101) — streams a multi-GB dataset. The request/response wire protocol isn't built for streaming; needs fd-passing or a different transport. zfs snapshot (cheap half) could be a verb today but shipping it without zfs send leaves crate backup half-rootless.

Audit chain status

Item Status
validator length/charset fixes (anchor, jailname) ✅ 1.1.2–1.1.4
securelevel/children.max, RCTL ✅ 1.1.5/1.1.6
ipfw teardown + setup ✅ 1.1.7/1.1.8
cpuset, devfs ruleset + GPU unhide ✅ 1.1.9/1.1.10
graceful stop via SignalJail this PR
chroot run-hooks, zfs snapshot/send 1.2.0 design

Tests

signal_jail_minimal covers all 4 whitelisted signals + jid=0/STOP/number/SIG-prefix/empty rejection. dispatch_covers_every_verb extended. Suite grows from 1316 to 1317.

Test plan

  • FreeBSD CI lite green
  • Linux CI green
  • Manual rootless: crate run a jail with a slow-to-exit process, crate stop — verify it exits promptly on SIGTERM instead of waiting the full timeout
  • Manual legacy setuid: behaviour unchanged

Generated by Claude Code

lib/lifecycle.cpp sent SIGTERM/SIGKILL to jail processes via
`jexec <jid> /bin/kill`. Under 1.0.0+ rootless those EACCES'd,
the SIGTERM never landed, and every `crate stop` waited the
full stopTimeout before forced destroy_jail — a 1s graceful
stop became a 10s hang.

New SignalJail verb wraps `jexec <jid> /bin/kill -<signal> -1`.
Signal whitelisted to TERM/KILL/HUP/INT (rejects numbers,
SIG-prefix, STOP). Wire taxonomy grows 28 -> 29. Both kill
sites in stopCrate route through the verb when socket detected;
legacy jexec preserved.

Tests: signal_jail_minimal. Suite grows 1316 -> 1317.

Remaining bare-shell (chroot run-hooks, zfs send) need design
decisions (path-ownership enforcement, streaming transport) —
tracked for 1.2.0, documented in CHANGELOG.
@click0 click0 merged commit 3b85bc2 into main May 23, 2026
2 checks passed
@click0 click0 deleted the claude/release-1.1.11 branch May 24, 2026 16:02
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