xref: /aosp_15_r20/external/sandboxed-api/oss-internship-2020/libarchive/examples/sandbox.h (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
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