By default, forbid special files.

This commit is contained in:
Nick Mathewson 2022-04-18 17:14:30 -04:00
parent 2042d0934b
commit d574afa230
2 changed files with 40 additions and 17 deletions

View File

@ -1,6 +1,9 @@
//! Implementation logic for `fs-mistrust`.
use std::{fs::Metadata, path::Path};
use std::{
fs::{FileType, Metadata},
path::Path,
};
#[cfg(target_family = "unix")]
use std::os::unix::prelude::MetadataExt;
@ -88,18 +91,11 @@ impl<'a> super::Verifier<'a> {
self.enforce_type
} else {
// We make sure that everything at a higher level is a directory.
Some(Type::Dir)
Type::Dir
};
let have_type = meta.file_type();
match want_type {
Some(Type::Dir) if !have_type.is_dir() => {
errors.push(Error::BadType(path.into()));
}
Some(Type::File) if !have_type.is_file() => {
errors.push(Error::BadType(path.into()));
}
_ => {}
if !want_type.matches(meta.file_type()) {
errors.push(Error::BadType(path.into()));
}
// If we are on unix, make sure that the owner and permissions are
@ -152,3 +148,16 @@ impl<'a> super::Verifier<'a> {
errors
}
}
impl super::Type {
/// Return true if this required type is matched by a given `FileType`
/// object.
fn matches(&self, have_type: FileType) -> bool {
match self {
Type::Dir => have_type.is_dir(),
Type::File => have_type.is_file(),
Type::DirOrFile => have_type.is_dir() || have_type.is_file(),
Type::Anything => true,
}
}
}

View File

@ -89,7 +89,6 @@
// - Test the absolute heck out of it.
// POSSIBLY TODO:
// - Forbid special files even when not checking file type?
// - Cache information across runs.
// - Add a way to recursively check the contents of a directory.
// - Define a hard-to-misuse API for opening files, making secret directories, etc etc.
@ -205,7 +204,7 @@ pub struct Verifier<'a> {
/// If the user called [`Verifier::require_file`] or
/// [`Verifier::require_directory`], which did they call?
enforce_type: Option<Type>,
enforce_type: Type,
}
/// A type of object that we have been told to require.
@ -215,6 +214,10 @@ enum Type {
Dir,
/// A regular file.
File,
/// A directory or a regular file.
DirOrFile,
/// Absolutely anything at all.
Anything,
}
impl Mistrust {
@ -279,7 +282,7 @@ impl Mistrust {
mistrust: self,
readable_okay: false,
collect_multiple_errors: false,
enforce_type: None,
enforce_type: Type::DirOrFile,
}
}
@ -310,14 +313,25 @@ impl<'a> Verifier<'a> {
/// Configure this `Verifier` to require that all paths it checks be
/// files (not directories).
pub fn require_file(mut self) -> Self {
self.enforce_type = Some(Type::File);
self.enforce_type = Type::File;
self
}
/// Configure this `Verifier` to require that all paths it checks be
/// directories.
pub fn require_directory(mut self) -> Self {
self.enforce_type = Some(Type::Dir);
self.enforce_type = Type::Dir;
self
}
/// Configure this `Verifier` to allow the paths that it checks to be
/// filesystem objects of any type.
///
/// By default, the final path (after resolving all links) must be a
/// directory or a regular file, not (for example) a block device or a named
/// pipe.
pub fn permit_all_object_types(mut self) -> Self {
self.enforce_type = Type::Anything;
self
}
@ -397,7 +411,7 @@ impl<'a> Verifier<'a> {
/// * after creating the directory, we found that it had a permissions or
/// ownership problem.
pub fn make_directory<P: AsRef<Path>>(mut self, path: P) -> Result<()> {
self.enforce_type = Some(Type::Dir);
self.enforce_type = Type::Dir;
let path = path.as_ref();
match self.clone().check(path) {