Skip to content

Commit fd5b28b

Browse files
committed
sandlock-oci: mount sysfs read-only so the sandbox sees a populated /sys
Signed-off-by: Cong Wang <cwang@multikernel.io>
1 parent 893ef07 commit fd5b28b

1 file changed

Lines changed: 28 additions & 9 deletions

File tree

crates/sandlock-oci/src/policy.rs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -340,12 +340,16 @@ fn rootfs_path(spec: &Spec, bundle: &Path) -> Result<Option<PathBuf>> {
340340
/// - **tmpfs** writable scratch (`/tmp`, `/run`, `/dev/shm`, …): backed by a
341341
/// host directory under the sandbox state dir and bind-mounted read-write,
342342
/// so it works on a read-only root and stays isolated from the rootfs.
343-
/// - **proc**: `fs_mount(dest, /proc)` — the host procfs, so the sandbox gets a
344-
/// full `/proc` like a container; the seccomp `/proc` handler synthesizes the
345-
/// limit-aware files on top and blocks foreign PIDs / sensitive paths.
346-
/// - **tmpfs at `/dev`, sysfs**: passed through read-only so sandlock's `/dev`
347-
/// interception services them; an empty backing dir would shadow `/dev/null`,
348-
/// `/sys/*`, etc.
343+
/// - **proc**: `fs_mount(dest, /proc)` read-only — the host procfs, so the
344+
/// sandbox gets a full `/proc` like a container; the seccomp `/proc` handler
345+
/// synthesizes the limit-aware files on top and blocks foreign PIDs /
346+
/// sensitive paths. Read-only blocks host-global writes (`/proc/sys/*`).
347+
/// - **sysfs**: `fs_mount(dest, /sys)` read-only — the host sysfs, so the
348+
/// sandbox sees a populated `/sys`. Read-only blocks host-global writes
349+
/// (`/sys/power/state`, …); there is no per-path filter, so reads are full
350+
/// host sysfs (as in a container's ro `/sys`).
351+
/// - **tmpfs at `/dev`**: passed through read-only so sandlock's `/dev`
352+
/// interception services it; an empty backing dir would shadow `/dev/null`.
349353
/// - **devpts/mqueue/cgroup**: skipped (no safe namespace-less equivalent).
350354
fn map_mounts(
351355
mounts: &[oci_spec::runtime::Mount],
@@ -377,9 +381,17 @@ fn map_mounts(
377381
fs_mount.push((dest.to_path_buf(), PathBuf::from("/proc")));
378382
fs_mount_ro.push(dest.to_path_buf());
379383
}
380-
// sysfs: pass the host's through read-only; sandlock's sensitive-path
381-
// filter still gates it.
382-
"sysfs" => fs_read.push(PathBuf::from("/sys")),
384+
// sysfs: mount the host /sys READ-ONLY at the requested destination
385+
// so the sandbox sees a populated /sys like a container (an empty
386+
// rootfs /sys is otherwise bare). Read-only is mandatory: writable
387+
// sysfs exposes host-global controls (/sys/power/state,
388+
// /sys/kernel/*, device controls). Unlike /proc there is no
389+
// per-path sandlock filter for sysfs, so this is full read-only host
390+
// sysfs exposure (consistent with a container's ro /sys mount).
391+
"sysfs" => {
392+
fs_mount.push((dest.to_path_buf(), PathBuf::from("/sys")));
393+
fs_mount_ro.push(dest.to_path_buf());
394+
}
383395

384396
"tmpfs" => {
385397
if dest.to_str() == Some("/dev") {
@@ -656,6 +668,7 @@ mod tests {
656668
"mounts": [
657669
{ "destination": "/tmp", "type": "tmpfs", "source": "tmpfs" },
658670
{ "destination": "/proc", "type": "proc", "source": "proc" },
671+
{ "destination": "/sys", "type": "sysfs", "source": "sysfs" },
659672
{ "destination": "/dev", "type": "tmpfs", "source": "tmpfs" }
660673
]
661674
});
@@ -681,6 +694,12 @@ mod tests {
681694
// ...and it is read-only, so the sandbox can't write host-global
682695
// controls like /proc/sys/* through the mount.
683696
assert!(policy.fs_mount_ro.contains(&PathBuf::from("/proc")));
697+
// /sys mounts the host sysfs read-only, same as /proc.
698+
assert!(policy
699+
.fs_mount
700+
.iter()
701+
.any(|(d, h)| d == Path::new("/sys") && h == Path::new("/sys")));
702+
assert!(policy.fs_mount_ro.contains(&PathBuf::from("/sys")));
684703
// /dev is passed through read-only, not emulated.
685704
assert!(policy.fs_read.contains(&PathBuf::from("/dev")));
686705
assert!(!policy.fs_mount.iter().any(|(d, _)| d == Path::new("/dev")));

0 commit comments

Comments
 (0)