diff --git a/components/net/chrome_loader.rs b/components/net/chrome_loader.rs index 31a52913929..544e9a64f4a 100644 --- a/components/net/chrome_loader.rs +++ b/components/net/chrome_loader.rs @@ -6,6 +6,7 @@ use file_loader; use mime_classifier::MIMEClassifier; use net_traits::{LoadConsumer, LoadData, NetworkError}; use resource_thread::{CancellationListener, send_error}; +use std::fs::canonicalize; use std::sync::Arc; use url::Url; use url::percent_encoding::percent_decode; @@ -16,16 +17,22 @@ pub fn resolve_chrome_url(url: &Url) -> Result { if url.host_str() != Some("resources") { return Err(()) } - let resources = resources_dir_path(); + let resources = canonicalize(resources_dir_path()) + .expect("Error canonicalizing path to the resources directory"); let mut path = resources.clone(); for segment in url.path_segments().unwrap() { - path.push(&*try!(percent_decode(segment.as_bytes()).decode_utf8().map_err(|_| ()))) + match percent_decode(segment.as_bytes()).decode_utf8() { + // Check ".." to prevent access to files outside of the resources directory. + Ok(segment) => path.push(&*segment), + _ => return Err(()) + } } - // Don't allow chrome URLs access to files outside of the resources directory. - if !(path.starts_with(resources) && path.exists()) { - return Err(()); + match canonicalize(path) { + Ok(ref path) if path.starts_with(&resources) && path.exists() => { + Ok(Url::from_file_path(path).unwrap()) + } + _ => Err(()) } - return Ok(Url::from_file_path(&*path).unwrap()); } pub fn factory(mut load_data: LoadData, diff --git a/tests/unit/net/chrome_loader.rs b/tests/unit/net/chrome_loader.rs index 2b335651272..5008fe67fc8 100644 --- a/tests/unit/net/chrome_loader.rs +++ b/tests/unit/net/chrome_loader.rs @@ -5,48 +5,40 @@ use net::chrome_loader::resolve_chrome_url; use url::Url; -#[test] -fn test_relative() { - let url = Url::parse("chrome://resources/../something").unwrap(); - assert!(resolve_chrome_url(&url).is_err()); +fn c(s: &str) -> Result { + resolve_chrome_url(&Url::parse(s).unwrap()) } #[test] -fn test_relative_2() { - let url = Url::parse("chrome://resources/subdir/../something").unwrap(); - assert!(resolve_chrome_url(&url).is_err()); -} +fn test_resolve_chrome_url() { + assert_eq!(c("chrome://resources/nonexistent.jpg"), Err(())); + assert_eq!(c("chrome://not-resources/badcert.jpg"), Err(())); + assert_eq!(c("chrome://resources/badcert.jpg").unwrap().scheme(), "file"); + assert_eq!(c("chrome://resources/subdir/../badcert.jpg").unwrap().scheme(), "file"); + assert_eq!(c("chrome://resources/subdir/../../badcert.jpg").unwrap().scheme(), "file"); + assert_eq!(c("chrome://resources/../badcert.jpg").unwrap().scheme(), "file"); + assert_eq!(c("chrome://resources/../README.md"), Err(())); + assert_eq!(c("chrome://resources/%2e%2e/README.md"), Err(())); -#[test] -#[cfg(not(target_os = "windows"))] -fn test_absolute() { - let url = Url::parse("chrome://resources/etc/passwd").unwrap(); - assert!(resolve_chrome_url(&url).is_err()); -} + assert_eq!(c("chrome://resources/etc/passwd"), Err(())); + assert_eq!(c("chrome://resources//etc/passwd"), Err(())); + assert_eq!(c("chrome://resources/%2Fetc%2Fpasswd"), Err(())); -#[test] -#[cfg(target_os = "windows")] -fn test_absolute_2() { - let url = Url::parse("chrome://resources/C:\\Windows").unwrap(); - assert!(resolve_chrome_url(&url).is_err()); -} + assert_eq!(c("chrome://resources/C:/Windows/notepad.exe"), Err(())); + assert_eq!(c("chrome://resources/C:\\Windows\\notepad.exe"), Err(())); -#[test] -#[cfg(target_os = "windows")] -fn test_absolute_3() { - let url = Url::parse("chrome://resources/\\\\server/C$").unwrap(); - assert!(resolve_chrome_url(&url).is_err()); -} + assert_eq!(c("chrome://resources/localhost/C:/Windows/notepad.exe"), Err(())); + assert_eq!(c("chrome://resources//localhost/C:/Windows/notepad.exe"), Err(())); + assert_eq!(c("chrome://resources///localhost/C:/Windows/notepad.exe"), Err(())); + assert_eq!(c("chrome://resources/\\\\localhost\\C:\\Windows\\notepad.exe"), Err(())); -#[test] -fn test_valid() { - let url = Url::parse("chrome://resources/badcert.jpg").unwrap(); - let resolved = resolve_chrome_url(&url).unwrap(); - assert_eq!(resolved.scheme(), "file"); -} + assert_eq!(c("chrome://resources/%3F/C:/Windows/notepad.exe"), Err(())); + assert_eq!(c("chrome://resources//%3F/C:/Windows/notepad.exe"), Err(())); + assert_eq!(c("chrome://resources///%3F/C:/Windows/notepad.exe"), Err(())); + assert_eq!(c("chrome://resources/\\\\%3F\\C:\\Windows\\notepad.exe"), Err(())); -#[test] -fn test_incorrect_host() { - let url = Url::parse("chrome://not-resources/badcert.jpg").unwrap(); - assert!(resolve_chrome_url(&url).is_err()); + assert_eq!(c("chrome://resources/%3F/UNC/localhost/C:/Windows/notepad.exe"), Err(())); + assert_eq!(c("chrome://resources//%3F/UNC/localhost/C:/Windows/notepad.exe"), Err(())); + assert_eq!(c("chrome://resources///%3F/UNC/localhost/C:/Windows/notepad.exe"), Err(())); + assert_eq!(c("chrome://resources/\\\\%3F\\UNC\\localhost\\C:\\Windows\\notepad.exe"), Err(())); }