mirror of
https://github.com/Horizontal42/summarum.git
synced 2026-11-11 01:02:01 +03:00
57 lines
1.8 KiB
Rust
57 lines
1.8 KiB
Rust
use std::path::{Path, PathBuf};
|
|
use std::fs;
|
|
|
|
fn canon_or_raw(p: &Path) -> PathBuf {
|
|
let mut normalized = PathBuf::new();
|
|
for component in p.components() {
|
|
match component {
|
|
std::path::Component::ParentDir => {
|
|
let can_pop = matches!(
|
|
normalized.components().next_back(),
|
|
Some(std::path::Component::Normal(_))
|
|
);
|
|
if can_pop {
|
|
normalized.pop();
|
|
} else if !normalized.has_root() {
|
|
normalized.push(component);
|
|
}
|
|
}
|
|
std::path::Component::CurDir => {}
|
|
_ => normalized.push(component),
|
|
}
|
|
}
|
|
normalized
|
|
}
|
|
|
|
fn secure_canonicalize(path: &Path) -> PathBuf {
|
|
let mut p = PathBuf::new();
|
|
for component in path.components() {
|
|
p.push(component);
|
|
if let Ok(canon) = fs::canonicalize(&p) {
|
|
p = canon;
|
|
}
|
|
}
|
|
canon_or_raw(&p)
|
|
}
|
|
|
|
fn main() {
|
|
let temp = std::env::temp_dir();
|
|
let real_allowed = temp.join("allowed_dir_abc");
|
|
fs::create_dir_all(&real_allowed).unwrap();
|
|
let secret = temp.join("secret_dir_xyz");
|
|
fs::create_dir_all(&secret).unwrap();
|
|
|
|
// Attacker makes a symlink from allowed/sym -> target
|
|
let symlink = real_allowed.join("sym");
|
|
#[cfg(unix)]
|
|
std::os::unix::fs::symlink(&secret, &symlink).unwrap_or(());
|
|
|
|
// Attacker tries to write to allowed/sym/../secret_dir_xyz/new_file
|
|
let malicious = symlink.join("..").join("secret_dir_xyz").join("new_file");
|
|
println!("malicious path: {:?}", malicious);
|
|
println!("secure_canonicalize: {:?}", secure_canonicalize(&malicious));
|
|
println!("canon_or_raw: {:?}", canon_or_raw(&malicious));
|
|
|
|
let allowed = real_allowed.clone();
|
|
println!("secure_canonicalize(allowed): {:?}", secure_canonicalize(&allowed));
|
|
}
|