Skip to content

Commit 8d2bd4c

Browse files
author
curious-rabbit
committed
complete fixes
1 parent de5e24b commit 8d2bd4c

5 files changed

Lines changed: 34 additions & 27 deletions

File tree

src/archive/rar.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use crate::{
88
error::{Error, Result},
99
info,
1010
list::{FileInArchive, ListFileType},
11-
utils::{BytesFmt, PathFmt},
11+
utils::{BytesFmt, PathFmt, validate_entry_path},
12+
warning,
1213
};
1314

1415
/// Unpacks the archive given by `archive_path` into the folder given by `output_folder`.
@@ -25,13 +26,18 @@ pub fn unpack_archive(archive_path: &Path, output_folder: &Path, password: Optio
2526
while let Some(header) = archive.read_header()? {
2627
let entry = header.entry();
2728
archive = if entry.is_file() {
28-
info!(
29-
"extracted ({}) {}",
30-
BytesFmt(entry.unpacked_size),
31-
PathFmt(&entry.filename),
32-
);
33-
files_unpacked += 1;
34-
header.extract_with_base(output_folder)?
29+
if let Err(e) = validate_entry_path(&entry.filename) {
30+
warning!("skipping unsafe rar entry {}: {}", PathFmt(&entry.filename), e);
31+
header.skip()?
32+
} else {
33+
info!(
34+
"extracted ({}) {}",
35+
BytesFmt(entry.unpacked_size),
36+
PathFmt(&entry.filename),
37+
);
38+
files_unpacked += 1;
39+
header.extract_with_base(output_folder)?
40+
}
3541
} else {
3642
header.skip()?
3743
};

src/archive/sevenz.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ use crate::{
1717
info,
1818
list::{FileInArchive, ListFileType},
1919
utils::{
20-
BytesFmt, FileVisibilityPolicy, PathFmt, SanitizedStr, cd_into_same_dir_as, ensure_parent_dir_exists,
21-
is_same_file_as_output, validate_dest_inside_root, validate_entry_path,
20+
BytesFmt, FileVisibilityPolicy, LimitedReader, PathFmt, SanitizedStr, cd_into_same_dir_as,
21+
ensure_parent_dir_exists, is_same_file_as_output, max_decompressed_bytes, validate_dest_inside_root,
22+
validate_entry_path,
2223
},
2324
warning,
2425
};
@@ -64,7 +65,8 @@ where
6465

6566
let file = fs::File::create(path)?;
6667
let mut writer = BufWriter::new(file);
67-
io::copy(reader, &mut writer)?;
68+
let mut limited = LimitedReader::new(reader, max_decompressed_bytes());
69+
io::copy(&mut limited, &mut writer)?;
6870

6971
use filetime_creation as ft;
7072
// Surface mtime-set failures as warnings so users know timestamps weren't preserved

src/archive/zip.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ use crate::{
2222
info, info_accessible,
2323
list::{FileInArchive, ListFileType},
2424
utils::{
25-
BytesFmt, FileType, FileVisibilityPolicy, PathFmt, SanitizedStr, canonicalize, cd_into_same_dir_as,
26-
create_symlink, ensure_parent_dir_exists, get_invalid_utf8_paths, is_same_file_as_output,
27-
pretty_format_list_of_paths, read_file_type, strip_cur_dir, validate_dest_inside_root, validate_symlink_target,
25+
BytesFmt, FileType, FileVisibilityPolicy, LimitedReader, PathFmt, SanitizedStr, canonicalize,
26+
cd_into_same_dir_as, create_symlink, ensure_parent_dir_exists, get_invalid_utf8_paths, is_same_file_as_output,
27+
max_decompressed_bytes, pretty_format_list_of_paths, read_file_type, strip_cur_dir, validate_dest_inside_root,
28+
validate_symlink_target,
2829
},
2930
warning,
3031
};
@@ -106,7 +107,10 @@ where
106107
};
107108
#[cfg(not(unix))]
108109
let mut output_file = fs::File::create(file_path)?;
109-
io::copy(&mut file, &mut output_file)?;
110+
{
111+
let mut limited = LimitedReader::new(&mut file, max_decompressed_bytes());
112+
io::copy(&mut limited, &mut output_file)?;
113+
}
110114
set_last_modified_time(&file, file_path)?;
111115
#[cfg(unix)]
112116
unix_set_permissions(file_path, &file)?;

src/list.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,14 @@ fn print_entry(out: &mut impl Write, name: impl fmt::Display, file_type: &ListFi
9090
};
9191

9292
if is_running_in_accessible_mode() {
93-
let _ = writeln!(out, "{name} -> {}{suffix}", target.display());
93+
let _ = writeln!(out, "{name} -> {}{suffix}", NoQuotePathFmt(target));
9494
} else {
9595
let _ = writeln!(
9696
out,
9797
"{c}{name}{r} {c}-> {c}{target}{suffix}{r}",
9898
c = *CYAN,
9999
r = *ALL_RESET,
100-
target = target.display()
100+
target = NoQuotePathFmt(target)
101101
);
102102
}
103103
}
@@ -129,7 +129,6 @@ mod tree {
129129
path,
130130
};
131131

