Refer: https://github.com/rust-lang/cargo/commit/2b68d3c07a4a056264dc006ecb9f1354a0679cd3 https://build.opensuse.org/package/show/SUSE:SLE-15-SP3:Update/rust1.62 From 2b68d3c07a4a056264dc006ecb9f1354a0679cd3 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 18 Aug 2022 17:45:45 +0200 Subject: [PATCH] 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. --- .../cargo/src/cargo/sources/registry/mod.rs | 4 ++- src/tools/cargo/src/cargo/util/io.rs | 27 +++++++++++++++++++ src/tools/cargo/src/cargo/util/mod.rs | 2 ++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/tools/cargo/src/cargo/util/io.rs diff --git a/src/tools/cargo/src/cargo/sources/registry/mod.rs b/src/tools/cargo/src/cargo/sources/registry/mod.rs index 5357e9c..e2028d5 100644 --- a/src/tools/cargo/src/cargo/sources/registry/mod.rs +++ b/src/tools/cargo/src/cargo/sources/registry/mod.rs @@ -179,7 +179,7 @@ use crate::util::errors::CargoResultExt; use crate::util::hex; use crate::util::interning::InternedString; use crate::util::into_url::IntoUrl; -use crate::util::{restricted_names, CargoResult, Config, Filesystem}; +use crate::util::{restricted_names, CargoResult, Config, Filesystem, LimitErrorReader}; const PACKAGE_SOURCE_LOCK: &str = ".cargo-ok"; pub const CRATES_IO_INDEX: &str = "https://github.com/rust-lang/crates.io-index"; @@ -188,6 +188,7 @@ const CRATE_TEMPLATE: &str = "{crate}"; const VERSION_TEMPLATE: &str = "{version}"; const PREFIX_TEMPLATE: &str = "{prefix}"; const LOWER_PREFIX_TEMPLATE: &str = "{lowerprefix}"; +const MAX_UNPACK_SIZE: u64 = 512 * 1024 * 1024; /// A "source" for a [local](local::LocalRegistry) or /// [remote](remote::RemoteRegistry) registry. @@ -583,6 +584,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(); diff --git a/src/tools/cargo/src/cargo/util/io.rs b/src/tools/cargo/src/cargo/util/io.rs new file mode 100644 index 0000000..f62672d --- /dev/null +++ b/src/tools/cargo/src/cargo/util/io.rs @@ -0,0 +1,27 @@ +use std::io::{self, Read, Take}; + +#[derive(Debug)] +pub struct LimitErrorReader { + inner: Take, +} + +impl LimitErrorReader { + pub fn new(r: R, limit: u64) -> LimitErrorReader { + LimitErrorReader { + inner: r.take(limit), + } + } +} + +impl Read for LimitErrorReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + 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, + } + } +} + diff --git a/src/tools/cargo/src/cargo/util/mod.rs b/src/tools/cargo/src/cargo/util/mod.rs index f0408d2..9e5f83e 100644 --- a/src/tools/cargo/src/cargo/util/mod.rs +++ b/src/tools/cargo/src/cargo/util/mod.rs @@ -13,6 +13,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::paths::{bytes2path, dylib_path, join_paths, path2bytes}; @@ -46,6 +47,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; -- 2.27.0