Prevent bypassing safe guard in pathbuf segments

This commit is contained in:
Choongwoo Han 2017-01-14 04:07:55 +09:00
parent 41aecc3e7f
commit 432a6a1832
2 changed files with 36 additions and 5 deletions

View File

@ -290,13 +290,15 @@ impl<'a> FromSegments<'a> for PathBuf {
fn from_segments(segments: Segments<'a>) -> Result<PathBuf, Utf8Error> { fn from_segments(segments: Segments<'a>) -> Result<PathBuf, Utf8Error> {
let mut buf = PathBuf::new(); let mut buf = PathBuf::new();
for segment in segments { for segment in segments {
let decoded = URI::percent_decode(segment.as_bytes())?; let decoded_seg = URI::percent_decode(segment.as_bytes())?;
for decoded in Segments(&decoded_seg) {
if decoded == ".." { if decoded == ".." {
buf.pop(); buf.pop();
} else if !(decoded.starts_with('.') || decoded.starts_with('*')) { } else if !(decoded.starts_with('.') || decoded.starts_with('*')) {
buf.push(&*decoded) buf.push(&*decoded)
} }
} }
}
Ok(buf) Ok(buf)
} }

View File

@ -0,0 +1,29 @@
#![feature(plugin)]
#![plugin(rocket_codegen)]
extern crate rocket;
use std::path::PathBuf;
#[get("/<path..>")]
fn none(path: PathBuf) -> String {
path.to_string_lossy().into()
}
#[cfg(feature = "testing")]
mod tests {
use super::*;
use rocket::testing::MockRequest;
use rocket::http::Method::*;
#[test]
fn secure_segments() {
let rocket = rocket::ignite()
.mount("/", routes![none]);
let mut req = MockRequest::new(Get, "hello%2f..%2f..%2f..%2fetc%2fpasswd");
let mut response = req.dispatch_with(&rocket);
let body_str = response.body().and_then(|b| b.into_string());
assert_eq!(body_str, Some("etc/passwd".into()));
}
}