Skip to content

Commit

Permalink
CVE-2022-36114: limit the maximum unpacked size of a crate to 512MB
Browse files Browse the repository at this point in the history
This gives users of custom registries the same protections, using the
same size limit that crates.io uses.

`LimitErrorReader` code copied from crates.io.
  • Loading branch information
joshtriplett authored and pietroalbini committed Sep 14, 2022
1 parent dafe4a7 commit d1f9553
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/cargo/sources/registry/mod.rs
Expand Up @@ -182,7 +182,9 @@ use crate::util::hex;
use crate::util::interning::InternedString;
use crate::util::into_url::IntoUrl;
use crate::util::network::PollExt;
use crate::util::{restricted_names, CargoResult, Config, Filesystem, OptVersionReq};
use crate::util::{
restricted_names, CargoResult, Config, Filesystem, LimitErrorReader, OptVersionReq,
};

const PACKAGE_SOURCE_LOCK: &str = ".cargo-ok";
pub const CRATES_IO_INDEX: &str = "https://github.com/rust-lang/crates.io-index";
Expand All @@ -194,6 +196,7 @@ const VERSION_TEMPLATE: &str = "{version}";
const PREFIX_TEMPLATE: &str = "{prefix}";
const LOWER_PREFIX_TEMPLATE: &str = "{lowerprefix}";
const CHECKSUM_TEMPLATE: &str = "{sha256-checksum}";
const MAX_UNPACK_SIZE: u64 = 512 * 1024 * 1024;

/// A "source" for a local (see `local::LocalRegistry`) or remote (see
/// `remote::RemoteRegistry`) registry.
Expand Down Expand Up @@ -615,6 +618,7 @@ impl<'cfg> RegistrySource<'cfg> {
}
}
let gz = GzDecoder::new(tarball);
let gz = LimitErrorReader::new(gz, MAX_UNPACK_SIZE);
let mut tar = Archive::new(gz);
let prefix = unpack_dir.file_name().unwrap();
let parent = unpack_dir.parent().unwrap();
Expand Down
27 changes: 27 additions & 0 deletions src/cargo/util/io.rs
@@ -0,0 +1,27 @@
use std::io::{self, Read, Take};

#[derive(Debug)]
pub struct LimitErrorReader<R> {
inner: Take<R>,
}

impl<R: Read> LimitErrorReader<R> {
pub fn new(r: R, limit: u64) -> LimitErrorReader<R> {
LimitErrorReader {
inner: r.take(limit),
}
}
}

impl<R: Read> Read for LimitErrorReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self.inner.read(buf) {
Ok(0) if self.inner.limit() == 0 => Err(io::Error::new(
io::ErrorKind::Other,
"maximum limit reached when reading",
)),
e => e,
}
}
}

2 changes: 2 additions & 0 deletions src/cargo/util/mod.rs
Expand Up @@ -14,6 +14,7 @@ pub use self::hasher::StableHasher;
pub use self::hex::{hash_u64, short_hash, to_hex};
pub use self::into_url::IntoUrl;
pub use self::into_url_with_base::IntoUrlWithBase;
pub(crate) use self::io::LimitErrorReader;
pub use self::lev_distance::{closest, closest_msg, lev_distance};
pub use self::lockserver::{LockServer, LockServerClient, LockServerStarted};
pub use self::progress::{Progress, ProgressStyle};
Expand Down Expand Up @@ -44,6 +45,7 @@ pub mod important_paths;
pub mod interning;
pub mod into_url;
mod into_url_with_base;
mod io;
pub mod job;
pub mod lev_distance;
mod lockserver;
Expand Down

0 comments on commit d1f9553

Please sign in to comment.