diff options
-rw-r--r-- | src/runner/container/tar.rs | 99 | ||||
-rw-r--r-- | src/runner/container/task.rs | 4 | ||||
-rw-r--r-- | src/util/fs.rs | 10 |
3 files changed, 65 insertions, 48 deletions
diff --git a/src/runner/container/tar.rs b/src/runner/container/tar.rs index 67993c1..5800aa0 100644 --- a/src/runner/container/tar.rs +++ b/src/runner/container/tar.rs @@ -1,67 +1,76 @@ use std::{ + fs::File, io::{self, Read, Write}, + os::unix::prelude::CommandExt, path::Path, - process, + process::{self, Command, Stdio}, }; -use nix::mount::MsFlags; +use nix::{ + mount::{self, MsFlags}, + sched::CloneFlags, + sys::wait, + unistd, +}; use crate::{ paths, - types::InputHash, util::{error::*, fs, Checkable}, }; -use super::spec; +use super::ns; -pub fn pack<W: Write, P: AsRef<Path>>( - input_hash: &InputHash, - archive: &mut W, - source: P, -) -> Result<()> { - let task_tmp_dir = paths::task_tmp_dir(input_hash); +pub fn pack<W: Write, P: AsRef<Path>>(archive: &mut W, source: P) -> Result<()> { + let (mut piper, pipew) = fs::pipe()?; - let rootfs_mount_target = paths::join(&[&task_tmp_dir, paths::TASK_TMP_ROOTFS_SUBDIR]); - let _rootfs_mount = fs::mount( - paths::ROOTFS_DIR, - &rootfs_mount_target, - None, - MsFlags::MS_BIND, - None, - )?; + let exec_tar = |stdout: File| -> Result<()> { + // We are in our own mount namespace, so mounting into the shared ROOTFS_DIR is fine + let mount_target = paths::join(&[paths::ROOTFS_DIR, paths::TASK_BUILDDIR]); + mount::mount::<_, _, str, str>( + Some(source.as_ref()), + mount_target.as_str(), + None, + MsFlags::MS_BIND, + None, + )?; - let source_mount_target = paths::join(&[&task_tmp_dir, paths::TASK_WORKDIR]); - let _source_mount = fs::mount(source, &source_mount_target, None, MsFlags::MS_BIND, None)?; + unistd::chroot(paths::ROOTFS_DIR).context("chroot()")?; + unistd::chdir(paths::abs(paths::TASK_BUILDDIR).as_str()).context("chdir()")?; - spec::generate_spec(&[ - "tar", - "-c", - "--sort=name", - "--numeric-owner", - "--owner=0", - "--group=0", - "--mtime=@0", - ".", - ]) - .save(paths::join(&[&task_tmp_dir, "config.json"])) - .map_err(Error::new) - .context("Failed to save runtime config")?; + let err = Command::new("tar") + .args(&[ + "-c", + "--sort=name", + "--numeric-owner", + "--owner=0", + "--group=0", + "--mtime=@0", + ".", + ]) + .stdin(Stdio::null()) + .stdout(stdout) + .env_clear() + .env("PATH", "/usr/sbin:/usr/bin:/sbin:/bin") + .exec(); + eprintln!("{}", err); + process::exit(127); + }; - let mut child = process::Command::new("crun") - .arg("--root") - .arg(paths::TASK_TMP_CONTAINERS_ROOT_SUBDIR) - .arg("run") - .arg(input_hash.to_string()) - .current_dir(task_tmp_dir) - .stdin(process::Stdio::null()) - .stdout(process::Stdio::piped()) - .spawn() - .context("Failed to start container runtime")?; + let (pid, pipew) = unsafe { + ns::spawn(CloneFlags::CLONE_NEWNS, pipew, |pipew| { + exec_tar(pipew).unwrap() + }) + } + .context("Failed to run tar")?; - io::copy(&mut child.stdout.take().unwrap(), archive).context("Failed to write TAR archive")?; + drop(pipew); + let result = io::copy(&mut piper, archive).context("Failed to write TAR archive"); - child.wait()?.check()?; + wait::waitpid(pid, None)? + .check() + .context("tar did not exit successfully")?; + result?; Ok(()) } diff --git a/src/runner/container/task.rs b/src/runner/container/task.rs index b6b8026..73d0d64 100644 --- a/src/runner/container/task.rs +++ b/src/runner/container/task.rs @@ -167,7 +167,7 @@ fn collect_output(input_hash: &InputHash, path: &str) -> Result<Option<ArchiveHa let writer = TeeWriter::new(file, hasher); let mut buffered_writer = BufWriter::with_capacity(16 * 1024 * 1024, writer); - super::tar::pack(input_hash, &mut buffered_writer, &source)?; + super::tar::pack(&mut buffered_writer, &source)?; let writer = buffered_writer.into_inner()?; let (file, hasher) = writer.into_inner(); @@ -271,7 +271,7 @@ fn hash_layer(input_hash: &InputHash) -> Result<Option<LayerHash>> { let hasher = LayerHasher::new(); let mut buffered_writer = BufWriter::with_capacity(16 * 1024 * 1024, hasher); - tar::pack(input_hash, &mut buffered_writer, &task_layer_dir)?; + tar::pack(&mut buffered_writer, &task_layer_dir)?; let hasher = buffered_writer.into_inner()?; Ok(Some(LayerHash(StringHash(hasher.finalize().into())))) diff --git a/src/util/fs.rs b/src/util/fs.rs index 9344c72..cfc7610 100644 --- a/src/util/fs.rs +++ b/src/util/fs.rs @@ -1,10 +1,12 @@ use std::{ - fs, io, + fs::{self, File}, + io, os::unix::prelude::*, path::{Path, PathBuf}, }; use nix::{ + fcntl::OFlag, mount::{self, MsFlags}, unistd, }; @@ -112,3 +114,9 @@ pub fn mount<P1: AsRef<Path>, P2: AsRef<Path>>( .with_context(|| format!("Failed to mount {:?}", canon_target))?; Ok(Mount(canon_target)) } + +pub fn pipe() -> Result<(File, File)> { + unistd::pipe2(OFlag::O_CLOEXEC) + .context("pipe2()") + .map(|(piper, pipew)| unsafe { (File::from_raw_fd(piper), File::from_raw_fd(pipew)) }) +} |