Skip to content

Relocate vDSO/vvar on restore so libc programs resume#140

Open
congwang-mk wants to merge 1 commit into
mainfrom
feat/restore-vdso-relocation
Open

Relocate vDSO/vvar on restore so libc programs resume#140
congwang-mk wants to merge 1 commit into
mainfrom
feat/restore-vdso-relocation

Conversation

@congwang-mk

Copy link
Copy Markdown
Contributor

What

The injection-based restore engine now relocates the kernel-provided [vdso], [vvar], and [vvar_vclock] mappings onto the checkpoint-recorded bases (via injected mremap) before the trampoline is torn down.

Why

glibc/musl cache vDSO function pointers (e.g. clock_gettime) at the vDSO's load-time base. A fresh restore stub maps its vDSO elsewhere under ASLR, so without relocation a restored libc program faulted on its first vDSO call. This was the gate on restoring ordinary programs: previously only vDSO-free (raw-syscall) binaries could be restored. Assumes a same-kernel restore (the vDSO code is byte-identical; only the ASLR base differs).

Changes

  • checkpoint/resume.rs: plan_vdso_moves computes a safe relocation order (no move clobbers a not-yet-moved source; an unresolvable swap is rejected rather than corrupting memory), driven through the existing injection trampoline. Pure ordering logic is unit-tested (5 cases).
  • checkpoint/mod.rs: is_special now also recognizes [vvar_vclock] (a newer-kernel split of [vvar]), so it is relocated rather than captured/restored as normal memory.
  • Docs on restore_into / restore_interactive updated to reflect that vDSO now works.
  • Test: replaced the embedded-C restore tests with a single integration test that drives the shared tests/rootfs-helper.c (new single-process clock-loop command calling clock_gettime each iteration). Checkpoints it mid-loop, kills the original, restores into a fresh sandbox, and asserts the restored process keeps advancing its counter (which requires every post-restore vDSO call to succeed).

Deferred

The leftover-mapping sweep (unmapping the stub's residual mappings so the restored address space is exactly the checkpoint) is not included. Driving munmaps through the ptrace single-step injection channel destabilizes that channel: once the stub's stack/TLS region is unmapped, subsequent injects SIGSEGV even with valid rip/rsp/fs_base and the gadget page intact. This needs a CRIU-style in-target restorer (a self-contained blob running inside the target with its own stack), tracked as follow-up. The /proc/self/maps union and supervisor-memory-exposure this would address already exist on main, so nothing regresses.

Testing

Full suite green: 486 lib tests, 290 integration tests, FFI restore tests, and the chroot tests that exercise the modified helper.

Signed-off-by: Cong Wang <cwang@multikernel.io>
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.

1 participant