Skip to content

Commit

Permalink
Mitigate CVE-2021-42574
Browse files Browse the repository at this point in the history
  • Loading branch information
kornelski committed Nov 1, 2021
1 parent 6a9907d commit f542891
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 7 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions cargo-crev/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
edition = '2018'
name = "cargo-crev"
version = "0.21.2"
version = "0.21.3"
authors = ["Dawid Ciężarkiewicz <dpc@dpc.pw>", "Kornel Lesiński <kornel@geekhood.net>"]
categories = ["development-tools::cargo-plugins"]
default-run = "cargo-crev"
Expand All @@ -25,7 +25,7 @@ path = "src/lib.rs"
crev-common = { path = "../crev-common", version = "0.21" }
crev-data = { path = "../crev-data", version = "0.22" }
crev-wot = { path = "../crev-wot", version = "0.22" }
crev-lib = { path = "../crev-lib", version = "0.22" }
crev-lib = { path = "../crev-lib", version = "0.22.1" }
anyhow = "1.0.42"
atty = "0.2.14"
cargo = "0.57.0"
Expand Down
3 changes: 2 additions & 1 deletion crev-lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
edition = "2018"
name = "crev-lib"
version = "0.22.0"
version = "0.22.1"
description = "Library interface for programmatic access to crate reviews of cargo-crev"
authors = ["Dawid Ciężarkiewicz <dpc@dpc.pw>", "Kornel Lesiński <kornel@geekhood.net>"]
documentation = "https://docs.rs/crev-lib"
Expand Down Expand Up @@ -34,3 +34,4 @@ walkdir = "2.3.2"
thiserror = "1.0.26"
rayon = "1.5.1"
aes-siv = "0.6.2"
bstr = "0.2.17"
66 changes: 64 additions & 2 deletions crev-lib/src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use std::{
io,
path::{Path, PathBuf},
};
use std::borrow::Cow;
use bstr::ByteSlice;

pub mod git;

Expand Down Expand Up @@ -171,12 +173,72 @@ pub fn copy_dir_sanitized(
src_path.display()
));
} else if ft.is_file() {
std::fs::copy(entry.path(), &dest_path)?;
// only obviously non-text files get a pass
if is_binary_file_extension(&dest_path) {
std::fs::copy(&src_path, &dest_path)?;
} else {
let input = std::fs::read(&src_path)?;
let output = escape_tricky_unicode(&input);
if output != input {
changes.push(format!("Escaped potentially confusing UTF-8 in '{}'", src_path.display()));
}
std::fs::write(&dest_path, output)?;
}
} else {
assert!(ft.is_dir());
let _ = std::fs::create_dir(&dest_path);
copy_dir_sanitized(&entry.path(), &dest_path, changes)?;
copy_dir_sanitized(&src_path, &dest_path, changes)?;
}
}
Ok(())
}

fn is_binary_file_extension(path: &Path) -> bool {
path.extension().and_then(|e| e.to_str()) .map_or(false, |e| {
matches!(e.to_lowercase().as_str(), "bin" | "zip" | "gz" | "xz" | "bz2" | "jpg" | "jpeg" | "png" | "gif" | "exe" | "dll")
})
}

fn escape_tricky_unicode(input: &[u8]) -> Cow<[u8]> {
if input.is_ascii() {
return input.into();
}

let mut output = Vec::with_capacity(input.len());
for ch in input.utf8_chunks() {
output.extend_from_slice(escape_tricky_unicode_str(ch.valid()).as_bytes());
output.extend_from_slice(ch.invalid());
}
output.into()
}

fn escape_tricky_unicode_str(input: &str) -> Cow<str> {
if input.is_ascii() {
return input.into();
}

use std::fmt::Write;
let mut out = String::with_capacity(input.len());
for ch in input.chars() {
match ch {
// https://blog.rust-lang.org/2021/11/01/cve-2021-42574.html
'\u{202A}' | '\u{202B}' | '\u{202C}' | '\u{202D}' | '\u{202E}' | '\u{2066}' | '\u{2067}' | '\u{2068}' | '\u{2069}' => {
let _ = write!(&mut out, "\\u{{{:04x}}}", ch as u32);
} ,
_ => out.push(ch),
}
}
out.into()
}

#[test]
fn escapes_unicode_bidi() {
let bidi_test = "\u{202A}\u{202B}\u{202C}\u{202D}\u{202E} | \u{2066} | \x00\u{2067} | \u{2068}\u{FFFF} | \u{2069}";
assert_eq!(
"\\u{202a}\\u{202b}\\u{202c}\\u{202d}\\u{202e} | \\u{2066} | \u{0}\\u{2067} | \\u{2068}\u{ffff} | \\u{2069}".as_bytes(),
&*escape_tricky_unicode(bidi_test.as_bytes()),
);

let binary_test = &b"ABC\0\0\0\x11\xff \xc0\xfa\xda"[..];
assert_eq!(binary_test, &*escape_tricky_unicode(binary_test));
}

0 comments on commit f542891

Please sign in to comment.