mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-25 15:26:17 +02:00
Validate tarball components
This commit is contained in:
parent
4581159e3f
commit
5a6d6da7ae
5 changed files with 27 additions and 5 deletions
|
@ -11,7 +11,10 @@ pub extern "C" fn unpack_tarfile(
|
||||||
source: foreign::Source,
|
source: foreign::Source,
|
||||||
dest_dir: &str,
|
dest_dir: &str,
|
||||||
) -> CBox<Result<(), error::CppException>> {
|
) -> CBox<Result<(), error::CppException>> {
|
||||||
CBox::new(util::tarfile::unpack_tarfile(source, dest_dir).map_err(|err| err.into()))
|
CBox::new(
|
||||||
|
util::tarfile::unpack_tarfile(source, std::path::Path::new(dest_dir))
|
||||||
|
.map_err(|err| err.into()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
|
@ -23,6 +23,7 @@ pub enum Error {
|
||||||
HttpError(hyper::error::Error),
|
HttpError(hyper::error::Error),
|
||||||
Misc(String),
|
Misc(String),
|
||||||
Foreign(CppException),
|
Foreign(CppException),
|
||||||
|
BadTarFileMemberName(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<std::io::Error> for Error {
|
impl From<std::io::Error> for Error {
|
||||||
|
@ -64,6 +65,9 @@ impl fmt::Display for Error {
|
||||||
Error::HttpError(err) => write!(f, "HTTP error: {}", err),
|
Error::HttpError(err) => write!(f, "HTTP error: {}", err),
|
||||||
Error::Foreign(_) => write!(f, "<C++ exception>"), // FIXME
|
Error::Foreign(_) => write!(f, "<C++ exception>"), // FIXME
|
||||||
Error::Misc(s) => write!(f, "{}", s),
|
Error::Misc(s) => write!(f, "{}", s),
|
||||||
|
Error::BadTarFileMemberName(s) => {
|
||||||
|
write!(f, "tar archive contains illegal file name '{}'", s)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,18 +2,28 @@ use crate::{foreign::Source, Error};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::os::unix::fs::OpenOptionsExt;
|
use std::os::unix::fs::OpenOptionsExt;
|
||||||
use std::path::Path;
|
use std::path::{Component, Path};
|
||||||
use tar::Archive;
|
use tar::Archive;
|
||||||
|
|
||||||
pub fn unpack_tarfile(source: Source, dest_dir: &str) -> Result<(), Error> {
|
pub fn unpack_tarfile(source: Source, dest_dir: &Path) -> Result<(), Error> {
|
||||||
let dest_dir = Path::new(dest_dir);
|
fs::create_dir_all(dest_dir)?;
|
||||||
|
|
||||||
let mut tar = Archive::new(source);
|
let mut tar = Archive::new(source);
|
||||||
|
|
||||||
for file in tar.entries()? {
|
for file in tar.entries()? {
|
||||||
let mut file = file?;
|
let mut file = file?;
|
||||||
|
|
||||||
let dest_file = dest_dir.join(file.path()?);
|
let path = file.path()?;
|
||||||
|
|
||||||
|
for i in path.components() {
|
||||||
|
if let Component::Prefix(_) | Component::RootDir | Component::ParentDir = i {
|
||||||
|
return Err(Error::BadTarFileMemberName(
|
||||||
|
file.path()?.to_str().unwrap().to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let dest_file = dest_dir.join(path);
|
||||||
|
|
||||||
fs::create_dir_all(dest_file.parent().unwrap())?;
|
fs::create_dir_all(dest_file.parent().unwrap())?;
|
||||||
|
|
||||||
|
|
BIN
tests/bad.tar.xz
Normal file
BIN
tests/bad.tar.xz
Normal file
Binary file not shown.
|
@ -35,3 +35,8 @@ test_tarball() {
|
||||||
test_tarball '' cat
|
test_tarball '' cat
|
||||||
test_tarball .xz xz
|
test_tarball .xz xz
|
||||||
test_tarball .gz gzip
|
test_tarball .gz gzip
|
||||||
|
|
||||||
|
rm -rf $TEST_ROOT/tmp
|
||||||
|
mkdir -p $TEST_ROOT/tmp
|
||||||
|
(! TMPDIR=$TEST_ROOT/tmp XDG_RUNTIME_DIR=$TEST_ROOT/tmp nix-env -f file://$(pwd)/bad.tar.xz -qa --out-path)
|
||||||
|
(! [ -e $TEST_ROOT/tmp/bad ])
|
||||||
|
|
Loading…
Reference in a new issue