| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- // Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
- // This source code is licensed under both the GPLv2 (found in the
- // COPYING file in the root directory) and Apache 2.0 License
- // (found in the LICENSE.Apache file in the root directory).
- #if !defined(ROCKSDB_LITE) && !defined(OS_WIN)
- #include "env/env_chroot.h"
- #include <errno.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <string>
- #include <utility>
- #include <vector>
- #include "rocksdb/status.h"
- namespace ROCKSDB_NAMESPACE {
- class ChrootEnv : public EnvWrapper {
- public:
- ChrootEnv(Env* base_env, const std::string& chroot_dir)
- : EnvWrapper(base_env) {
- #if defined(OS_AIX)
- char resolvedName[PATH_MAX];
- char* real_chroot_dir = realpath(chroot_dir.c_str(), resolvedName);
- #else
- char* real_chroot_dir = realpath(chroot_dir.c_str(), nullptr);
- #endif
- // chroot_dir must exist so realpath() returns non-nullptr.
- assert(real_chroot_dir != nullptr);
- chroot_dir_ = real_chroot_dir;
- #if !defined(OS_AIX)
- free(real_chroot_dir);
- #endif
- }
- Status NewSequentialFile(const std::string& fname,
- std::unique_ptr<SequentialFile>* result,
- const EnvOptions& options) override {
- auto status_and_enc_path = EncodePathWithNewBasename(fname);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::NewSequentialFile(status_and_enc_path.second, result,
- options);
- }
- Status NewRandomAccessFile(const std::string& fname,
- std::unique_ptr<RandomAccessFile>* result,
- const EnvOptions& options) override {
- auto status_and_enc_path = EncodePathWithNewBasename(fname);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::NewRandomAccessFile(status_and_enc_path.second, result,
- options);
- }
- Status NewWritableFile(const std::string& fname,
- std::unique_ptr<WritableFile>* result,
- const EnvOptions& options) override {
- auto status_and_enc_path = EncodePathWithNewBasename(fname);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::NewWritableFile(status_and_enc_path.second, result,
- options);
- }
- Status ReuseWritableFile(const std::string& fname,
- const std::string& old_fname,
- std::unique_ptr<WritableFile>* result,
- const EnvOptions& options) override {
- auto status_and_enc_path = EncodePathWithNewBasename(fname);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- auto status_and_old_enc_path = EncodePath(old_fname);
- if (!status_and_old_enc_path.first.ok()) {
- return status_and_old_enc_path.first;
- }
- return EnvWrapper::ReuseWritableFile(status_and_old_enc_path.second,
- status_and_old_enc_path.second, result,
- options);
- }
- Status NewRandomRWFile(const std::string& fname,
- std::unique_ptr<RandomRWFile>* result,
- const EnvOptions& options) override {
- auto status_and_enc_path = EncodePathWithNewBasename(fname);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::NewRandomRWFile(status_and_enc_path.second, result,
- options);
- }
- Status NewDirectory(const std::string& dir,
- std::unique_ptr<Directory>* result) override {
- auto status_and_enc_path = EncodePathWithNewBasename(dir);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::NewDirectory(status_and_enc_path.second, result);
- }
- Status FileExists(const std::string& fname) override {
- auto status_and_enc_path = EncodePathWithNewBasename(fname);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::FileExists(status_and_enc_path.second);
- }
- Status GetChildren(const std::string& dir,
- std::vector<std::string>* result) override {
- auto status_and_enc_path = EncodePath(dir);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::GetChildren(status_and_enc_path.second, result);
- }
- Status GetChildrenFileAttributes(
- const std::string& dir, std::vector<FileAttributes>* result) override {
- auto status_and_enc_path = EncodePath(dir);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::GetChildrenFileAttributes(status_and_enc_path.second,
- result);
- }
- Status DeleteFile(const std::string& fname) override {
- auto status_and_enc_path = EncodePath(fname);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::DeleteFile(status_and_enc_path.second);
- }
- Status CreateDir(const std::string& dirname) override {
- auto status_and_enc_path = EncodePathWithNewBasename(dirname);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::CreateDir(status_and_enc_path.second);
- }
- Status CreateDirIfMissing(const std::string& dirname) override {
- auto status_and_enc_path = EncodePathWithNewBasename(dirname);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::CreateDirIfMissing(status_and_enc_path.second);
- }
- Status DeleteDir(const std::string& dirname) override {
- auto status_and_enc_path = EncodePath(dirname);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::DeleteDir(status_and_enc_path.second);
- }
- Status GetFileSize(const std::string& fname, uint64_t* file_size) override {
- auto status_and_enc_path = EncodePath(fname);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::GetFileSize(status_and_enc_path.second, file_size);
- }
- Status GetFileModificationTime(const std::string& fname,
- uint64_t* file_mtime) override {
- auto status_and_enc_path = EncodePath(fname);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::GetFileModificationTime(status_and_enc_path.second,
- file_mtime);
- }
- Status RenameFile(const std::string& src, const std::string& dest) override {
- auto status_and_src_enc_path = EncodePath(src);
- if (!status_and_src_enc_path.first.ok()) {
- return status_and_src_enc_path.first;
- }
- auto status_and_dest_enc_path = EncodePathWithNewBasename(dest);
- if (!status_and_dest_enc_path.first.ok()) {
- return status_and_dest_enc_path.first;
- }
- return EnvWrapper::RenameFile(status_and_src_enc_path.second,
- status_and_dest_enc_path.second);
- }
- Status LinkFile(const std::string& src, const std::string& dest) override {
- auto status_and_src_enc_path = EncodePath(src);
- if (!status_and_src_enc_path.first.ok()) {
- return status_and_src_enc_path.first;
- }
- auto status_and_dest_enc_path = EncodePathWithNewBasename(dest);
- if (!status_and_dest_enc_path.first.ok()) {
- return status_and_dest_enc_path.first;
- }
- return EnvWrapper::LinkFile(status_and_src_enc_path.second,
- status_and_dest_enc_path.second);
- }
- Status LockFile(const std::string& fname, FileLock** lock) override {
- auto status_and_enc_path = EncodePathWithNewBasename(fname);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- // FileLock subclasses may store path (e.g., PosixFileLock stores it). We
- // can skip stripping the chroot directory from this path because callers
- // shouldn't use it.
- return EnvWrapper::LockFile(status_and_enc_path.second, lock);
- }
- Status GetTestDirectory(std::string* path) override {
- // Adapted from PosixEnv's implementation since it doesn't provide a way to
- // create directory in the chroot.
- char buf[256];
- snprintf(buf, sizeof(buf), "/rocksdbtest-%d", static_cast<int>(geteuid()));
- *path = buf;
- // Directory may already exist, so ignore return
- CreateDir(*path);
- return Status::OK();
- }
- Status NewLogger(const std::string& fname,
- std::shared_ptr<Logger>* result) override {
- auto status_and_enc_path = EncodePathWithNewBasename(fname);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::NewLogger(status_and_enc_path.second, result);
- }
- Status GetAbsolutePath(const std::string& db_path,
- std::string* output_path) override {
- auto status_and_enc_path = EncodePath(db_path);
- if (!status_and_enc_path.first.ok()) {
- return status_and_enc_path.first;
- }
- return EnvWrapper::GetAbsolutePath(status_and_enc_path.second, output_path);
- }
- private:
- // Returns status and expanded absolute path including the chroot directory.
- // Checks whether the provided path breaks out of the chroot. If it returns
- // non-OK status, the returned path should not be used.
- std::pair<Status, std::string> EncodePath(const std::string& path) {
- if (path.empty() || path[0] != '/') {
- return {Status::InvalidArgument(path, "Not an absolute path"), ""};
- }
- std::pair<Status, std::string> res;
- res.second = chroot_dir_ + path;
- #if defined(OS_AIX)
- char resolvedName[PATH_MAX];
- char* normalized_path = realpath(res.second.c_str(), resolvedName);
- #else
- char* normalized_path = realpath(res.second.c_str(), nullptr);
- #endif
- if (normalized_path == nullptr) {
- res.first = Status::NotFound(res.second, strerror(errno));
- } else if (strlen(normalized_path) < chroot_dir_.size() ||
- strncmp(normalized_path, chroot_dir_.c_str(),
- chroot_dir_.size()) != 0) {
- res.first = Status::IOError(res.second,
- "Attempted to access path outside chroot");
- } else {
- res.first = Status::OK();
- }
- #if !defined(OS_AIX)
- free(normalized_path);
- #endif
- return res;
- }
- // Similar to EncodePath() except assumes the basename in the path hasn't been
- // created yet.
- std::pair<Status, std::string> EncodePathWithNewBasename(
- const std::string& path) {
- if (path.empty() || path[0] != '/') {
- return {Status::InvalidArgument(path, "Not an absolute path"), ""};
- }
- // Basename may be followed by trailing slashes
- size_t final_idx = path.find_last_not_of('/');
- if (final_idx == std::string::npos) {
- // It's only slashes so no basename to extract
- return EncodePath(path);
- }
- // Pull off the basename temporarily since realname(3) (used by
- // EncodePath()) requires a path that exists
- size_t base_sep = path.rfind('/', final_idx);
- auto status_and_enc_path = EncodePath(path.substr(0, base_sep + 1));
- status_and_enc_path.second.append(path.substr(base_sep + 1));
- return status_and_enc_path;
- }
- std::string chroot_dir_;
- };
- Env* NewChrootEnv(Env* base_env, const std::string& chroot_dir) {
- if (!base_env->FileExists(chroot_dir).ok()) {
- return nullptr;
- }
- return new ChrootEnv(base_env, chroot_dir);
- }
- } // namespace ROCKSDB_NAMESPACE
- #endif // !defined(ROCKSDB_LITE) && !defined(OS_WIN)
|