1*1a96fba6SXin Li // Copyright 2019 The Chromium OS Authors. All rights reserved. 2*1a96fba6SXin Li // Use of this source code is governed by a BSD-style license that can be 3*1a96fba6SXin Li // found in the LICENSE file. 4*1a96fba6SXin Li 5*1a96fba6SXin Li // This provides an API for performing typical filesystem related tasks while 6*1a96fba6SXin Li // guaranteeing certain security properties are maintained. Specifically, checks 7*1a96fba6SXin Li // are performed to disallow symbolic links, and exotic file objects. The goal 8*1a96fba6SXin Li // behind these checks is to thwart attacks that rely on confusing system 9*1a96fba6SXin Li // services to perform unintended file operations like ownership changes or 10*1a96fba6SXin Li // copy-as-root attack primitives. To accomplish this these operations are 11*1a96fba6SXin Li // written to avoid susceptibility to TOCTOU (time-of-check-time-of-use) 12*1a96fba6SXin Li // attacks. 13*1a96fba6SXin Li 14*1a96fba6SXin Li // To use this API start with the root path and work from there. For example: 15*1a96fba6SXin Li // SafeFD fd(SafeDirFD::Root().MakeFile(PATH).first); 16*1a96fba6SXin Li // if (!fd.is_valid()) { 17*1a96fba6SXin Li // LOG(ERROR) << "Failed to open " << PATH; 18*1a96fba6SXin Li // return false; 19*1a96fba6SXin Li // } 20*1a96fba6SXin Li // if (fd.WriteString(CONTENTS) != SafeFD::kNoError) { 21*1a96fba6SXin Li // LOG(ERROR) << "Failed to write to " << PATH; 22*1a96fba6SXin Li // return false; 23*1a96fba6SXin Li // } 24*1a96fba6SXin Li // auto read_result = fd.ReadString(); 25*1a96fba6SXin Li // if (!read_result.second != SafeFD::kNoError) { 26*1a96fba6SXin Li // LOG(ERROR) << "Failed to read from " << PATH; 27*1a96fba6SXin Li // return false; 28*1a96fba6SXin Li // } 29*1a96fba6SXin Li 30*1a96fba6SXin Li #ifndef LIBBRILLO_BRILLO_FILES_SAFE_FD_H_ 31*1a96fba6SXin Li #define LIBBRILLO_BRILLO_FILES_SAFE_FD_H_ 32*1a96fba6SXin Li 33*1a96fba6SXin Li #include <fcntl.h> 34*1a96fba6SXin Li 35*1a96fba6SXin Li #include <string> 36*1a96fba6SXin Li #include <utility> 37*1a96fba6SXin Li #include <vector> 38*1a96fba6SXin Li 39*1a96fba6SXin Li #include <base/files/file_path.h> 40*1a96fba6SXin Li #include <base/files/scoped_file.h> 41*1a96fba6SXin Li #include <base/optional.h> 42*1a96fba6SXin Li #include <base/synchronization/lock.h> 43*1a96fba6SXin Li #include <brillo/brillo_export.h> 44*1a96fba6SXin Li 45*1a96fba6SXin Li namespace brillo { 46*1a96fba6SXin Li 47*1a96fba6SXin Li class SafeFDTest; 48*1a96fba6SXin Li 49*1a96fba6SXin Li class SafeFD { 50*1a96fba6SXin Li public: 51*1a96fba6SXin Li enum class Error { 52*1a96fba6SXin Li kNoError = 0, 53*1a96fba6SXin Li kBadArgument, 54*1a96fba6SXin Li kNotInitialized, // Invalid operation on a SafeFD that was not initialized. 55*1a96fba6SXin Li kIOError, // Check errno for specific cause. 56*1a96fba6SXin Li kDoesNotExist, // The specified path does not exist. 57*1a96fba6SXin Li kSymlinkDetected, 58*1a96fba6SXin Li kBoundaryDetected, // Detected a file system boundary during recursion. 59*1a96fba6SXin Li kWrongType, // (e.g. got a directory and expected a file) 60*1a96fba6SXin Li kWrongUID, 61*1a96fba6SXin Li kWrongGID, 62*1a96fba6SXin Li kWrongPermissions, 63*1a96fba6SXin Li kExceededMaximum, // The maximum allowed read size was reached. 64*1a96fba6SXin Li }; 65*1a96fba6SXin Li 66*1a96fba6SXin Li // Returns true if |err| denotes a failed operation. 67*1a96fba6SXin Li BRILLO_EXPORT static bool IsError(SafeFD::Error err); 68*1a96fba6SXin Li 69*1a96fba6SXin Li typedef std::pair<SafeFD, Error> SafeFDResult; 70*1a96fba6SXin Li 71*1a96fba6SXin Li // 100 MiB 72*1a96fba6SXin Li BRILLO_EXPORT static constexpr size_t kDefaultMaxRead = 100 << 20; 73*1a96fba6SXin Li BRILLO_EXPORT static constexpr size_t kDefaultMaxPathDepth = 256; 74*1a96fba6SXin Li // User read and write only. 75*1a96fba6SXin Li BRILLO_EXPORT static constexpr size_t kDefaultFilePermissions = 0640; 76*1a96fba6SXin Li // User read, write, and execute. Group read and execute. 77*1a96fba6SXin Li BRILLO_EXPORT static constexpr size_t kDefaultDirPermissions = 0750; 78*1a96fba6SXin Li 79*1a96fba6SXin Li // Get a SafeFD to the root path. 80*1a96fba6SXin Li BRILLO_EXPORT static SafeFDResult Root() WARN_UNUSED_RESULT; 81*1a96fba6SXin Li BRILLO_EXPORT static void SetRootPathForTesting(const char* new_root_path); 82*1a96fba6SXin Li 83*1a96fba6SXin Li // Constructs an invalid fd; 84*1a96fba6SXin Li BRILLO_EXPORT SafeFD() = default; 85*1a96fba6SXin Li 86*1a96fba6SXin Li // Move-based constructor and assignment. 87*1a96fba6SXin Li BRILLO_EXPORT SafeFD(SafeFD&&) = default; 88*1a96fba6SXin Li BRILLO_EXPORT SafeFD& operator=(SafeFD&&) = default; 89*1a96fba6SXin Li 90*1a96fba6SXin Li // Return the fd number. 91*1a96fba6SXin Li BRILLO_EXPORT int get() const WARN_UNUSED_RESULT; 92*1a96fba6SXin Li 93*1a96fba6SXin Li // Check the validity of the file descriptor. 94*1a96fba6SXin Li BRILLO_EXPORT bool is_valid() const WARN_UNUSED_RESULT; 95*1a96fba6SXin Li 96*1a96fba6SXin Li // Close the scoped file if one was open. 97*1a96fba6SXin Li BRILLO_EXPORT void reset(); 98*1a96fba6SXin Li 99*1a96fba6SXin Li // Wrap |fd| with a SafeFD which will close the fd when this goes out of 100*1a96fba6SXin Li // scope. This closes the original fd if one was open. 101*1a96fba6SXin Li // This is named "Unsafe" because the recommended way to get a SafeFD 102*1a96fba6SXin Li // instance is opening one from SafeFD::Root(). 103*1a96fba6SXin Li BRILLO_EXPORT void UnsafeReset(int fd); 104*1a96fba6SXin Li 105*1a96fba6SXin Li // Writes |size| bytes from |data| into a file and returns kNoError on 106*1a96fba6SXin Li // success. Note the file will be truncated to the size of the content. 107*1a96fba6SXin Li // 108*1a96fba6SXin Li // Parameters 109*1a96fba6SXin Li // data - The buffer to write to the file. 110*1a96fba6SXin Li // size - The number of bytes to write. 111*1a96fba6SXin Li BRILLO_EXPORT Error Write(const char* data, size_t size) WARN_UNUSED_RESULT; 112*1a96fba6SXin Li 113*1a96fba6SXin Li // Read the contents of the file and return it as a string. 114*1a96fba6SXin Li // 115*1a96fba6SXin Li // Parameters 116*1a96fba6SXin Li // size - The max number of bytes to read. 117*1a96fba6SXin Li BRILLO_EXPORT std::pair<std::vector<char>, Error> ReadContents( 118*1a96fba6SXin Li size_t max_size = kDefaultMaxRead) WARN_UNUSED_RESULT; 119*1a96fba6SXin Li 120*1a96fba6SXin Li // Reads exactly |size| bytes into |data|. 121*1a96fba6SXin Li // 122*1a96fba6SXin Li // Parameters 123*1a96fba6SXin Li // data - The buffer to read the file into. 124*1a96fba6SXin Li // size - The number of bytes to read. 125*1a96fba6SXin Li BRILLO_EXPORT Error Read(char* data, size_t size) WARN_UNUSED_RESULT; 126*1a96fba6SXin Li 127*1a96fba6SXin Li // Open an existing file relative to this directory. 128*1a96fba6SXin Li // 129*1a96fba6SXin Li // Parameters 130*1a96fba6SXin Li // path - The path to open relative to the current directory. 131*1a96fba6SXin Li BRILLO_EXPORT SafeFDResult OpenExistingFile(const base::FilePath& path, 132*1a96fba6SXin Li int flags = O_RDWR | O_CLOEXEC) 133*1a96fba6SXin Li WARN_UNUSED_RESULT; 134*1a96fba6SXin Li 135*1a96fba6SXin Li // Open an existing directory relative to this directory. 136*1a96fba6SXin Li // 137*1a96fba6SXin Li // Parameters 138*1a96fba6SXin Li // path - The path to open relative to the current directory. 139*1a96fba6SXin Li BRILLO_EXPORT SafeFDResult OpenExistingDir(const base::FilePath& path, 140*1a96fba6SXin Li int flags = O_RDONLY | O_CLOEXEC) 141*1a96fba6SXin Li WARN_UNUSED_RESULT; 142*1a96fba6SXin Li 143*1a96fba6SXin Li // Open a file relative to this directory creating the parent directories and 144*1a96fba6SXin Li // file if they don't already exist. 145*1a96fba6SXin Li BRILLO_EXPORT SafeFDResult 146*1a96fba6SXin Li MakeFile(const base::FilePath& path, 147*1a96fba6SXin Li mode_t permissions = kDefaultFilePermissions, 148*1a96fba6SXin Li uid_t uid = getuid(), 149*1a96fba6SXin Li gid_t gid = getgid(), 150*1a96fba6SXin Li int flags = O_RDWR | O_CLOEXEC) WARN_UNUSED_RESULT; 151*1a96fba6SXin Li 152*1a96fba6SXin Li // Create the directories in the relative path with the given ownership and 153*1a96fba6SXin Li // permissions and return a file descriptor to the result. 154*1a96fba6SXin Li BRILLO_EXPORT SafeFDResult 155*1a96fba6SXin Li MakeDir(const base::FilePath& path, 156*1a96fba6SXin Li mode_t permissions = kDefaultDirPermissions, 157*1a96fba6SXin Li uid_t uid = getuid(), 158*1a96fba6SXin Li gid_t gid = getgid(), 159*1a96fba6SXin Li int flags = O_RDONLY | O_CLOEXEC) WARN_UNUSED_RESULT; 160*1a96fba6SXin Li 161*1a96fba6SXin Li // Hard link |fd| in the directory represented by |this| with the specified 162*1a96fba6SXin Li // name |filename|. This requires CAP_DAC_READ_SEARCH. 163*1a96fba6SXin Li // 164*1a96fba6SXin Li // Parameters 165*1a96fba6SXin Li // data - The buffer to write to the file. 166*1a96fba6SXin Li // size - The number of bytes to write. 167*1a96fba6SXin Li BRILLO_EXPORT Error Link(const SafeFD& source_dir, 168*1a96fba6SXin Li const std::string& source_name, 169*1a96fba6SXin Li const std::string& destination_name) 170*1a96fba6SXin Li WARN_UNUSED_RESULT; 171*1a96fba6SXin Li 172*1a96fba6SXin Li // Deletes the child path named |name|. 173*1a96fba6SXin Li // 174*1a96fba6SXin Li // Parameters 175*1a96fba6SXin Li // name - the name of the filesystem object to delete. 176*1a96fba6SXin Li BRILLO_EXPORT Error Unlink(const std::string& name) WARN_UNUSED_RESULT; 177*1a96fba6SXin Li 178*1a96fba6SXin Li // Deletes a child directory. It will return kBoundaryDetected if a file 179*1a96fba6SXin Li // system boundary is reached during recursion. 180*1a96fba6SXin Li // 181*1a96fba6SXin Li // Parameters 182*1a96fba6SXin Li // name - the name of the directory to delete. 183*1a96fba6SXin Li // recursive - if true also unlink child paths. 184*1a96fba6SXin Li // max_depth - limit on recursion depth to prevent fd exhaustion and stack 185*1a96fba6SXin Li // overflows. 186*1a96fba6SXin Li // keep_going - in recursive case continue deleting even in the face of 187*1a96fba6SXin Li // errors. If all entries cannot be deleted, the last error encountered 188*1a96fba6SXin Li // during recursion is returned. 189*1a96fba6SXin Li BRILLO_EXPORT Error Rmdir(const std::string& name, 190*1a96fba6SXin Li bool recursive = false, 191*1a96fba6SXin Li size_t max_depth = kDefaultMaxPathDepth, 192*1a96fba6SXin Li bool keep_going = true) WARN_UNUSED_RESULT; 193*1a96fba6SXin Li 194*1a96fba6SXin Li private: 195*1a96fba6SXin Li BRILLO_EXPORT static const char* RootPath; 196*1a96fba6SXin Li 197*1a96fba6SXin Li base::ScopedFD fd_; 198*1a96fba6SXin Li 199*1a96fba6SXin Li DISALLOW_COPY_AND_ASSIGN(SafeFD); 200*1a96fba6SXin Li }; 201*1a96fba6SXin Li 202*1a96fba6SXin Li } // namespace brillo 203*1a96fba6SXin Li 204*1a96fba6SXin Li #endif // LIBBRILLO_BRILLO_FILES_SAFE_FD_H_ 205