]>
git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/env/env_chroot.cc
4bc2f9a250721f803f95ce4dd20461071f201b7f
1 // Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
6 #if !defined(ROCKSDB_LITE) && !defined(OS_WIN)
8 #include "env/env_chroot.h"
19 #include "rocksdb/status.h"
21 namespace ROCKSDB_NAMESPACE
{
23 class ChrootEnv
: public EnvWrapper
{
25 ChrootEnv(Env
* base_env
, const std::string
& chroot_dir
)
26 : EnvWrapper(base_env
) {
28 char resolvedName
[PATH_MAX
];
29 char* real_chroot_dir
= realpath(chroot_dir
.c_str(), resolvedName
);
31 char* real_chroot_dir
= realpath(chroot_dir
.c_str(), nullptr);
33 // chroot_dir must exist so realpath() returns non-nullptr.
34 assert(real_chroot_dir
!= nullptr);
35 chroot_dir_
= real_chroot_dir
;
37 free(real_chroot_dir
);
41 Status
RegisterDbPaths(const std::vector
<std::string
>& paths
) override
{
42 std::vector
<std::string
> encoded_paths
;
43 encoded_paths
.reserve(paths
.size());
44 for (auto& path
: paths
) {
45 auto status_and_enc_path
= EncodePathWithNewBasename(path
);
46 if (!status_and_enc_path
.first
.ok()) {
47 return status_and_enc_path
.first
;
49 encoded_paths
.emplace_back(status_and_enc_path
.second
);
51 return EnvWrapper::Env::RegisterDbPaths(encoded_paths
);
54 Status
UnregisterDbPaths(const std::vector
<std::string
>& paths
) override
{
55 std::vector
<std::string
> encoded_paths
;
56 encoded_paths
.reserve(paths
.size());
57 for (auto& path
: paths
) {
58 auto status_and_enc_path
= EncodePathWithNewBasename(path
);
59 if (!status_and_enc_path
.first
.ok()) {
60 return status_and_enc_path
.first
;
62 encoded_paths
.emplace_back(status_and_enc_path
.second
);
64 return EnvWrapper::Env::UnregisterDbPaths(encoded_paths
);
67 Status
NewSequentialFile(const std::string
& fname
,
68 std::unique_ptr
<SequentialFile
>* result
,
69 const EnvOptions
& options
) override
{
70 auto status_and_enc_path
= EncodePathWithNewBasename(fname
);
71 if (!status_and_enc_path
.first
.ok()) {
72 return status_and_enc_path
.first
;
74 return EnvWrapper::NewSequentialFile(status_and_enc_path
.second
, result
,
78 Status
NewRandomAccessFile(const std::string
& fname
,
79 std::unique_ptr
<RandomAccessFile
>* result
,
80 const EnvOptions
& options
) override
{
81 auto status_and_enc_path
= EncodePathWithNewBasename(fname
);
82 if (!status_and_enc_path
.first
.ok()) {
83 return status_and_enc_path
.first
;
85 return EnvWrapper::NewRandomAccessFile(status_and_enc_path
.second
, result
,
89 Status
NewWritableFile(const std::string
& fname
,
90 std::unique_ptr
<WritableFile
>* result
,
91 const EnvOptions
& options
) override
{
92 auto status_and_enc_path
= EncodePathWithNewBasename(fname
);
93 if (!status_and_enc_path
.first
.ok()) {
94 return status_and_enc_path
.first
;
96 return EnvWrapper::NewWritableFile(status_and_enc_path
.second
, result
,
100 Status
ReuseWritableFile(const std::string
& fname
,
101 const std::string
& old_fname
,
102 std::unique_ptr
<WritableFile
>* result
,
103 const EnvOptions
& options
) override
{
104 auto status_and_enc_path
= EncodePathWithNewBasename(fname
);
105 if (!status_and_enc_path
.first
.ok()) {
106 return status_and_enc_path
.first
;
108 auto status_and_old_enc_path
= EncodePath(old_fname
);
109 if (!status_and_old_enc_path
.first
.ok()) {
110 return status_and_old_enc_path
.first
;
112 return EnvWrapper::ReuseWritableFile(status_and_old_enc_path
.second
,
113 status_and_old_enc_path
.second
, result
,
117 Status
NewRandomRWFile(const std::string
& fname
,
118 std::unique_ptr
<RandomRWFile
>* result
,
119 const EnvOptions
& options
) override
{
120 auto status_and_enc_path
= EncodePathWithNewBasename(fname
);
121 if (!status_and_enc_path
.first
.ok()) {
122 return status_and_enc_path
.first
;
124 return EnvWrapper::NewRandomRWFile(status_and_enc_path
.second
, result
,
128 Status
NewDirectory(const std::string
& dir
,
129 std::unique_ptr
<Directory
>* result
) override
{
130 auto status_and_enc_path
= EncodePathWithNewBasename(dir
);
131 if (!status_and_enc_path
.first
.ok()) {
132 return status_and_enc_path
.first
;
134 return EnvWrapper::NewDirectory(status_and_enc_path
.second
, result
);
137 Status
FileExists(const std::string
& fname
) override
{
138 auto status_and_enc_path
= EncodePathWithNewBasename(fname
);
139 if (!status_and_enc_path
.first
.ok()) {
140 return status_and_enc_path
.first
;
142 return EnvWrapper::FileExists(status_and_enc_path
.second
);
145 Status
GetChildren(const std::string
& dir
,
146 std::vector
<std::string
>* result
) override
{
147 auto status_and_enc_path
= EncodePath(dir
);
148 if (!status_and_enc_path
.first
.ok()) {
149 return status_and_enc_path
.first
;
151 return EnvWrapper::GetChildren(status_and_enc_path
.second
, result
);
154 Status
GetChildrenFileAttributes(
155 const std::string
& dir
, std::vector
<FileAttributes
>* result
) override
{
156 auto status_and_enc_path
= EncodePath(dir
);
157 if (!status_and_enc_path
.first
.ok()) {
158 return status_and_enc_path
.first
;
160 return EnvWrapper::GetChildrenFileAttributes(status_and_enc_path
.second
,
164 Status
DeleteFile(const std::string
& fname
) override
{
165 auto status_and_enc_path
= EncodePath(fname
);
166 if (!status_and_enc_path
.first
.ok()) {
167 return status_and_enc_path
.first
;
169 return EnvWrapper::DeleteFile(status_and_enc_path
.second
);
172 Status
CreateDir(const std::string
& dirname
) override
{
173 auto status_and_enc_path
= EncodePathWithNewBasename(dirname
);
174 if (!status_and_enc_path
.first
.ok()) {
175 return status_and_enc_path
.first
;
177 return EnvWrapper::CreateDir(status_and_enc_path
.second
);
180 Status
CreateDirIfMissing(const std::string
& dirname
) override
{
181 auto status_and_enc_path
= EncodePathWithNewBasename(dirname
);
182 if (!status_and_enc_path
.first
.ok()) {
183 return status_and_enc_path
.first
;
185 return EnvWrapper::CreateDirIfMissing(status_and_enc_path
.second
);
188 Status
DeleteDir(const std::string
& dirname
) override
{
189 auto status_and_enc_path
= EncodePath(dirname
);
190 if (!status_and_enc_path
.first
.ok()) {
191 return status_and_enc_path
.first
;
193 return EnvWrapper::DeleteDir(status_and_enc_path
.second
);
196 Status
GetFileSize(const std::string
& fname
, uint64_t* file_size
) override
{
197 auto status_and_enc_path
= EncodePath(fname
);
198 if (!status_and_enc_path
.first
.ok()) {
199 return status_and_enc_path
.first
;
201 return EnvWrapper::GetFileSize(status_and_enc_path
.second
, file_size
);
204 Status
GetFileModificationTime(const std::string
& fname
,
205 uint64_t* file_mtime
) override
{
206 auto status_and_enc_path
= EncodePath(fname
);
207 if (!status_and_enc_path
.first
.ok()) {
208 return status_and_enc_path
.first
;
210 return EnvWrapper::GetFileModificationTime(status_and_enc_path
.second
,
214 Status
RenameFile(const std::string
& src
, const std::string
& dest
) override
{
215 auto status_and_src_enc_path
= EncodePath(src
);
216 if (!status_and_src_enc_path
.first
.ok()) {
217 return status_and_src_enc_path
.first
;
219 auto status_and_dest_enc_path
= EncodePathWithNewBasename(dest
);
220 if (!status_and_dest_enc_path
.first
.ok()) {
221 return status_and_dest_enc_path
.first
;
223 return EnvWrapper::RenameFile(status_and_src_enc_path
.second
,
224 status_and_dest_enc_path
.second
);
227 Status
LinkFile(const std::string
& src
, const std::string
& dest
) override
{
228 auto status_and_src_enc_path
= EncodePath(src
);
229 if (!status_and_src_enc_path
.first
.ok()) {
230 return status_and_src_enc_path
.first
;
232 auto status_and_dest_enc_path
= EncodePathWithNewBasename(dest
);
233 if (!status_and_dest_enc_path
.first
.ok()) {
234 return status_and_dest_enc_path
.first
;
236 return EnvWrapper::LinkFile(status_and_src_enc_path
.second
,
237 status_and_dest_enc_path
.second
);
240 Status
LockFile(const std::string
& fname
, FileLock
** lock
) override
{
241 auto status_and_enc_path
= EncodePathWithNewBasename(fname
);
242 if (!status_and_enc_path
.first
.ok()) {
243 return status_and_enc_path
.first
;
245 // FileLock subclasses may store path (e.g., PosixFileLock stores it). We
246 // can skip stripping the chroot directory from this path because callers
248 return EnvWrapper::LockFile(status_and_enc_path
.second
, lock
);
251 Status
GetTestDirectory(std::string
* path
) override
{
252 // Adapted from PosixEnv's implementation since it doesn't provide a way to
253 // create directory in the chroot.
255 snprintf(buf
, sizeof(buf
), "/rocksdbtest-%d", static_cast<int>(geteuid()));
258 // Directory may already exist, so ignore return
259 return CreateDirIfMissing(*path
);
262 Status
NewLogger(const std::string
& fname
,
263 std::shared_ptr
<Logger
>* result
) override
{
264 auto status_and_enc_path
= EncodePathWithNewBasename(fname
);
265 if (!status_and_enc_path
.first
.ok()) {
266 return status_and_enc_path
.first
;
268 return EnvWrapper::NewLogger(status_and_enc_path
.second
, result
);
271 Status
GetAbsolutePath(const std::string
& db_path
,
272 std::string
* output_path
) override
{
273 auto status_and_enc_path
= EncodePath(db_path
);
274 if (!status_and_enc_path
.first
.ok()) {
275 return status_and_enc_path
.first
;
277 return EnvWrapper::GetAbsolutePath(status_and_enc_path
.second
, output_path
);
281 // Returns status and expanded absolute path including the chroot directory.
282 // Checks whether the provided path breaks out of the chroot. If it returns
283 // non-OK status, the returned path should not be used.
284 std::pair
<Status
, std::string
> EncodePath(const std::string
& path
) {
285 if (path
.empty() || path
[0] != '/') {
286 return {Status::InvalidArgument(path
, "Not an absolute path"), ""};
288 std::pair
<Status
, std::string
> res
;
289 res
.second
= chroot_dir_
+ path
;
291 char resolvedName
[PATH_MAX
];
292 char* normalized_path
= realpath(res
.second
.c_str(), resolvedName
);
294 char* normalized_path
= realpath(res
.second
.c_str(), nullptr);
296 if (normalized_path
== nullptr) {
297 res
.first
= Status::NotFound(res
.second
, strerror(errno
));
298 } else if (strlen(normalized_path
) < chroot_dir_
.size() ||
299 strncmp(normalized_path
, chroot_dir_
.c_str(),
300 chroot_dir_
.size()) != 0) {
301 res
.first
= Status::IOError(res
.second
,
302 "Attempted to access path outside chroot");
304 res
.first
= Status::OK();
307 free(normalized_path
);
312 // Similar to EncodePath() except assumes the basename in the path hasn't been
314 std::pair
<Status
, std::string
> EncodePathWithNewBasename(
315 const std::string
& path
) {
316 if (path
.empty() || path
[0] != '/') {
317 return {Status::InvalidArgument(path
, "Not an absolute path"), ""};
319 // Basename may be followed by trailing slashes
320 size_t final_idx
= path
.find_last_not_of('/');
321 if (final_idx
== std::string::npos
) {
322 // It's only slashes so no basename to extract
323 return EncodePath(path
);
326 // Pull off the basename temporarily since realname(3) (used by
327 // EncodePath()) requires a path that exists
328 size_t base_sep
= path
.rfind('/', final_idx
);
329 auto status_and_enc_path
= EncodePath(path
.substr(0, base_sep
+ 1));
330 status_and_enc_path
.second
.append(path
.substr(base_sep
+ 1));
331 return status_and_enc_path
;
334 std::string chroot_dir_
;
337 Env
* NewChrootEnv(Env
* base_env
, const std::string
& chroot_dir
) {
338 if (!base_env
->FileExists(chroot_dir
).ok()) {
341 return new ChrootEnv(base_env
, chroot_dir
);
344 } // namespace ROCKSDB_NAMESPACE
346 #endif // !defined(ROCKSDB_LITE) && !defined(OS_WIN)