From d2524fdb9afed2b1f2ceec5f6e90107fa32668dd Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 30 Oct 2021 22:03:10 +0200 Subject: runner: verify hash when unpacking dependencies --- crates/runner/src/task.rs | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/crates/runner/src/task.rs b/crates/runner/src/task.rs index a6fbd25..08b9cb4 100644 --- a/crates/runner/src/task.rs +++ b/crates/runner/src/task.rs @@ -1,6 +1,6 @@ use std::{ collections::HashMap, - io::BufWriter, + io::{self, BufWriter}, os::unix::prelude::CommandExt, path::Path, process::{self, Command, Stdio}, @@ -15,7 +15,7 @@ use nix::{ unistd::{self, Gid, Uid}, }; use serde::Serialize; -use tee_readwrite::TeeWriter; +use tee_readwrite::{TeeReader, TeeWriter}; use common::{error::*, string_hash::*, types::*}; @@ -156,9 +156,39 @@ fn cleanup_task(input_hash: &InputHash) -> Result<()> { Ok(()) } -fn unpack_dependency, P2: AsRef>(filename: P1, dest: P2) -> Result<()> { - let file = fs::open(filename.as_ref())?; - tar::unpack(file, dest.as_ref()).with_context(|| { +fn unpack_dependency, P2: AsRef>( + filename: P1, + dest: P2, + expected_hash: &ArchiveHash, +) -> Result<()> { + (|| -> Result<()> { + let file = fs::open(filename.as_ref())?; + let hasher = ArchiveHasher::new(); + let buffered_hasher = BufWriter::with_capacity(16 * 1024 * 1024, hasher); + let mut reader = TeeReader::new(file, buffered_hasher, false); + + tar::unpack(&mut reader, dest.as_ref())?; + + // Read file to end to get the correct hash + io::copy(&mut reader, &mut io::sink())?; + + let (_, buffered_hasher) = reader.into_inner(); + let hasher = buffered_hasher.into_inner()?; + + let actual_hash = ArchiveHash(StringHash(hasher.finalize().into())); + + if &actual_hash != expected_hash { + return Err(Error::new(format!( + "Incorrect file hash for {:?} (expected: {}, actual: {})", + filename.as_ref(), + expected_hash, + actual_hash + ))); + } + + Ok(()) + })() + .with_context(|| { format!( "Failed to unpack {:?} to {:?}", filename.as_ref(), @@ -189,6 +219,7 @@ fn unpack_dependencies(input_hash: &InputHash, task: &Task) -> Result<()> { unpack_dependency( paths::archive_filename(output), paths::join(&[&depends_dir, path]), + output, )?; } } -- cgit v1.2.3