Skip to main content

sandlock_core/checkpoint/
mod.rs

1use serde::{Serialize, Deserialize};
2use std::path::PathBuf;
3use crate::sandbox::Sandbox;
4
5pub(crate) mod capture;
6mod image;
7mod inject;
8mod regs;
9pub(crate) mod resume;
10// The execve-stub restore path (blob serializer, supervisor pager, fd
11// convention) is validated by its own unit tests and the end-to-end
12// `test_restore_stub` integration test, but is not yet wired into the live
13// restore code (which still uses the injection engine). The `allow(dead_code)`
14// stands until the supervisor cutover replaces that path; drop it then.
15#[allow(dead_code)]
16pub(crate) mod restore_blob;
17#[allow(dead_code)]
18pub(crate) mod pager;
19
20/// Fixed inherited-fd convention for the execve restore-stub.
21#[allow(dead_code)]
22pub(crate) const CTRL_FD: i32 = 3;   // control-blob memfd
23#[allow(dead_code)]
24pub(crate) const READY_FD: i32 = 4;  // eventfd: stub -> supervisor ("uffd ready")
25#[allow(dead_code)]
26pub(crate) const GO_FD: i32 = 5;     // eventfd: supervisor -> stub ("pager attached")
27#[allow(dead_code)]
28pub(crate) const UFFD_SLOT: i32 = 6; // stub dup2's its userfaultfd here
29
30pub(crate) use capture::capture;
31
32/// A frozen snapshot of sandbox state.
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct Checkpoint {
35    pub name: String,
36    pub policy: Sandbox,
37    pub process_state: ProcessState,
38    pub fd_table: Vec<FdInfo>,
39    pub cow_snapshot: Option<PathBuf>,
40    pub app_state: Option<Vec<u8>>,
41}
42
43/// Captured process state via ptrace (registers) + process_vm_readv (memory) + /proc (metadata).
44#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct ProcessState {
46    pub pid: i32,
47    pub cwd: String,
48    pub exe: String,
49    pub regs: Vec<u64>,
50    pub fpregs: Vec<u8>,
51    pub memory_maps: Vec<MemoryMap>,
52    pub memory_data: Vec<MemorySegment>,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct MemorySegment {
57    pub start: u64,
58    pub data: Vec<u8>,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct MemoryMap {
63    pub start: u64,
64    pub end: u64,
65    pub perms: String,
66    pub offset: u64,
67    pub path: Option<String>,
68}
69
70impl MemoryMap {
71    pub fn writable(&self) -> bool {
72        self.perms.starts_with("rw")
73    }
74
75    pub fn private(&self) -> bool {
76        self.perms.contains('p')
77    }
78
79    pub fn is_special(&self) -> bool {
80        self.path.as_ref().map_or(false, |p| {
81            // `[vvar_vclock]` is a newer-kernel split of `[vvar]`; it is also
82            // kernel-provided and relocated (not captured) during restore.
83            p.starts_with("[vdso]")
84                || p.starts_with("[vvar]")
85                || p.starts_with("[vvar_vclock]")
86                || p.starts_with("[vsyscall]")
87        })
88    }
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct FdInfo {
93    pub fd: i32,
94    pub path: String,
95    pub flags: i32,
96    pub offset: u64,
97}
98
99/// An fd that a restore could not transparently recreate (socket, pipe,
100/// memfd, deleted or pseudo-filesystem path). The restored process runs
101/// without it; such resources fall to the `app_state` hatch.
102#[derive(Debug, Clone, PartialEq, Eq)]
103pub struct SkippedFd {
104    /// The fd number in the checkpointed process.
105    pub fd: i32,
106    /// The resource the fd pointed at (e.g. `pipe:[12345]`, `/memfd:x`).
107    pub path: String,
108}