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