132-
use bstr::{ByteSlice, ByteVec};
133132
use linked_hash_map::LinkedHashMap;
134133

135134
use super::{FileInArchive, ListFileType};
@@ -199,7 +198,7 @@ mod tree {
199198
};
200199
super::print_entry(
201200
out,
202-
<Vec<u8> as ByteVec>::from_os_str_lossy(name).as_bstr(),
201+
super::NoQuotePathFmt(path::Path::new(name)),
203202
&file_type,
204203
false, // Always show targets in tree view, regardless of --quiet flag
205204
);

src/utils/fs.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ pub fn normalize_safe_path(path: &Path) -> Option<PathBuf> {
140140
pub fn validate_entry_path(path: &Path) -> Result<PathBuf> {
141141
normalize_safe_path(path).ok_or_else(|| {
142142
FinalError::with_title("refusing to extract archive entry with unsafe path")
143-
.detail(format!("entry: {}", path.display()))
143+
.detail(format!("entry: {}", PathFmt(path)))
144144
.into()
145145
})
146146
}
@@ -154,11 +154,7 @@ pub fn validate_symlink_target(link_relpath: &Path, target: &Path) -> Result<()>
154154
if normalize_safe_path(&parent.join(target)).is_none() {
155155
return Err(
156156
FinalError::with_title("refusing to create symlink escaping extraction root")
157-
.detail(format!(
158-
"link: {} target: {}",
159-
link_relpath.display(),
160-
target.display()
161-
))
157+
.detail(format!("link: {} target: {}", PathFmt(link_relpath), PathFmt(target)))
162158
.into(),
163159
);
164160
}
@@ -169,7 +165,7 @@ pub fn validate_symlink_target(link_relpath: &Path, target: &Path) -> Result<()>
169165
/// Walks every existing prefix between root and dest and errors if any component is a symlink.
170166
pub fn validate_dest_inside_root(root: &Path, dest: &Path) -> Result<()> {
171167
let rel = dest.strip_prefix(root).map_err(|_| {
172-
FinalError::with_title("refusing to write outside extraction root").detail(format!("dest: {}", dest.display()))
168+
FinalError::with_title("refusing to write outside extraction root").detail(format!("dest: {}", PathFmt(dest)))
173169
})?;
174170
let mut probe = root.to_path_buf();
175171
for comp in rel.components() {
@@ -178,7 +174,7 @@ pub fn validate_dest_inside_root(root: &Path, dest: &Path) -> Result<()> {
178174
Ok(md) if md.file_type().is_symlink() => {
179175
return Err(
180176
FinalError::with_title("refusing to traverse on-disk symlink during extraction")
181-
.detail(format!("path: {}", probe.display()))
177+
.detail(format!("path: {}", PathFmt(&probe)))
182178
.into(),
183179
);
184180
}

0 commit comments

Comments
 (0)