sandboxed-api/oss-internship-2020/libarchive/examples/sandbox.h

145 lines
5.3 KiB
C++

// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SAPI_LIBARCHIVE_SANDBOX_H
#define SAPI_LIBARCHIVE_SANDBOX_H
#include <asm/unistd_64.h>
#include "libarchive_sapi.sapi.h"
#include "sandboxed_api/sandbox2/util/fileops.h"
// When creating an archive, we need read permissions on each of the
// file/directory added in the archive. Also, in order to create the archive, we
// map "/output" with the basename of the archive. This way, the program can
// create the file without having access to anything else.
class SapiLibarchiveSandboxCreate : public LibarchiveSandbox {
public:
explicit SapiLibarchiveSandboxCreate(const std::vector<std::string>& files,
absl::string_view archive_path)
: files_(files), archive_path_(archive_path) {}
private:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder*) override {
sandbox2::PolicyBuilder policy =
sandbox2::PolicyBuilder()
.AddDirectoryAt(archive_path_, "/output", false)
.AllowRead()
.AllowWrite()
.AllowOpen()
.AllowSystemMalloc()
.AllowGetIDs()
.AllowSafeFcntl()
.AllowStat()
.AllowExit()
.AllowSyscalls({
__NR_futex,
__NR_lseek,
__NR_close,
__NR_gettid,
__NR_umask,
__NR_utimensat,
__NR_unlink,
__NR_mkdir,
__NR_fstatfs,
__NR_socket,
__NR_connect,
__NR_ioctl,
__NR_flistxattr,
__NR_recvmsg,
__NR_getdents64,
});
// We check whether the entry is a file or a directory.
for (const auto& i : files_) {
struct stat s;
stat(i.c_str(), &s);
if (S_ISDIR(s.st_mode)) {
policy = policy.AddDirectory(i);
} else {
policy = policy.AddFile(i);
}
}
return policy.BuildOrDie();
}
const std::vector<std::string> files_;
absl::string_view archive_path_;
};
// When an archive is extracted, the generated files/directories will be placed
// relative to the current working directory. In order to add permissions to
// this we create a temporary directory at every extraction. Then, we change the
// directory of the sandboxed process to that directory and map it to the
// current "real" working directory. This way the contents of the archived will
// pe placed correctly without offering additional permission.
class SapiLibarchiveSandboxExtract : public LibarchiveSandbox {
public:
explicit SapiLibarchiveSandboxExtract(absl::string_view archive_path,
const int do_extract,
absl::string_view tmp_dir)
: archive_path_(archive_path),
do_extract_(do_extract),
tmp_dir_(tmp_dir) {}
private:
virtual void ModifyExecutor(sandbox2::Executor* executor) override {
// If the user only wants to list the entries in the archive, we do
// not need to worry about changing directories;
if (do_extract_) {
executor = &executor->set_cwd(std::string(tmp_dir_));
}
}
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder*) override {
sandbox2::PolicyBuilder policy = sandbox2::PolicyBuilder()
.AllowRead()
.AllowWrite()
.AllowOpen()
.AllowSystemMalloc()
.AllowGetIDs()
.AllowSafeFcntl()
.AllowStat()
.AllowExit()
.AllowSyscalls({
__NR_futex,
__NR_lseek,
__NR_close,
__NR_gettid,
__NR_umask,
__NR_utimensat,
__NR_unlink,
__NR_mkdir,
})
.AddFile(archive_path_);
if (do_extract_) {
// Get the real cwd and map it to the temporary directory in which
// the sandboxed process takes place().
std::string cwd = sandbox2::file_util::fileops::GetCWD();
policy = policy.AddDirectoryAt(cwd, tmp_dir_, false);
}
return policy.BuildOrDie();
}
absl::string_view archive_path_;
absl::string_view tmp_dir_;
const int do_extract_;
};
#endif // SAPI_LIBARCHIVE_SANDBOX_H