diff --git a/.gitignore b/.gitignore index f2e972d..adc6c0c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ # These are backup files generated by rustfmt **/*.rs.bk + +# Example nix directory +/.nix/ diff --git a/Cargo.lock b/Cargo.lock index 332d620..98947ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,169 +1,203 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "anyhow" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee67c11feeac938fae061b232e38e0b6d94f97a9df10e6271319325ac4c56a86" + [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "cc" version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "getrandom" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "libc", + "wasi", ] [[package]] name = "libc" -version = "0.2.68" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" [[package]] name = "nix" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" +dependencies = [ + "bitflags", + "cc", + "cfg-if 0.1.10", + "libc", + "void", +] + +[[package]] +name = "nix" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", ] [[package]] name = "nix-user-chroot" version = "1.0.3" dependencies = [ - "nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.17.0", + "rooter", + "tempfile", ] [[package]] name = "ppv-lite86" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" [[package]] name = "rand" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", ] [[package]] name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core", ] [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core", ] [[package]] name = "redox_syscall" version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" [[package]] name = "remove_dir_all" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", +] + +[[package]] +name = "rooter" +version = "0.1.0" +source = "git+https://gitlab.com/jD91mZM2/rooter#78443972cbc28d56368942ef4ad76617d68690a4" +dependencies = [ + "anyhow", + "libc", + "nix 0.19.1", + "tempfile", ] [[package]] name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", ] [[package]] name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "winapi" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" -"checksum nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" -"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index f71f623..c1aa138 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,5 @@ edition = "2018" [dependencies] nix = "0.17.*" -tempfile = "3" \ No newline at end of file +tempfile = "3" +rooter = { git = "https://gitlab.com/jD91mZM2/rooter" } diff --git a/container.sh b/container.sh new file mode 100755 index 0000000..92f2cd2 --- /dev/null +++ b/container.sh @@ -0,0 +1,26 @@ +ENGINE=docker + +if ! which "$ENGINE" &>/dev/null ; then + ENGINE=podman +fi + +if ! which "$ENGINE" &>/dev/null ; then + echo "No docker or podman in PATH" >&2 + exit 1 +fi + +read -d '' script < = None; - -fn bind_mount(source: &Path, dest: &Path) { - if let Err(e) = mount( - Some(source), - dest, - Some("none"), - MsFlags::MS_BIND | MsFlags::MS_REC, - NONE, - ) { - eprintln!( - "failed to bind mount {} to {}: {}", - source.display(), - dest.display(), - e - ); - } -} - -fn bind_mount_directory(entry: &fs::DirEntry) { - let mountpoint = PathBuf::from("/").join(entry.file_name()); - if let Err(e) = fs::create_dir(&mountpoint) { - if e.kind() != io::ErrorKind::AlreadyExists { - let e2: io::Result<()> = Err(e); - e2.unwrap_or_else(|_| panic!("failed to create {}", &mountpoint.display())); - } - } - - bind_mount(&entry.path(), &mountpoint) -} - -fn bind_mount_file(entry: &fs::DirEntry) { - let mountpoint = PathBuf::from("/").join(entry.file_name()); - fs::File::create(&mountpoint) - .unwrap_or_else(|_| panic!("failed to create {}", &mountpoint.display())); - - bind_mount(&entry.path(), &mountpoint) -} - -fn mirror_symlink(entry: &fs::DirEntry) { - let path = entry.path(); - let target = fs::read_link(&path) - .unwrap_or_else(|_| panic!("failed to resolve symlink {}", &path.display())); - let link_path = PathBuf::from("/").join(entry.file_name()); - symlink(&target, &link_path).unwrap_or_else(|_| { - panic!( - "failed to create symlink {} -> {}", - &link_path.display(), - &target.display() - ) - }); -} - -fn bind_mount_direntry(entry: io::Result) { - let entry = entry.expect("error while listing from /nix directory"); - // do not bind mount an existing nix installation - if entry.file_name() == PathBuf::from("nix") { - return; - } - let path = entry.path(); - let stat = entry - .metadata() - .unwrap_or_else(|_| panic!("cannot get stat of {}", path.display())); - if stat.is_dir() { - bind_mount_directory(&entry); - } else if stat.is_file() { - bind_mount_file(&entry); - } else if stat.file_type().is_symlink() { - mirror_symlink(&entry); - } -} +use rooter::Rooter; fn run_chroot(nixdir: &Path, rootdir: &Path, cmd: &str, args: &[String]) { - let cwd = env::current_dir().expect("cannot get current working directory"); - let uid = unistd::getuid(); let gid = unistd::getgid(); @@ -99,59 +24,23 @@ fn run_chroot(nixdir: &Path, rootdir: &Path, cmd: &str, args: &[String]) { // prepare pivot_root call: // rootdir must be a mount point - mount( - Some(rootdir), - rootdir, - Some("none"), - MsFlags::MS_BIND | MsFlags::MS_REC, - NONE, - ) - .expect("failed to re-bind mount / to our new chroot"); - - mount( - Some(rootdir), - rootdir, - Some("none"), - MsFlags::MS_PRIVATE | MsFlags::MS_REC, - NONE, - ).expect("failed to re-mount our chroot as private mount"); - - // create the mount point for the old root - // The old root cannot be unmounted/removed after pivot_root, the only way to - // keep / clean is to hide the directory with another mountpoint. Therefore - // we pivot the old root to /nix. This is somewhat confusing, though. - let nix_mountpoint = rootdir.join("nix"); - fs::create_dir(&nix_mountpoint) - .unwrap_or_else(|_| panic!("failed to create {}/nix", &nix_mountpoint.display())); - - unistd::pivot_root(rootdir, &nix_mountpoint).unwrap_or_else(|_| { - panic!( - "pivot_root({},{})", - rootdir.display(), - nix_mountpoint.display() - ) - }); - - env::set_current_dir("/").expect("cannot change directory to /"); + let mut rooter = Rooter::new(rootdir.to_owned()); // bind mount all / stuff into rootdir // the orginal content of / now available under /nix - let nix_root = PathBuf::from("/nix"); - let dir = fs::read_dir(&nix_root).expect("failed to list /nix directory"); + let nix_root = PathBuf::from("/"); + let dir = fs::read_dir(&nix_root).expect("failed to list / directory"); for entry in dir { - bind_mount_direntry(entry); + let entry = entry.expect("failed to read directory entry"); + let path = Path::new("/").join(entry.file_name()); + rooter.bind_self(path).expect("failed to bind host directory"); } - // mount the store and hide the old root - // we fetch nixdir under the old root - let nix_store = nix_root.join(nixdir); - mount( - Some(&nix_store), - "/nix", - Some("none"), - MsFlags::MS_BIND | MsFlags::MS_REC, - NONE, - ) - .unwrap_or_else(|_| panic!("failed to bind mount {} to /nix", nix_store.display())); + + rooter + .bind_dir(nixdir, "/nix").expect("failed to bind /nix") + .preserve_cwd(true); + + rooter.chroot().expect("failed to change root directory"); // fixes issue #1 where writing to /proc/self/gid_map fails // see user_namespaces(7) for more documentation @@ -171,10 +60,6 @@ fn run_chroot(nixdir: &Path, rootdir: &Path, cmd: &str, args: &[String]) { .write_all(format!("{} {} 1", gid, gid).as_bytes()) .expect("failed to write new gid mapping to /proc/self/gid_map"); - // restore cwd - env::set_current_dir(&cwd) - .unwrap_or_else(|_| panic!("cannot restore working directory {}", cwd.display())); - let err = process::Command::new(cmd) .args(args) .env("NIX_CONF_DIR", "/nix/etc/nix")