xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/sandbox2/examples/static/static_sandbox.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1 // Copyright 2019 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 // A demo sandbox for the static_bin binary.
16 // Use: static_sandbox --logtostderr
17 
18 #include <fcntl.h>
19 #include <sys/mman.h>
20 #include <syscall.h>
21 #include <unistd.h>
22 
23 #include <cerrno>
24 #include <cstdlib>
25 #include <memory>
26 #include <string>
27 #include <utility>
28 #include <vector>
29 
30 #include "absl/log/check.h"
31 #include "absl/flags/parse.h"
32 #include "absl/log/globals.h"
33 #include "absl/log/initialize.h"
34 #include "absl/log/log.h"
35 #include "absl/base/log_severity.h"
36 #include "absl/time/time.h"
37 #include "sandboxed_api/config.h"
38 #include "sandboxed_api/sandbox2/executor.h"
39 #include "sandboxed_api/sandbox2/limits.h"
40 #include "sandboxed_api/sandbox2/policy.h"
41 #include "sandboxed_api/sandbox2/policybuilder.h"
42 #include "sandboxed_api/sandbox2/result.h"
43 #include "sandboxed_api/sandbox2/sandbox2.h"
44 #include "sandboxed_api/sandbox2/util/bpf_helper.h"
45 #include "sandboxed_api/util/runfiles.h"
46 
GetPolicy()47 std::unique_ptr<sandbox2::Policy> GetPolicy() {
48   return sandbox2::PolicyBuilder()
49       // The most frequent syscall should go first in this sequence (to make it
50       // fast).
51       // Allow read() with all arguments.
52       .AllowRead()
53       // Allow a preset of syscalls that are known to be used during startup
54       // of static binaries.
55       .AllowStaticStartup()
56       // Allow the getpid() syscall.
57       .AllowSyscall(__NR_getpid)
58 
59       // Examples for AddPolicyOnSyscall:
60       .AddPolicyOnSyscall(__NR_write,
61                           {
62                               // Load the first argument of write() (= fd)
63                               ARG_32(0),
64                               // Allow write(fd=STDOUT)
65                               JEQ32(1, ALLOW),
66                               // Allow write(fd=STDERR)
67                               JEQ32(2, ALLOW),
68                               // Fall-through for every other case.
69                               // The default action will be KILL if it is not
70                               // explicitly ALLOWed by a following rule.
71                           })
72       // write() calls with fd not in (1, 2) will continue evaluating the
73       // policy. This means that other rules might still allow them.
74 
75       // Allow the Sandboxee to set the name for better recognition in the
76       // process listing.
77       .AllowPrctlSetName()
78 
79       // Allow the dynamic loader to mark pages to never allow read-write-exec.
80       .AddPolicyOnSyscall(__NR_mprotect,
81                           {
82                               ARG_32(2),
83                               JEQ32(PROT_READ, ALLOW),
84                               JEQ32(PROT_NONE, ALLOW),
85                               JEQ32(PROT_READ | PROT_WRITE, ALLOW),
86                               JEQ32(PROT_READ | PROT_EXEC, ALLOW),
87                           })
88 
89       // Allow exit() only with an exit_code of 0.
90       // Explicitly jumping to KILL, thus the following rules can not
91       // override this rule.
92       .AddPolicyOnSyscall(
93           __NR_exit_group,
94           {
95               // Load first argument (exit_code).
96               ARG_32(0),
97               // Deny every argument except 0.
98               JNE32(0, KILL),
99               // Allow all exit() calls that were not previously forbidden
100               // = exit_code == 0.
101               ALLOW,
102           })
103 
104       // = This won't have any effect as we handled every case of this syscall
105       // in the previous rule.
106       .AllowSyscall(__NR_exit_group)
107 
108       .BlockSyscallsWithErrno(
109           {
110 #ifdef __NR_access
111               // On Debian, even static binaries check existence of
112               // /etc/ld.so.nohwcap.
113               __NR_access,
114 #endif
115               __NR_faccessat,
116 
117 #ifdef __NR_open
118               __NR_open,
119 #endif
120               __NR_openat,
121           },
122           ENOENT)
123       .BuildOrDie();
124 }
125 
main(int argc,char * argv[])126 int main(int argc, char* argv[]) {
127   // This test is incompatible with sanitizers.
128   // The `SKIP_SANITIZERS_AND_COVERAGE` macro won't work for us here since we
129   // need to return something.
130   if constexpr (sapi::sanitizers::IsAny()) {
131     return EXIT_SUCCESS;
132   }
133   absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
134   absl::ParseCommandLine(argc, argv);
135   absl::InitializeLog();
136 
137   // Note: In your own code, use sapi::GetDataDependencyFilePath() instead.
138   const std::string path = sapi::internal::GetSapiDataDependencyFilePath(
139       "sandbox2/examples/static/static_bin");
140   std::vector<std::string> args = {path};
141   auto executor = std::make_unique<sandbox2::Executor>(path, args);
142 
143   executor
144       // Sandboxing is enabled by the sandbox itself. The sandboxed binary is
145       // not aware that it'll be sandboxed.
146       // Note: 'true' is the default setting for this class.
147       ->set_enable_sandbox_before_exec(true)
148       .limits()
149       // Kill sandboxed processes with a signal (SIGXFSZ) if it writes more than
150       // these many bytes to the file-system.
151       ->set_rlimit_fsize(1024 * 1024)
152       // The CPU time limit.
153       .set_rlimit_cpu(60)
154       .set_walltime_limit(absl::Seconds(30));
155 
156   int proc_version_fd = open("/proc/version", O_RDONLY);
157   PCHECK(proc_version_fd != -1);
158 
159   // Map this fils to sandboxee's stdin.
160   executor->ipc()->MapFd(proc_version_fd, STDIN_FILENO);
161 
162   auto policy = GetPolicy();
163   sandbox2::Sandbox2 s2(std::move(executor), std::move(policy));
164 
165   // Let the sandboxee run (synchronously).
166   sandbox2::Result result = s2.Run();
167 
168   LOG(INFO) << "Final execution status: " << result.ToString();
169 
170   return result.final_status() == sandbox2::Result::OK ? EXIT_SUCCESS
171                                                        : EXIT_FAILURE;
172 }
173