Commit bb62ce62 authored by Alexis Janon's avatar Alexis Janon
Browse files

Check_path method for sysfscontrollerlist

Checks that a given path is authorized by first resolving any references
to parent directories, and then checking if the path starts with the
path to a controller. This basically creates an absolute path (but not
necessarily canonical!)
More precisely, starting from the root, on each element of the path:
- if it is a 'normal' element: push it at the end of the current
built path
- it if is a 'parent dir' (..): pop the last element of the current path
(i.e. go up a level)
After processing all components of a path, we get an absolute path.
This is then checked against the controllers paths.
For now, this algorithm seems to work pretty well on simple and more
complex examples. It ignores references to the root dir in the input
path (because that is the starting point of the algorithm). In
addition, it also ignores references to the current directory (.)
There is currently no symlink resolution, nor is there a check to ensure
the user is not trying to write in the root cgroup controller, or in the
controller of cuttr (if there is one). This will probably be added in
the future by parsing /proc/self/cgroup which contains the list of
cgroup the current process belongs to.
parent 4d243c43
use error::*; use error::*;
use result::CommandResult;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs; use std::fs;
use std::io; use std::io;
...@@ -58,6 +59,36 @@ impl SysFsControllerList { ...@@ -58,6 +59,36 @@ impl SysFsControllerList {
Error::from(io::Error::new(io::ErrorKind::NotFound, "key was not found")) Error::from(io::Error::new(io::ErrorKind::NotFound, "key was not found"))
}) })
} }
pub fn check_path(&self, path: &path::Path) -> Result<CommandResult> {
// inspired by https://github.com/vitiral/path_abs
let mut absolute_path = path::PathBuf::from("/");
for component in path.components() {
match component {
path::Component::ParentDir => if !absolute_path.pop() {
return Err(Error::from(io::Error::new(
io::ErrorKind::PermissionDenied,
format!("Could not access {:?}: permission denied", path),
)));
},
path::Component::Normal(_) => absolute_path.push(&component),
_ => (),
}
}
match self.is_authorized_path(&absolute_path) {
false => Err(Error::from(io::Error::new(
io::ErrorKind::PermissionDenied,
format!("Could not access {:?}: permission denied", path),
))),
true => Ok(CommandResult::from(())),
}
}
pub fn is_authorized_path(&self, path: &path::Path) -> bool {
self.values()
.map(|controller| &controller.path)
.any(|cpath| path.starts_with(cpath))
}
} }
impl From<HashMap<String, SysFsController>> for SysFsControllerList { impl From<HashMap<String, SysFsController>> for SysFsControllerList {
...@@ -165,6 +196,10 @@ mod tests { ...@@ -165,6 +196,10 @@ mod tests {
const NO_KEY_NAME: &str = "test_find_no_key"; const NO_KEY_NAME: &str = "test_find_no_key";
const DUPLICATE_NAME: &str = "test_find_duplicate"; const DUPLICATE_NAME: &str = "test_find_duplicate";
const KEY: &str = "test1.prop"; const KEY: &str = "test1.prop";
const INVALID_PATH_SIMPLE: &str = "../test_check_invalid";
const VALID_PATH_SIMPLE: &str = "test_check_valid";
const VALID_PATH_COMPLEX: &str =
"../fake_parent/../fake_grandparent/fake_parent/../../tmp/test_check_valid_complex/fake_child/..";
#[test] #[test]
fn test_controllers() { fn test_controllers() {
...@@ -282,4 +317,48 @@ mod tests { ...@@ -282,4 +317,48 @@ mod tests {
} }
} }
#[test]
fn test_invalid_simple() {
let mut map = HashMap::new();
map.insert(
"tmp".to_owned(),
SysFsController::new(path::PathBuf::from("/tmp/"), SysFsType::Cgroup),
);
let controllers = SysFsControllerList::from(map);
assert!(
controllers
.check_path(&path::Path::new(&format!("/tmp/{}", INVALID_PATH_SIMPLE)))
.is_err()
);
}
#[test]
fn test_valid_simple() {
let mut map = HashMap::new();
map.insert(
"tmp".to_owned(),
SysFsController::new(path::PathBuf::from("/tmp/"), SysFsType::Cgroup),
);
let controllers = SysFsControllerList::from(map);
assert!(
controllers
.check_path(&path::Path::new(&format!("/tmp/{}", VALID_PATH_SIMPLE)))
.is_ok()
);
}
#[test]
fn test_valid_complex() {
let mut map = HashMap::new();
map.insert(
"tmp".to_owned(),
SysFsController::new(path::PathBuf::from("/tmp/"), SysFsType::Cgroup),
);
let controllers = SysFsControllerList::from(map);
assert!(
controllers
.check_path(&path::Path::new(&format!("/tmp/{}", VALID_PATH_COMPLEX)))
.is_ok()
);
}
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment