bytecodealliance / rustix

Safe Rust bindings to POSIX-ish APIs
Other
1.46k stars 152 forks source link

Add pivot_root syscall. #1116

Closed ayosec closed 1 month ago

ayosec commented 1 month ago

This pull-request adds the pivot_root syscall.

The implementation is behind the fs feature, like chroot.

It is only enabled on Linux. The manpages for FreeBSD, OpenBSD, and NetBSD show no results. And, according to https://github.com/nginx/unit/issues/737, macOS implements the syscall, but it is undocumented, and its signature is very different.

Test Program

I tested the syscall with the following program:

// Cargo.toml
//
//   [dependencies]
//   rustix = { version = "0.38.34", path = "../rustix", features = ["fs", "mount", "process", "thread"] }

use std::{fs, io::ErrorKind};

use rustix::{
    fs::{mount, unmount, MountFlags, UnmountFlags},
    process::{chdir, pivot_root},
    thread::{unshare, UnshareFlags},
};

fn main() {
    unshare(UnshareFlags::NEWNS | UnshareFlags::NEWUSER).expect("unshare");

    fs::write("/proc/self/uid_map", "0 1000 1").expect("write uid_map");
    fs::write("/proc/self/setgroups", "deny").expect("write setgroups");
    fs::write("/proc/self/gid_map", "0 1000 1").expect("write gid_map");

    // tmpfs on /tmp
    mount(c"none", c"/tmp", c"tmpfs", MountFlags::empty(), c"").expect("mount tmpfs");

    fs::write("/tmp/file0", "").expect("write file0");
    fs::write("/tmp/file1", "").expect("write file1");

    // pivot_root to /tmp
    chdir(c"/tmp").expect("cd /tmp");
    pivot_root(c".", c".").expect("pivot_root");
    unmount(c".", UnmountFlags::DETACH).expect("unmount");

    // See the contents in root.
    chdir(c"/").expect("cd /");
    for entry in std::fs::read_dir("/").expect("read_dir /") {
        println!("{:?}", entry);
    }

    // Detect errors.
    assert_eq!(
        pivot_root(c"bad", c"path").unwrap_err().kind(),
        ErrorKind::NotFound,
    )
}

Output:

$ ./target/debug/rustix-pivot_root
Ok(DirEntry("/file1"))
Ok(DirEntry("/file0"))

From strace:

chdir("/tmp")                           = 0
pivot_root(".", ".")                    = 0
umount2(".", MNT_DETACH)                = 0
chdir("/")                              = 0
ayosec commented 1 month ago

The failure in CI seems to be a problem with GitHub Actions:

The hosted runner encountered an error while running your job. (Error Type: Disconnect).
sunfishcode commented 1 month ago

Thanks!

sunfishcode commented 1 month ago

This is released in rustix 0.38.35.