1*ec63e07aSXin Li // Copyright 2020 Google LLC 2*ec63e07aSXin Li // 3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License"); 4*ec63e07aSXin Li // you may not use this file except in compliance with the License. 5*ec63e07aSXin Li // You may obtain a copy of the License at 6*ec63e07aSXin Li // 7*ec63e07aSXin Li // https://www.apache.org/licenses/LICENSE-2.0 8*ec63e07aSXin Li // 9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software 10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS, 11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*ec63e07aSXin Li // See the License for the specific language governing permissions and 13*ec63e07aSXin Li // limitations under the License. 14*ec63e07aSXin Li 15*ec63e07aSXin Li #ifndef SAPI_LIBARCHIVE_EXAMPLES_SANDBOX_H 16*ec63e07aSXin Li #define SAPI_LIBARCHIVE_EXAMPLES_SANDBOX_H 17*ec63e07aSXin Li 18*ec63e07aSXin Li #include <asm/unistd_64.h> 19*ec63e07aSXin Li #include <linux/fs.h> 20*ec63e07aSXin Li 21*ec63e07aSXin Li #include "libarchive_sapi.sapi.h" // NOLINT(build/include) 22*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util/bpf_helper.h" 23*ec63e07aSXin Li #include "sandboxed_api/util/fileops.h" 24*ec63e07aSXin Li 25*ec63e07aSXin Li // When creating an archive, we need read permissions on each of the 26*ec63e07aSXin Li // file/directory added in the archive. Also, in order to create the archive, we 27*ec63e07aSXin Li // map "/output" with the basename of the archive. This way, the program can 28*ec63e07aSXin Li // create the file without having access to anything else. 29*ec63e07aSXin Li class SapiLibarchiveSandboxCreate : public LibarchiveSandbox { 30*ec63e07aSXin Li public: SapiLibarchiveSandboxCreate(const std::vector<std::string> & files,absl::string_view archive_path)31*ec63e07aSXin Li SapiLibarchiveSandboxCreate(const std::vector<std::string>& files, 32*ec63e07aSXin Li absl::string_view archive_path) 33*ec63e07aSXin Li : files_(files), archive_path_(archive_path) {} 34*ec63e07aSXin Li 35*ec63e07aSXin Li private: ModifyPolicy(sandbox2::PolicyBuilder *)36*ec63e07aSXin Li std::unique_ptr<sandbox2::Policy> ModifyPolicy( 37*ec63e07aSXin Li sandbox2::PolicyBuilder*) override { 38*ec63e07aSXin Li sandbox2::PolicyBuilder policy = 39*ec63e07aSXin Li sandbox2::PolicyBuilder() 40*ec63e07aSXin Li .AddDirectoryAt(archive_path_, "/output", false) 41*ec63e07aSXin Li .AllowRead() 42*ec63e07aSXin Li .AllowWrite() 43*ec63e07aSXin Li .AllowOpen() 44*ec63e07aSXin Li .AllowSystemMalloc() 45*ec63e07aSXin Li .AllowGetIDs() 46*ec63e07aSXin Li .AllowSafeFcntl() 47*ec63e07aSXin Li .AllowStat() 48*ec63e07aSXin Li .AllowExit() 49*ec63e07aSXin Li .AllowSyscall(__NR_futex) 50*ec63e07aSXin Li .AllowSyscall(__NR_lseek) 51*ec63e07aSXin Li .AllowSyscall(__NR_close) 52*ec63e07aSXin Li .AllowSyscall(__NR_gettid) 53*ec63e07aSXin Li .AllowSyscall(__NR_umask) 54*ec63e07aSXin Li .AllowSyscall(__NR_utimensat) 55*ec63e07aSXin Li .AllowUnlink() 56*ec63e07aSXin Li .AllowMkdir() 57*ec63e07aSXin Li .AllowSyscall(__NR_fstatfs) 58*ec63e07aSXin Li .AllowSyscall(__NR_socket) 59*ec63e07aSXin Li .AllowSyscall(__NR_connect) 60*ec63e07aSXin Li .AllowSyscall(__NR_flistxattr) 61*ec63e07aSXin Li .AllowSyscall(__NR_recvmsg) 62*ec63e07aSXin Li .AllowSyscall(__NR_getdents64) 63*ec63e07aSXin Li // Allow ioctl only for FS_IOC_GETFLAGS. 64*ec63e07aSXin Li .AddPolicyOnSyscall(__NR_ioctl, 65*ec63e07aSXin Li {ARG(1), JEQ(FS_IOC_GETFLAGS, ALLOW)}); 66*ec63e07aSXin Li 67*ec63e07aSXin Li // We check whether the entry is a file or a directory. 68*ec63e07aSXin Li for (const auto& i : files_) { 69*ec63e07aSXin Li struct stat s; 70*ec63e07aSXin Li CHECK(stat(i.c_str(), &s) == 0) << "Could not stat " << i; 71*ec63e07aSXin Li if (S_ISDIR(s.st_mode)) { 72*ec63e07aSXin Li policy = policy.AddDirectory(i); 73*ec63e07aSXin Li } else { 74*ec63e07aSXin Li policy = policy.AddFile(i); 75*ec63e07aSXin Li } 76*ec63e07aSXin Li } 77*ec63e07aSXin Li 78*ec63e07aSXin Li return policy.BuildOrDie(); 79*ec63e07aSXin Li } 80*ec63e07aSXin Li 81*ec63e07aSXin Li const std::vector<std::string> files_; 82*ec63e07aSXin Li absl::string_view archive_path_; 83*ec63e07aSXin Li }; 84*ec63e07aSXin Li 85*ec63e07aSXin Li // When an archive is extracted, the generated files/directories will be placed 86*ec63e07aSXin Li // relative to the current working directory. In order to add permissions to 87*ec63e07aSXin Li // this we create a temporary directory at every extraction. Then, we change the 88*ec63e07aSXin Li // directory of the sandboxed process to that directory and map it to the 89*ec63e07aSXin Li // current "real" working directory. This way the contents of the archived will 90*ec63e07aSXin Li // pe placed correctly without offering additional permission. 91*ec63e07aSXin Li class SapiLibarchiveSandboxExtract : public LibarchiveSandbox { 92*ec63e07aSXin Li public: SapiLibarchiveSandboxExtract(absl::string_view archive_path,int do_extract,absl::string_view tmp_dir)93*ec63e07aSXin Li SapiLibarchiveSandboxExtract(absl::string_view archive_path, int do_extract, 94*ec63e07aSXin Li absl::string_view tmp_dir) 95*ec63e07aSXin Li : archive_path_(archive_path), 96*ec63e07aSXin Li do_extract_(do_extract), 97*ec63e07aSXin Li tmp_dir_(tmp_dir) {} 98*ec63e07aSXin Li 99*ec63e07aSXin Li private: ModifyExecutor(sandbox2::Executor * executor)100*ec63e07aSXin Li void ModifyExecutor(sandbox2::Executor* executor) override { 101*ec63e07aSXin Li // If the user only wants to list the entries in the archive, we do 102*ec63e07aSXin Li // not need to worry about changing directories; 103*ec63e07aSXin Li if (do_extract_) { 104*ec63e07aSXin Li executor->set_cwd(std::string(tmp_dir_)); 105*ec63e07aSXin Li } 106*ec63e07aSXin Li } 107*ec63e07aSXin Li ModifyPolicy(sandbox2::PolicyBuilder *)108*ec63e07aSXin Li std::unique_ptr<sandbox2::Policy> ModifyPolicy( 109*ec63e07aSXin Li sandbox2::PolicyBuilder*) override { 110*ec63e07aSXin Li sandbox2::PolicyBuilder policy = sandbox2::PolicyBuilder() 111*ec63e07aSXin Li .AllowRead() 112*ec63e07aSXin Li .AllowWrite() 113*ec63e07aSXin Li .AllowOpen() 114*ec63e07aSXin Li .AllowSystemMalloc() 115*ec63e07aSXin Li .AllowGetIDs() 116*ec63e07aSXin Li .AllowSafeFcntl() 117*ec63e07aSXin Li .AllowStat() 118*ec63e07aSXin Li .AllowExit() 119*ec63e07aSXin Li .AllowSyscall(__NR_futex) 120*ec63e07aSXin Li .AllowSyscall(__NR_lseek) 121*ec63e07aSXin Li .AllowSyscall(__NR_close) 122*ec63e07aSXin Li .AllowSyscall(__NR_gettid) 123*ec63e07aSXin Li .AllowSyscall(__NR_umask) 124*ec63e07aSXin Li .AllowSyscall(__NR_utimensat) 125*ec63e07aSXin Li .AllowUnlink() 126*ec63e07aSXin Li .AllowMkdir() 127*ec63e07aSXin Li .AddFile(archive_path_); 128*ec63e07aSXin Li 129*ec63e07aSXin Li if (do_extract_) { 130*ec63e07aSXin Li // Get the real cwd and map it to the temporary directory in which 131*ec63e07aSXin Li // the sandboxed process takes place(). 132*ec63e07aSXin Li std::string cwd = sandbox2::file_util::fileops::GetCWD(); 133*ec63e07aSXin Li policy = policy.AddDirectoryAt(cwd, tmp_dir_, false); 134*ec63e07aSXin Li } 135*ec63e07aSXin Li return policy.BuildOrDie(); 136*ec63e07aSXin Li } 137*ec63e07aSXin Li 138*ec63e07aSXin Li absl::string_view archive_path_; 139*ec63e07aSXin Li absl::string_view tmp_dir_; 140*ec63e07aSXin Li const int do_extract_; 141*ec63e07aSXin Li }; 142*ec63e07aSXin Li 143*ec63e07aSXin Li #endif // SAPI_LIBARCHIVE_EXAMPLES_SANDBOX_H 144