Skip to content

Commit dafe4a7

Browse files
weihanglopietroalbini
authored andcommitted
CVE-2022-36113: add tests
1 parent 97b8091 commit dafe4a7

File tree

2 files changed

+74
-7
lines changed

2 files changed

+74
-7
lines changed

crates/cargo-test-support/src/registry.rs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -403,10 +403,17 @@ pub struct Dependency {
403403
optional: bool,
404404
}
405405

406+
/// Entry with data that corresponds to [`tar::EntryType`].
407+
#[non_exhaustive]
408+
enum EntryData {
409+
Regular(String),
410+
Symlink(PathBuf),
411+
}
412+
406413
/// A file to be created in a package.
407414
struct PackageFile {
408415
path: String,
409-
contents: String,
416+
contents: EntryData,
410417
/// The Unix mode for the file. Note that when extracted on Windows, this
411418
/// is mostly ignored since it doesn't have the same style of permissions.
412419
mode: u32,
@@ -780,13 +787,24 @@ impl Package {
780787
pub fn file_with_mode(&mut self, path: &str, mode: u32, contents: &str) -> &mut Package {
781788
self.files.push(PackageFile {
782789
path: path.to_string(),
783-
contents: contents.to_string(),
790+
contents: EntryData::Regular(contents.into()),
784791
mode,
785792
extra: false,
786793
});
787794
self
788795
}
789796

797+
/// Adds a symlink to a path to the package.
798+
pub fn symlink(&mut self, dst: &str, src: &str) -> &mut Package {
799+
self.files.push(PackageFile {
800+
path: dst.to_string(),
801+
contents: EntryData::Symlink(src.into()),
802+
mode: DEFAULT_MODE,
803+
extra: false,
804+
});
805+
self
806+
}
807+
790808
/// Adds an "extra" file that is not rooted within the package.
791809
///
792810
/// Normal files are automatically placed within a directory named
@@ -795,7 +813,7 @@ impl Package {
795813
pub fn extra_file(&mut self, path: &str, contents: &str) -> &mut Package {
796814
self.files.push(PackageFile {
797815
path: path.to_string(),
798-
contents: contents.to_string(),
816+
contents: EntryData::Regular(contents.to_string()),
799817
mode: DEFAULT_MODE,
800818
extra: true,
801819
});
@@ -1033,7 +1051,7 @@ impl Package {
10331051
self.append_manifest(&mut a);
10341052
}
10351053
if self.files.is_empty() {
1036-
self.append(&mut a, "src/lib.rs", DEFAULT_MODE, "");
1054+
self.append(&mut a, "src/lib.rs", DEFAULT_MODE, &EntryData::Regular("".into()));
10371055
} else {
10381056
for PackageFile {
10391057
path,
@@ -1107,10 +1125,10 @@ impl Package {
11071125
manifest.push_str("[lib]\nproc-macro = true\n");
11081126
}
11091127

1110-
self.append(ar, "Cargo.toml", DEFAULT_MODE, &manifest);
1128+
self.append(ar, "Cargo.toml", DEFAULT_MODE, &EntryData::Regular(manifest.into()));
11111129
}
11121130

1113-
fn append<W: Write>(&self, ar: &mut Builder<W>, file: &str, mode: u32, contents: &str) {
1131+
fn append<W: Write>(&self, ar: &mut Builder<W>, file: &str, mode: u32, contents: &EntryData) {
11141132
self.append_raw(
11151133
ar,
11161134
&format!("{}-{}/{}", self.name, self.vers, file),
@@ -1119,8 +1137,16 @@ impl Package {
11191137
);
11201138
}
11211139

1122-
fn append_raw<W: Write>(&self, ar: &mut Builder<W>, path: &str, mode: u32, contents: &str) {
1140+
fn append_raw<W: Write>(&self, ar: &mut Builder<W>, path: &str, mode: u32, contents: &EntryData) {
11231141
let mut header = Header::new_ustar();
1142+
let contents = match contents {
1143+
EntryData::Regular(contents) => contents.as_str(),
1144+
EntryData::Symlink(src) => {
1145+
header.set_entry_type(tar::EntryType::Symlink);
1146+
t!(header.set_link_name(src));
1147+
"" // Symlink has no contents.
1148+
}
1149+
};
11241150
header.set_size(contents.len() as u64);
11251151
t!(header.set_path(path));
11261152
header.set_mode(mode);

tests/testsuite/registry.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2583,6 +2583,47 @@ fn package_lock_inside_package_is_overwritten() {
25832583
assert_eq!(ok.metadata().unwrap().len(), 2);
25842584
}
25852585

2586+
#[cargo_test]
2587+
fn package_lock_as_a_symlink_inside_package_is_overwritten() {
2588+
let registry = registry::init();
2589+
let p = project()
2590+
.file(
2591+
"Cargo.toml",
2592+
r#"
2593+
[project]
2594+
name = "foo"
2595+
version = "0.0.1"
2596+
authors = []
2597+
2598+
[dependencies]
2599+
bar = ">= 0.0.0"
2600+
"#,
2601+
)
2602+
.file("src/main.rs", "fn main() {}")
2603+
.build();
2604+
2605+
Package::new("bar", "0.0.1")
2606+
.file("src/lib.rs", "pub fn f() {}")
2607+
.symlink(".cargo-ok", "src/lib.rs")
2608+
.publish();
2609+
2610+
p.cargo("build").run();
2611+
2612+
let id = SourceId::for_registry(registry.index_url()).unwrap();
2613+
let hash = cargo::util::hex::short_hash(&id);
2614+
let pkg_root = cargo_home()
2615+
.join("registry")
2616+
.join("src")
2617+
.join(format!("-{}", hash))
2618+
.join("bar-0.0.1");
2619+
let ok = pkg_root.join(".cargo-ok");
2620+
let librs = pkg_root.join("src/lib.rs");
2621+
2622+
// Is correctly overwritten and doesn't affect the file linked to
2623+
assert_eq!(ok.metadata().unwrap().len(), 2);
2624+
assert_eq!(fs::read_to_string(librs).unwrap(), "pub fn f() {}");
2625+
}
2626+
25862627
#[cargo_test]
25872628
fn ignores_unknown_index_version_http() {
25882629
let _server = setup_http();

0 commit comments

Comments
 (0)