mirror of
https://github.com/marcoallegretti/WEFT_OS.git
synced 2026-03-26 17:03:09 +00:00
fix(file-portal): block dotdot path-traversal in is_allowed
Path::starts_with is component-aware but does not resolve .., so /allowed/../etc/passwd would pass the check. Add normalize_path() that lexically resolves . and .. components without touching the filesystem so the check works on non-existent paths too. Add regression test.
This commit is contained in:
parent
a18f5c7604
commit
8eace960c2
1 changed files with 26 additions and 1 deletions
|
|
@ -74,11 +74,27 @@ fn parse_allowed(args: &[String]) -> Vec<PathBuf> {
|
|||
allowed
|
||||
}
|
||||
|
||||
fn normalize_path(path: &Path) -> PathBuf {
|
||||
use std::path::Component;
|
||||
let mut out = PathBuf::new();
|
||||
for c in path.components() {
|
||||
match c {
|
||||
Component::ParentDir => {
|
||||
out.pop();
|
||||
}
|
||||
Component::CurDir => {}
|
||||
other => out.push(other),
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn is_allowed(path: &Path, allowed: &[PathBuf]) -> bool {
|
||||
if allowed.is_empty() {
|
||||
return false;
|
||||
}
|
||||
allowed.iter().any(|a| path.starts_with(a))
|
||||
let norm = normalize_path(path);
|
||||
allowed.iter().any(|a| norm.starts_with(a))
|
||||
}
|
||||
|
||||
fn handle_connection(stream: UnixStream, allowed: &[PathBuf]) {
|
||||
|
|
@ -191,6 +207,15 @@ mod tests {
|
|||
assert!(!is_allowed(Path::new("/etc/passwd"), &allowed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dotdot_traversal_blocked() {
|
||||
let allowed = vec![PathBuf::from("/tmp/weft-test-allowed")];
|
||||
assert!(!is_allowed(
|
||||
Path::new("/tmp/weft-test-allowed/../etc/passwd"),
|
||||
&allowed
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_allowlist_rejects_all() {
|
||||
assert!(!is_allowed(Path::new("/tmp/anything"), &[]));
|
||||
|
|
|
|||
Loading…
Reference in a new issue