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