Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

o Separate sanitizing of config subdirectories.

o On startup: warn about things that are not really qualifying.
  • Loading branch information...
commit a90d922418c8fcfcadac9260e2cd76710be5cbe9 1 parent c113afd
Henner Zeller authored
Showing with 81 additions and 51 deletions.
  1. +66 −40 folve-filesystem.cc
  2. +14 −0 folve-filesystem.h
  3. +1 −11 folve-main.cc
106 folve-filesystem.cc
View
@@ -640,6 +640,14 @@ void FolveFilesystem::Close(const char *fs_path, const FileHandler *handler) {
open_file_cache_.Unpin(cache_key);
}
+static bool IsDirectory(const std::string &path) {
+ if (path.empty()) return false;
+ struct stat st;
+ if (stat(path.c_str(), &st) != 0)
+ return false;
+ return (st.st_mode & S_IFMT) == S_IFDIR;
+}
+
bool FolveFilesystem::ListDirectory(const std::string &fs_dir,
const std::string &suffix,
std::set<std::string> *files) {
@@ -656,31 +664,40 @@ bool FolveFilesystem::ListDirectory(const std::string &fs_dir,
return true;
}
+bool FolveFilesystem::SanitizeConfigSubdir(std::string *subdir_path) const {
+ if (base_config_dir_.length() + 1 + subdir_path->length() > PATH_MAX)
+ return false; // uh, someone wants to buffer overflow us ?
+ const std::string to_verify_path = base_config_dir_ + "/" + *subdir_path;
+ char all_path[PATH_MAX];
+ // This will as well eat symbolic links that break out, though one could
+ // argue that that would be sane. We could think of some light
+ // canonicalization that only removes ./ and ../
+ const char *verified = realpath(to_verify_path.c_str(), all_path);
+ if (verified == NULL) { // bogus directory.
+ return false;
+ }
+ if (strncmp(verified, base_config_dir_.c_str(),
+ base_config_dir_.length()) != 0) {
+ // Attempt to break out with ../-tricks.
+ return false;
+ }
+ if (!IsDirectory(verified))
+ return false;
+
+ // Derive from sanitized dir. So someone can write lowpass/../highpass
+ // or '.' for empty filter. Or ./highpass. And all work.
+ *subdir_path = ((strlen(verified) == base_config_dir_.length())
+ ? "" // chose subdir '.'
+ : verified + base_config_dir_.length() + 1 /*slash*/);
+ return true;
+}
+
bool FolveFilesystem::SwitchCurrentConfigDir(const std::string &subdir_in) {
std::string subdir = subdir_in;
- if (!subdir.empty()) {
- std::string to_verify_path = base_config_dir_ + "/" + subdir;
- if (to_verify_path.length() > PATH_MAX)
- return false; // uh, someone wants to buffer overflow us ?
- char all_path[PATH_MAX];
- const char *verified = realpath(to_verify_path.c_str(), all_path);
- if (verified == NULL) { // bogus directory.
- syslog(LOG_INFO, "Filter config switch attempt to '%s': %s",
- subdir.c_str(), strerror(errno));
- return false;
- }
- if (strncmp(verified, base_config_dir_.c_str(),
- base_config_dir_.length()) != 0) {
- // Attempt to break out with ../-tricks.
- syslog(LOG_INFO, "Filter config switch: Someone tries something nasty "
- "changing filter to '%s'. Ha, in your face!", subdir.c_str());
- return false;
- }
- // Derive from sanitized dir. So someone can write lowpass/../highpass
- // or '.' for empty filter. Or ./highpass. And all work.
- subdir = ((strlen(verified) == base_config_dir_.length())
- ? "" // chose subdir '.'
- : verified + base_config_dir_.length() + 1 /*slash*/);
+ if (!subdir.empty() && !SanitizeConfigSubdir(&subdir)) {
+ syslog(LOG_INFO, "Invalid config switch attempt to '%s'",
+ subdir_in.c_str());
+ return false;
}
if (subdir != current_config_subdir_) {
current_config_subdir_ = subdir;
@@ -694,14 +711,6 @@ bool FolveFilesystem::SwitchCurrentConfigDir(const std::string &subdir_in) {
return false;
}
-static bool IsDirectory(const std::string &path) {
- if (path.empty()) return false;
- struct stat st;
- if (stat(path.c_str(), &st) != 0)
- return false;
- return (st.st_mode & S_IFMT) == S_IFDIR;
-}
-
bool FolveFilesystem::CheckInitialized() {
if (underlying_dir().empty()) {
fprintf(stderr, "Don't know the underlying directory to read from.\n");
@@ -720,28 +729,45 @@ bool FolveFilesystem::CheckInitialized() {
return false;
}
- std::set<std::string> cfg_dirs = GetAvailableConfigDirs();
- if (cfg_dirs.size() > 1) {
+ return true;
+}
+
+void FolveFilesystem::SetupInitialConfig() {
+ std::set<std::string> available_dirs = ListConfigDirs(true);
+ // Some sanity checks.
+ if (available_dirs.size() == 1) {
+ syslog(LOG_NOTICE, "No filter configuration directories given. "
+ "Any files will be just passed through verbatim.");
+ }
+ if (available_dirs.size() > 1) {
// By default, lets set the index to the first filter the user provided.
- SwitchCurrentConfigDir(*++cfg_dirs.begin());
+ SwitchCurrentConfigDir(*++available_dirs.begin());
}
- return true;
}
const std::set<std::string> FolveFilesystem::GetAvailableConfigDirs() const {
+ return ListConfigDirs(false);
+}
+
+const std::set<std::string> FolveFilesystem::ListConfigDirs(bool warn_invalid)
+ const {
std::set<std::string> result;
result.insert(""); // empty directory: pass-through.
DIR *dp = opendir(base_config_dir_.c_str());
if (dp == NULL) return result;
struct dirent *dent;
while ((dent = readdir(dp)) != NULL) {
- if (dent->d_name == std::string(".") || dent->d_name == std::string(".."))
+ std::string subdir = dent->d_name;
+ if (subdir == "." || subdir == "..")
continue;
- std::string full_path = base_config_dir_ + "/" + dent->d_name;
- struct stat st;
- if (stat(full_path.c_str(), &st) != 0 || !S_ISDIR(st.st_mode))
+ if (!SanitizeConfigSubdir(&subdir)) {
+ if (warn_invalid) {
+ syslog(LOG_INFO, "Note: '%s' ignored in config directory; not a "
+ "directory or pointing outside base directory.", dent->d_name);
+ }
continue;
- result.insert(dent->d_name);
+ }
+ result.insert(subdir);
}
closedir(dp);
return result;
14 folve-filesystem.h
View
@@ -62,6 +62,9 @@ class FolveFilesystem {
// to stderr.
bool CheckInitialized();
+ // After startup: choose the initial configuation.
+ void SetupInitialConfig();
+
// Create a new filter given the filesystem path and the underlying
// path.
// Returns NULL, if it cannot be created.
@@ -100,6 +103,17 @@ class FolveFilesystem {
const char *fs_path,
const std::string &underlying_file);
+ // Sanitize path to configuration subdirectory. Checks if someone tries
+ // to break out of the given base directory.
+ // Return if this is a sane directory.
+ // Passes the sanitized directory in the parameter.
+ bool SanitizeConfigSubdir(std::string *subdir_path) const;
+
+ // List available config directories; if "warn_invalid" is true,
+ // non-directories or symbolic links breaking out of the directory are
+ // reported.
+ const std::set<std::string> ListConfigDirs(bool warn_invalid) const;
+
std::string underlying_dir_;
std::string base_config_dir_;
std::string current_config_subdir_;
12 folve-main.cc
View
@@ -174,17 +174,7 @@ static void *folve_init(struct fuse_conn_info *conn) {
}
}
- // Some sanity checks.
- std::set<std::string> available_dirs = folve_rt.fs->GetAvailableConfigDirs();
- if (available_dirs.empty()) {
- syslog(LOG_NOTICE, "No filter configuration directories given. "
- "Any files will be just passed through verbatim.");
- }
- if (available_dirs.size() > 2 && folve_rt.status_port < 0) {
- syslog(LOG_WARNING, "Multiple filter configurations given, but no HTTP "
- "status port. You only can switch filters via the HTTP interface; "
- "add -p <port>");
- }
+ folve_rt.fs->SetupInitialConfig();
return NULL;
}
Please sign in to comment.
Something went wrong with that request. Please try again.