Skip to content
Permalink
Browse files Browse the repository at this point in the history
CVE-2022-36114: limit the maximum unpacked size of a crate to 512MB
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.