diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2021-02-06 23:24:05 +0100 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2021-02-06 23:24:05 +0100 |
commit | 6f446ffc9dd49cac07e6c0096cc512e379a7f3ed (patch) | |
tree | 987240e7137a9332dab957899533ffcbe04689c7 | |
parent | ad74dfb5520414b21d2e8b057f846661e671fc2e (diff) | |
download | rebel-6f446ffc9dd49cac07e6c0096cc512e379a7f3ed.tar rebel-6f446ffc9dd49cac07e6c0096cc512e379a7f3ed.zip |
Unpack rootfs into tmpfs in runc namespace
-rw-r--r-- | Cargo.lock | 33 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/runner/runc.rs | 4 | ||||
-rw-r--r-- | src/runner/runc/init.rs | 80 | ||||
-rw-r--r-- | src/runner/runc/run.rs | 18 |
5 files changed, 124 insertions, 12 deletions
@@ -74,6 +74,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e" [[package]] +name = "filetime" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "winapi 0.3.9", +] + +[[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -355,6 +367,7 @@ dependencies = [ "scopeguard", "serde", "serde_yaml", + "tar", "users", "walkdir", ] @@ -442,6 +455,17 @@ dependencies = [ ] [[package]] +name = "tar" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0313546c01d59e29be4f09687bcb4fb6690cec931cc3607b6aec7a0e417f4cc6" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] name = "tempfile" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -557,6 +581,15 @@ dependencies = [ ] [[package]] +name = "xattr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +dependencies = [ + "libc", +] + +[[package]] name = "yaml-rust" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -14,5 +14,6 @@ nix = "0.19.1" scopeguard = "1.1.0" serde = { version = "1", features = ["derive"] } serde_yaml = "0.8" +tar = "0.4.32" users = "0.11.0" walkdir = "2" diff --git a/src/runner/runc.rs b/src/runner/runc.rs index 6a60eea..35ef1f4 100644 --- a/src/runner/runc.rs +++ b/src/runner/runc.rs @@ -19,7 +19,7 @@ fn runner( init_error_sender: ipc::IpcSender<init::Error>, channel: ipc::IpcReceiver<Request>, ) -> ! { - if let Err(error) = init::runc_initialize() { + if let Err(error) = init::runc_unshare() { init_error_sender.send(error).expect("IPC send() failed"); process::exit(1); } @@ -36,6 +36,8 @@ fn runner( unistd::setgid(unistd::Gid::from_raw(0)).expect("setgid()"); unistd::setgroups(&[]).expect("setgroups()"); + init::runc_initialize().unwrap(); + while let Ok(request) = channel.recv() { let Request(task, task_def, reply_sender) = request; if let Err(error) = run::handle_task(task, task_def) { diff --git a/src/runner/runc/init.rs b/src/runner/runc/init.rs index 02b89e4..1786719 100644 --- a/src/runner/runc/init.rs +++ b/src/runner/runc/init.rs @@ -1,4 +1,10 @@ -use std::io; +use std::{ + ffi::CString, + fs::{DirBuilder, File}, + io, + os::unix::ffi::OsStrExt, + path::Path, +}; use nix::{ mount::{self, MsFlags}, @@ -6,7 +12,9 @@ use nix::{ }; use serde::{Deserialize, Serialize}; -fn mount_buildtmp() -> nix::Result<()> { +use crate::util::ToIOResult; + +fn prepare_buildtmp() -> io::Result<()> { mount::mount::<_, _, _, str>( Some("buildtmp"), "build/tmp", @@ -14,6 +22,56 @@ fn mount_buildtmp() -> nix::Result<()> { MsFlags::empty(), None, ) + .to_io_result()?; + + DirBuilder::new().create("build/tmp/rootfs")?; + + { + let file = File::open("build/rootfs.tar")?; + let mut archive = tar::Archive::new(file); + archive.set_preserve_permissions(true); + archive.set_preserve_mtime(true); + archive.set_unpack_xattrs(true); + + let dst = Path::new("build/tmp/rootfs"); + + for entry_r in archive.entries()? { + let mut entry = entry_r?; + if entry.unpack_in(dst)? { + let header = entry.header(); + let uid = header.uid()? as libc::uid_t; + let gid = header.gid()? as libc::gid_t; + + let path = CString::new(dst.join(entry.path()?).as_os_str().as_bytes()) + .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + if unsafe { libc::lchown(path.as_ptr(), uid, gid) } < 0 { + return Err(io::Error::last_os_error()); + } + } + } + } + + DirBuilder::new().create("build/tmp/runc")?; + DirBuilder::new().create("build/tmp/runc/rootfs")?; + + mount::mount::<_, _, str, str>( + Some("build/tmp/rootfs"), + "build/tmp/runc/rootfs", + None, + MsFlags::MS_BIND, + None, + ) + .to_io_result()?; + mount::mount::<str, _, str, str>( + None, + "build/tmp/runc/rootfs", + None, + MsFlags::MS_BIND | MsFlags::MS_REMOUNT | MsFlags::MS_RDONLY, + None, + ) + .to_io_result()?; + + Ok(()) } #[derive(Debug, Deserialize, Serialize)] @@ -22,11 +80,11 @@ pub enum Error { String(String), } -impl From<nix::Error> for Error { - fn from(error: nix::Error) -> Self { - match error { - nix::Error::Sys(code) => Error::Code(code as i32), - _ => Error::String(error.to_string()), +impl From<io::Error> for Error { + fn from(error: io::Error) -> Self { + match error.raw_os_error() { + Some(code) => Error::Code(code), + None => Error::String(error.to_string()), } } } @@ -40,8 +98,12 @@ impl From<Error> for io::Error { } } +pub fn runc_unshare() -> Result<(), Error> { + sched::unshare(CloneFlags::CLONE_NEWUSER | CloneFlags::CLONE_NEWNS).to_io_result()?; + Ok(()) +} + pub fn runc_initialize() -> Result<(), Error> { - sched::unshare(CloneFlags::CLONE_NEWUSER | CloneFlags::CLONE_NEWNS)?; - mount_buildtmp()?; + prepare_buildtmp()?; Ok(()) } diff --git a/src/runner/runc/run.rs b/src/runner/runc/run.rs index 2d13330..9261b7d 100644 --- a/src/runner/runc/run.rs +++ b/src/runner/runc/run.rs @@ -1,4 +1,4 @@ -use std::io; +use std::{io, process}; use serde::{Deserialize, Serialize}; @@ -13,6 +13,20 @@ impl From<Error> for io::Error { } pub fn handle_task(task: TaskRef, task_def: Task) -> Result<(), Error> { - println!("{}:\n\t{:?}", task, task_def); + let result = process::Command::new("sh") + .arg("-c") + .arg(task_def.run) + .current_dir("build/tmp/runc/rootfs") + .output(); + if let Ok(output) = result { + println!( + "{}:\n{}", + task, + String::from_utf8_lossy(output.stdout.as_slice()), + ); + } else { + println!("{}:\n\t{:?}", task, result); + } + Ok(()) } |