fix(checkpoint): restore file-backed mappings and fds under a chroot#142
Merged
Conversation
Checkpoint/restore of a confined (imaged/chrooted) workload failed at restore: sandlock_restore_interactive returned NULL and the process never came back. Two causes, both a mismatch between the paths the checkpoint records and what restore can open: 1. Capture reads /proc/<pid>/maps and /proc/<pid>/fd, whose entries are resolved in the mount namespace and so ignore the process's chroot: a file the workload sees at /lib/ld-musl... is recorded as its host path <rootfs>/lib/ld-musl... The open()s injected during restore run in the already-confined child, where that host path does not resolve, so the remap/reopen fails. restore_into now translates each recorded host path back to the child's in-chroot view (host_to_virtual over the chroot root and mounts) before opening. Non-chroot restores are unchanged. 2. An imaged binary is exec'd from a sealed memfd, so its code region is backed by "/memfd:sandlock-exec (deleted)" -- unreopenable by path. Capture only dumped writable regions, leaving the read-only code to be remapped from a file that cannot be reopened. Capture now also dumps private regions backed by a memfd or a "(deleted)" path so restore reconstructs them from bytes. With both fixes a checkpointed service in an imaged sandbox restores and resumes. Signed-off-by: Cong Wang <cwang@multikernel.io>
af3724d to
1f5b03b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Checkpoint/restore of a confined (imaged/chrooted) workload failed at restore:
sandlock_restore_interactivereturned NULL and the process never resumed. A non-chrooted (host) workload restored fine, so the bug was specific to the chroot path.Root cause
Two manifestations of the same mismatch between the paths the checkpoint records and what restore can open:
Host-recorded paths, opened under chroot. Capture reads
/proc/<pid>/mapsand/proc/<pid>/fd, whose entries are resolved in the mount namespace and therefore ignore the process's chroot. A file the workload sees at/lib/ld-musl-x86_64.so.1is recorded as its host path<rootfs>/lib/ld-musl-x86_64.so.1. Theopen()s injected during restore run in the already-confined child, where that host path does not resolve, so the remap/reopen fails.memfd-backed program text. An imaged binary is exec'd from a sealed memfd, so its code region is backed by
/memfd:sandlock-exec (deleted)— unreopenable by path. Capture only dumped writable regions, leaving the read-only code to be remapped from a file that cannot be reopened.Fix
restore_intotranslates each recorded host path back to the child's in-chroot view viahost_to_virtual(over the chroot root and mounts) before the injectedopen. Non-chroot restores pass paths through unchanged.(deleted)path, so restore reconstructs them from bytes instead of reopening a vanished file.Testing
Verified end to end via sandlock-server on a real host (Linux 7.x, Landlock ABI 10): a service checkpointed while running in an imaged (alpine) sandbox now restores and resumes (
running=True), where it previously failed with a 500.cargo test -p sandlock-core checkpoint::resumepasses.Known limitation (pre-existing, not addressed here)
Active workloads (e.g. a busy shell loop) can still segfault shortly after resume — the documented injection-restore limitation (cached vDSO pointers / unswept stub mappings). This affects direct library restores too and is independent of this fix; a passive process (blocked in a syscall) resumes cleanly.
🤖 Generated with Claude Code