diff options
Diffstat (limited to 'src/main/cpp')
-rw-r--r-- | src/main/cpp/blaze.cc | 83 | ||||
-rw-r--r-- | src/main/cpp/blaze_util_platform.h | 5 | ||||
-rw-r--r-- | src/main/cpp/blaze_util_posix.cc | 43 | ||||
-rw-r--r-- | src/main/cpp/blaze_util_windows.cc | 50 | ||||
-rw-r--r-- | src/main/cpp/util/file_platform.h | 9 | ||||
-rw-r--r-- | src/main/cpp/util/file_posix.cc | 14 | ||||
-rw-r--r-- | src/main/cpp/util/file_windows.cc | 10 |
7 files changed, 153 insertions, 61 deletions
diff --git a/src/main/cpp/blaze.cc b/src/main/cpp/blaze.cc index d95ba05b06..39d1165c5e 100644 --- a/src/main/cpp/blaze.cc +++ b/src/main/cpp/blaze.cc @@ -40,8 +40,6 @@ #include <sys/resource.h> #include <sys/select.h> #include <sys/socket.h> -#include <sys/stat.h> -#include <sys/statvfs.h> #include <sys/time.h> #include <sys/un.h> #include <time.h> @@ -945,8 +943,7 @@ static void ActuallyExtractData(const string &argv0, // Populates globals->extracted_binaries with their extracted locations. static void ExtractData(const string &self_path) { // If the install dir doesn't exist, create it, if it does, we know it's good. - struct stat buf; - if (stat(globals->options->install_base.c_str(), &buf) == -1) { + if (!blaze_util::PathExists(globals->options->install_base)) { uint64_t st = GetMillisecondsMonotonic(); // Work in a temp dir to avoid races. string tmp_install = globals->options->install_base + ".tmp." + @@ -967,7 +964,7 @@ static void ExtractData(const string &self_path) { tmp_install.c_str()); } } else { - if (!S_ISDIR(buf.st_mode)) { + if (!blaze_util::IsDirectory(globals->options->install_base)) { die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "Error: Install base directory '%s' could not be created. " "It exists but is not a directory.", @@ -981,19 +978,28 @@ static void ExtractData(const string &self_path) { for (const auto& it : globals->extracted_binaries) { string path = blaze_util::JoinPath(real_install_dir, it); // Check that the file exists and is readable. - if (stat(path.c_str(), &buf) == -1) { + if (!blaze_util::CanAccess(path, true, false, false)) { die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "Error: corrupt installation: file '%s' missing." " Please remove '%s' and try again.", path.c_str(), globals->options->install_base.c_str()); } - // Check that the timestamp is in the future. A past timestamp would indicate - // that the file has been tampered with. See ActuallyExtractData(). - if (!S_ISDIR(buf.st_mode) && buf.st_mtime <= time_now) { - die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, - "Error: corrupt installation: file '%s' " - "modified. Please remove '%s' and try again.", - path.c_str(), globals->options->install_base.c_str()); + // Check that the timestamp is in the future. A past timestamp would + // indicate that the file has been tampered with. + // See ActuallyExtractData(). + if (!blaze_util::IsDirectory(path)) { + time_t mtime = blaze_util::GetMtimeMillisec(path); + if (mtime == -1) { + die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, + "Error: could not retrieve mtime of file '%s'. " + "Please remove '%s' and try again.", + path.c_str(), globals->options->install_base.c_str()); + } else if (mtime <= time_now) { + die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, + "Error: corrupt installation: file '%s' " + "modified. Please remove '%s' and try again.", + path.c_str(), globals->options->install_base.c_str()); + } } } } @@ -1292,16 +1298,15 @@ static void ComputeBaseDirectories(const string &self_path) { globals->options->output_user_root, globals->workspace); } - struct stat buf; const char *output_base = globals->options->output_base.c_str(); - if (stat(output_base, &buf) == -1) { + if (!blaze_util::PathExists(globals->options->output_base)) { if (MakeDirectories(globals->options->output_base, 0777) == -1) { pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "Output base directory '%s' could not be created", output_base); } } else { - if (!S_ISDIR(buf.st_mode)) { + if (!blaze_util::IsDirectory(globals->options->output_base)) { die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "Error: Output base directory '%s' could not be created. " "It exists but is not a directory.", @@ -1393,50 +1398,6 @@ static void CheckBinaryPath(const string& argv0) { } } -// Create the user's directory where we keep state, installations etc. -// Typically, this happens inside a temp directory, so we have to be -// careful about symlink attacks. -static void CreateSecureOutputRoot() { - const char* root = globals->options->output_user_root.c_str(); - struct stat fileinfo = {}; - - if (MakeDirectories(root, 0755) == -1) { - pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "mkdir('%s')", root); - } - - // The path already exists. - // Check ownership and mode, and verify that it is a directory. - - if (lstat(root, &fileinfo) < 0) { - pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "lstat('%s')", root); - } - - if (fileinfo.st_uid != geteuid()) { - die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "'%s' is not owned by me", - root); - } - - if ((fileinfo.st_mode & 022) != 0) { - int new_mode = fileinfo.st_mode & (~022); - if (chmod(root, new_mode) < 0) { - die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, - "'%s' has mode %o, chmod to %o failed", root, - fileinfo.st_mode & 07777, new_mode); - } - } - - if (stat(root, &fileinfo) < 0) { - pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "stat('%s')", root); - } - - if (!S_ISDIR(fileinfo.st_mode)) { - die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "'%s' is not a directory", - root); - } - - ExcludePathFromBackup(root); -} - // TODO(bazel-team): Execute the server as a child process and write its exit // code to a file. In case the server becomes unresonsive or terminates // unexpectedly (in a way that isn't already handled), we can observe the file, @@ -1453,7 +1414,7 @@ int Main(int argc, const char *argv[], OptionProcessor *option_processor) { debug_log("Debug logging active"); CheckEnvironment(); - CreateSecureOutputRoot(); + blaze::CreateSecureOutputRoot(globals->options->output_user_root); const string self_path = GetSelfPath(); ComputeBaseDirectories(self_path); diff --git a/src/main/cpp/blaze_util_platform.h b/src/main/cpp/blaze_util_platform.h index 40b000bcc9..6a818e5e0c 100644 --- a/src/main/cpp/blaze_util_platform.h +++ b/src/main/cpp/blaze_util_platform.h @@ -141,6 +141,11 @@ void ExcludePathFromBackup(const std::string& path); std::string GetHashedBaseDir(const std::string& root, const std::string& hashable); +// Create a safe installation directory where we keep state, installations etc. +// This method ensures that the directory is created, is owned by the current +// user, and not accessible to anyone else. +void CreateSecureOutputRoot(const std::string& path); + } // namespace blaze #endif // BAZEL_SRC_MAIN_CPP_BLAZE_UTIL_PLATFORM_H_ diff --git a/src/main/cpp/blaze_util_posix.cc b/src/main/cpp/blaze_util_posix.cc index b0cb90d3d8..4c9ce44159 100644 --- a/src/main/cpp/blaze_util_posix.cc +++ b/src/main/cpp/blaze_util_posix.cc @@ -17,6 +17,7 @@ #include <limits.h> // PATH_MAX #include <signal.h> #include <stdio.h> +#include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> @@ -31,6 +32,7 @@ namespace blaze { +using blaze_util::die; using blaze_util::pdie; using std::string; @@ -226,4 +228,45 @@ string GetHashedBaseDir(const string& root, const string& hashable) { return root + "/" + digest.String(); } +void CreateSecureOutputRoot(const string& path) { + const char* root = path.c_str(); + struct stat fileinfo = {}; + + if (MakeDirectories(root, 0755) == -1) { + pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "mkdir('%s')", root); + } + + // The path already exists. + // Check ownership and mode, and verify that it is a directory. + + if (lstat(root, &fileinfo) < 0) { + pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "lstat('%s')", root); + } + + if (fileinfo.st_uid != geteuid()) { + die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "'%s' is not owned by me", + root); + } + + if ((fileinfo.st_mode & 022) != 0) { + int new_mode = fileinfo.st_mode & (~022); + if (chmod(root, new_mode) < 0) { + die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, + "'%s' has mode %o, chmod to %o failed", root, + fileinfo.st_mode & 07777, new_mode); + } + } + + if (stat(root, &fileinfo) < 0) { + pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "stat('%s')", root); + } + + if (!S_ISDIR(fileinfo.st_mode)) { + die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "'%s' is not a directory", + root); + } + + ExcludePathFromBackup(root); +} + } // namespace blaze. diff --git a/src/main/cpp/blaze_util_windows.cc b/src/main/cpp/blaze_util_windows.cc index 87fe5facbe..737c02a30c 100644 --- a/src/main/cpp/blaze_util_windows.cc +++ b/src/main/cpp/blaze_util_windows.cc @@ -19,6 +19,7 @@ #ifndef COMPILER_MSVC #include <sys/cygwin.h> #include <sys/socket.h> +#include <sys/stat.h> #include <sys/statfs.h> #include <unistd.h> #endif // COMPILER_MSVC @@ -851,6 +852,55 @@ string GetHashedBaseDir(const string& root, const string& hashable) { return root + "/" + string(coded_name); } +void CreateSecureOutputRoot(const string& path) { + // TODO(bazel-team) 2016-11-26: implement this function without using the + // POSIX API, then get rid of the POSIX version, which is a copy of the + // blaze_util_posix version of the same method. + +#ifdef COMPILER_MSVC + pdie(255, "blaze::CreateSecureOutputRoot is not implemented on Windows"); +#else // not COMPILER_MSVC + const char* root = path.c_str(); + struct stat fileinfo = {}; + + if (MakeDirectories(root, 0755) == -1) { + pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "mkdir('%s')", root); + } + + // The path already exists. + // Check ownership and mode, and verify that it is a directory. + + if (lstat(root, &fileinfo) < 0) { + pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "lstat('%s')", root); + } + + if (fileinfo.st_uid != geteuid()) { + die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "'%s' is not owned by me", + root); + } + + if ((fileinfo.st_mode & 022) != 0) { + int new_mode = fileinfo.st_mode & (~022); + if (chmod(root, new_mode) < 0) { + die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, + "'%s' has mode %o, chmod to %o failed", root, + fileinfo.st_mode & 07777, new_mode); + } + } + + if (stat(root, &fileinfo) < 0) { + pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "stat('%s')", root); + } + + if (!S_ISDIR(fileinfo.st_mode)) { + die(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "'%s' is not a directory", + root); + } + + ExcludePathFromBackup(root); +#endif // COMPILER_MSVC +} + LARGE_INTEGER WindowsClock::GetFrequency() { LARGE_INTEGER result; if (!QueryPerformanceFrequency(&result)) { diff --git a/src/main/cpp/util/file_platform.h b/src/main/cpp/util/file_platform.h index c43be7932a..fd725518e0 100644 --- a/src/main/cpp/util/file_platform.h +++ b/src/main/cpp/util/file_platform.h @@ -15,6 +15,8 @@ #ifndef BAZEL_SRC_MAIN_CPP_UTIL_FILE_PLATFORM_H_ #define BAZEL_SRC_MAIN_CPP_UTIL_FILE_PLATFORM_H_ +#include <stdint.h> + #include <string> namespace blaze_util { @@ -34,6 +36,13 @@ bool PathExists(const std::string& path); // openable. bool CanAccess(const std::string& path, bool read, bool write, bool exec); +// Returns true if `path` refers to a directory or a symlink/junction to one. +bool IsDirectory(const std::string& path); + +// Returns the last modification time of `path` in milliseconds since the Epoch. +// Returns -1 upon failure. +time_t GetMtimeMillisec(const std::string& path); + // Returns the current working directory. std::string GetCwd(); diff --git a/src/main/cpp/util/file_posix.cc b/src/main/cpp/util/file_posix.cc index 32f86da7a4..7691ee976a 100644 --- a/src/main/cpp/util/file_posix.cc +++ b/src/main/cpp/util/file_posix.cc @@ -73,6 +73,20 @@ bool CanAccess(const string& path, bool read, bool write, bool exec) { return access(path.c_str(), mode) == 0; } +bool IsDirectory(const string& path) { + struct stat buf; + return stat(path.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode); +} + +time_t GetMtimeMillisec(const string& path) { + struct stat buf; + if (stat(path.c_str(), &buf)) { + return -1; + } else { + return buf.st_mtime; + } +} + string GetCwd() { char cwdbuf[PATH_MAX]; if (getcwd(cwdbuf, sizeof cwdbuf) == NULL) { diff --git a/src/main/cpp/util/file_windows.cc b/src/main/cpp/util/file_windows.cc index c9df3af3c9..eb0efd271a 100644 --- a/src/main/cpp/util/file_windows.cc +++ b/src/main/cpp/util/file_windows.cc @@ -33,6 +33,16 @@ bool CanAccess(const string& path, bool read, bool write, bool exec) { pdie(255, "blaze_util::CanAccess is not implemented on Windows"); } +bool IsDirectory(const string& path) { + // TODO(bazel-team): implement this. + pdie(255, "blaze_util::IsDirectory is not implemented on Windows"); +} + +time_t GetMtimeMillisec(const string& path) { + // TODO(bazel-team): implement this. + pdie(255, "blaze_util::GetMtimeMillisec is not implemented on Windows"); +} + string GetCwd() { // TODO(bazel-team): implement this. pdie(255, "blaze_util::GetCwd is not implemented on Windows"); |