catch the panic to avoid peer thread quit early (#2686)

* catch the panic to avoid peer thread quit before taking the chance to ban
* move catch wrapper logic down into the util crate
* log the panic info
* keep txhashset.rs untouched
* remove a warning
This commit is contained in:
Gary Yu 2019-03-24 04:39:50 +08:00 committed by Ignotus Peverell
parent 148256de6e
commit 32d939189d

View file

@ -15,6 +15,7 @@
use std::fs::{self, File}; use std::fs::{self, File};
/// Wrappers around the `zip-rs` library to compress and decompress zip archives. /// Wrappers around the `zip-rs` library to compress and decompress zip archives.
use std::io; use std::io;
use std::panic;
use std::path::Path; use std::path::Path;
use walkdir::WalkDir; use walkdir::WalkDir;
@ -64,58 +65,80 @@ pub fn compress(src_dir: &Path, dst_file: &File) -> ZipResult<()> {
/// Decompress a source file into the provided destination path. /// Decompress a source file into the provided destination path.
pub fn decompress<R, F>(src_file: R, dest: &Path, expected: F) -> ZipResult<usize> pub fn decompress<R, F>(src_file: R, dest: &Path, expected: F) -> ZipResult<usize>
where where
R: io::Read + io::Seek, R: io::Read + io::Seek + panic::UnwindSafe,
F: Fn(&Path) -> bool, F: Fn(&Path) -> bool + panic::UnwindSafe,
{ {
let mut decompressed = 0; let mut decompressed = 0;
let mut archive = zip_rs::ZipArchive::new(src_file)?;
for i in 0..archive.len() { // catch the panic to avoid the thread quit
let mut file = archive.by_index(i)?; panic::set_hook(Box::new(|panic_info| {
let san_name = file.sanitized_name(); error!(
if san_name.to_str().unwrap_or("").replace("\\", "/") != file.name().replace("\\", "/") "panic occurred: {:?}",
|| !expected(&san_name) panic_info.payload().downcast_ref::<&str>().unwrap()
{ );
info!( }));
"ignoring a suspicious file: {}, got {:?}", let result = panic::catch_unwind(move || {
file.name(), let mut archive = zip_rs::ZipArchive::new(src_file)?;
san_name.to_str()
);
continue;
}
let file_path = dest.join(san_name);
if (&*file.name()).ends_with('/') { for i in 0..archive.len() {
fs::create_dir_all(&file_path)?; let mut file = archive.by_index(i)?;
} else { let san_name = file.sanitized_name();
if let Some(p) = file_path.parent() { if san_name.to_str().unwrap_or("").replace("\\", "/") != file.name().replace("\\", "/")
if !p.exists() { || !expected(&san_name)
fs::create_dir_all(&p)?; {
info!(
"ignoring a suspicious file: {}, got {:?}",
file.name(),
san_name.to_str()
);
continue;
}
let file_path = dest.join(san_name);
if (&*file.name()).ends_with('/') {
fs::create_dir_all(&file_path)?;
} else {
if let Some(p) = file_path.parent() {
if !p.exists() {
fs::create_dir_all(&p)?;
}
}
let res = fs::File::create(&file_path);
let mut outfile = match res {
Err(e) => {
error!("{:?}", e);
return Err(zip::result::ZipError::Io(e));
}
Ok(r) => r,
};
io::copy(&mut file, &mut outfile)?;
decompressed += 1;
}
// Get and Set permissions
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
if let Some(mode) = file.unix_mode() {
fs::set_permissions(
&file_path.to_str().unwrap(),
PermissionsExt::from_mode(mode),
)?;
} }
} }
let res = fs::File::create(&file_path);
let mut outfile = match res {
Err(e) => {
error!("{:?}", e);
return Err(zip::result::ZipError::Io(e));
}
Ok(r) => r,
};
io::copy(&mut file, &mut outfile)?;
decompressed += 1;
} }
Ok(decompressed)
// Get and Set permissions });
#[cfg(unix)] match result {
{ Ok(res) => match res {
use std::os::unix::fs::PermissionsExt; Err(e) => Err(e.into()),
if let Some(mode) = file.unix_mode() { Ok(_) => res,
fs::set_permissions( },
&file_path.to_str().unwrap(), Err(_) => {
PermissionsExt::from_mode(mode), error!("panic occurred on zip::decompress!");
)?; Err(zip::result::ZipError::InvalidArchive(
} "panic occurred on zip::decompress",
))
} }
} }
Ok(decompressed)
} }