Skip to content

1.1.70: regressions of 1.1.65–1.1.69 and the teardown SIGSEGV - #262

Merged
click0 merged 1 commit into
mainfrom
claude/analyze-test-coverage-nCOJW
Nov 6, 2026
Merged

click0 merged 1 commit into
mainfrom
claude/analyze-test-coverage-nCOJW

Conversation

@click0

@click0 click0 commented Nov 6, 2026

Copy link
Copy Markdown
Owner

1.1.70 — regressions found by the bug hunt, plus a teardown crash

Teardown SIGSEGV (lib/util.cpp)

RunAtEnd::doNow() dereferenced the handle unconditionally. The success path of crate run calls it on handles armed only in some configurations: killXephyrAtEnd without x11/gui, destroyJailDir for --warm-base, destroyAutoBridgeAtEnd on an existing bridge, the fw-slot / fw-lease pair. Every such run died right after the jail was removed, before unmounts, network teardown and the jail directory removal. Reproduced on a copy of the class (exit 139). An unarmed handle is now a no-op.

Warm-base clone leak (1.1.69, lib/run.cpp)

The DirLock descriptor sits on the clone's root, so the unmount inside zfs destroy got EBUSY and the error was swallowed: every warm-base run left its clone and @warm-run snapshot. The lock is released first; failures now warn.

crate clean deleted warm-base registry entries (1.1.69, lib/clean.cpp)

The orphan sweep stat()ed an empty path for <name> warm-base=<dataset> entries. They are now kept while zfs list finds the dataset (SpecRegistryPure::targetOf for messages).

stack up stopped on NAT members (1.1.68, lib/stack*.cpp)

1.1.68 made the pool address reach the member but gave one to every member with a net option; Spec::validate refuses a static ip in NAT mode. Now only a member in bridge/auto mode on that network's bridge with no options/net/ip of its own draws from the pool (StackPure::poolEligible); others get a warning and stay out of hosts/DNS. Member networks come from one template-merged YAML base per member (StackSpec::netInfo, vars substituted), replacing the Spec-level collectContainerIPs; prefix and gateway come from the network the address was drawn from.

crated zombies (1.1.65, daemon/privops_handlers.cpp)

The start watch ended without waitpid for failed starts (the old poll reaped them) and successful ones. The watch thread now waits for the supervisor to exit.

Docs / tests

crate.5 (who draws from ip_range), README en/uk, runbook §4m, CHANGELOG, TODO (§4 leftover: putting NAT / bridge-less members on the stack bridge is a design decision), VERSION / PORTVERSION 1.1.70.
make test-unit with -Werror: 1592/1592 passed (+2 cases: pool eligibility, targetOf). make check-version, make check-kyuafile, mandoc lint. StackSpec::netInfo exercised with a scratch harness on real examples and synthetic bridge/auto/dhcp/vars specs; everything touching zfs, jails and crated is runbook §4m.


Generated by Claude Code

- RunAtEnd::doNow() is a no-op on an unarmed handle: the success path
  of every `crate run` without x11/gui (and warm-base, NAT, existing
  bridge runs) dereferenced a null handle right after the jail was
  removed, skipping unmounts, network teardown and the jail directory.
- warm-base: release the DirLock before `zfs destroy` of the clone (its
  descriptor on the clone root made the unmount EBUSY, leaking the clone
  and the @warm-run snapshot on every run since 1.1.69); failures warn.
- crate clean keeps a `warm-base=<dataset>` registry entry while the
  dataset exists (stat("") deleted them all); SpecRegistryPure::targetOf.
- stack up: a pool address goes only to a member in bridge/auto mode on
  that network's bridge with no options/net/ip of its own
  (StackPure::poolEligible); others are warned about. 1.1.68 injected
  one into NAT members, which Spec::validate refuses. Member networks
  come from one template-merged YAML base (StackSpec::netInfo), which
  replaces the Spec-level collectContainerIPs; prefix and gateway from
  the network the address was drawn from.
- crated waits for every `crate run` it spawns (zombies since 1.1.65).
- crate.5, README en/uk, runbook §4m, CHANGELOG, TODO, VERSION 1.1.70.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X6t6tzVypHye5bDGLxzmZK
@click0
click0 merged commit b0399bf into main Nov 6, 2026
5 checks passed
click0 pushed a commit that referenced this pull request Nov 6, 2026
Folded into 1.1.70 (not tagged yet), on top of #262:

- Host descriptors no longer reach jails: SOCK_CLOEXEC on the cached
  IfconfigOps socket; closefrom(3) in the children of the Util exec
  helpers, JailExec and the ws-console shell; the crated-spawned
  supervisor keeps only stdio and its status pipe.
- devfs: a per-user caller may fill only a private ruleset
  (10000..59999) that no live jail of another caller uses; crated
  records every apply_devfs_rules; add_devfs_unhide_rule is refused to
  tenants; crate run steps to the next number on a refusal.
- backup-prune applies retention per jail; 128-char jail names parse.
- HTTP export: tar --one-file-system, paths from pathnames.h.
- JailQuery::findContainer: targets by kernel name, jid or container
  name (RunPure::containerNameOf / containerNameOfJail); restart in the
  CLI, the control socket and HTTP decides what to start before it
  stops; start no longer spawns a second instance.
- A tmpfs over /tmp is mounted before the X11 setup (firefox/chromium).
- crate -p stack up: --log-progress before `run` (StatusPure::crateRunArgv).
- One terminal event per --status-fd stream; jail_created carries the
  kernel's jail name.

Docs: crate.5, trust-model en/uk, README en/uk, runbook §4m, CHANGELOG,
TODO (what this left open). make test-unit -Werror: 1602/1602.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X6t6tzVypHye5bDGLxzmZK
click0 added a commit that referenced this pull request Nov 6, 2026
Folded into 1.1.70 (not tagged yet), on top of #262:

- Host descriptors no longer reach jails: SOCK_CLOEXEC on the cached
  IfconfigOps socket; closefrom(3) in the children of the Util exec
  helpers, JailExec and the ws-console shell; the crated-spawned
  supervisor keeps only stdio and its status pipe.
- devfs: a per-user caller may fill only a private ruleset
  (10000..59999) that no live jail of another caller uses; crated
  records every apply_devfs_rules; add_devfs_unhide_rule is refused to
  tenants; crate run steps to the next number on a refusal.
- backup-prune applies retention per jail; 128-char jail names parse.
- HTTP export: tar --one-file-system, paths from pathnames.h.
- JailQuery::findContainer: targets by kernel name, jid or container
  name (RunPure::containerNameOf / containerNameOfJail); restart in the
  CLI, the control socket and HTTP decides what to start before it
  stops; start no longer spawns a second instance.
- A tmpfs over /tmp is mounted before the X11 setup (firefox/chromium).
- crate -p stack up: --log-progress before `run` (StatusPure::crateRunArgv).
- One terminal event per --status-fd stream; jail_created carries the
  kernel's jail name.

Docs: crate.5, trust-model en/uk, README en/uk, runbook §4m, CHANGELOG,
TODO (what this left open). make test-unit -Werror: 1602/1602.


Claude-Session: https://claude.ai/code/session_01X6t6tzVypHye5bDGLxzmZK

Co-authored-by: Claude <noreply@anthropic.com>
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