• 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 crc4bin binary
16 
17 #include <syscall.h>
18 
19 #include <cstdint>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <memory>
23 #include <string>
24 #include <utility>
25 #include <vector>
26 
27 #include "absl/flags/flag.h"
28 #include "absl/flags/parse.h"
29 #include "absl/log/globals.h"
30 #include "absl/log/initialize.h"
31 #include "absl/log/log.h"
32 #include "absl/base/log_severity.h"
33 #include "absl/strings/string_view.h"
34 #include "absl/time/time.h"
35 #include "sandboxed_api/sandbox2/allowlists/namespaces.h"
36 #include "sandboxed_api/sandbox2/comms.h"
37 #include "sandboxed_api/sandbox2/executor.h"
38 #include "sandboxed_api/sandbox2/limits.h"
39 #include "sandboxed_api/sandbox2/policy.h"
40 #include "sandboxed_api/sandbox2/policybuilder.h"
41 #include "sandboxed_api/sandbox2/result.h"
42 #include "sandboxed_api/sandbox2/sandbox2.h"
43 #include "sandboxed_api/sandbox2/util/bpf_helper.h"
44 #include "sandboxed_api/util/runfiles.h"
45 
46 ABSL_FLAG(std::string, input, "", "Input to calculate CRC4 of.");
47 ABSL_FLAG(bool, call_syscall_not_allowed, false,
48           "Have sandboxee call clone (violation).");
49 
50 namespace {
51 
GetPolicy()52 std::unique_ptr<sandbox2::Policy> GetPolicy() {
53   return sandbox2::PolicyBuilder()
54       .DisableNamespaces(sandbox2::NamespacesToken())  // Safe, as we only allow
55                                                        // I/O on existing FDs.
56       .AllowExit()
57       .AddPolicyOnSyscalls(
58           {
59               __NR_read,
60               __NR_write,
61               __NR_close,
62           },
63           {
64               ARG_32(0),
65               JEQ32(sandbox2::Comms::kSandbox2ClientCommsFD, ALLOW),
66           })
67       .AllowLlvmSanitizers()  // Will be a no-op when not using sanitizers.
68       .BuildOrDie();
69 }
70 
SandboxedCRC4(sandbox2::Comms * comms,uint32_t * crc4)71 bool SandboxedCRC4(sandbox2::Comms* comms, uint32_t* crc4) {
72   const std::string input = absl::GetFlag(FLAGS_input);
73 
74   auto* buf = reinterpret_cast<const uint8_t*>(input.data());
75   size_t buf_size = input.size();
76 
77   if (!comms->SendBytes(buf, buf_size)) {
78     LOG(ERROR) << "sandboxee_comms->SendBytes() failed";
79     return false;
80   }
81 
82   if (!comms->RecvUint32(crc4)) {
83     LOG(ERROR) << "sandboxee_comms->RecvUint32(&crc4) failed";
84     return false;
85   }
86   return true;
87 }
88 
89 }  // namespace
90 
main(int argc,char * argv[])91 int main(int argc, char* argv[]) {
92   absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
93   absl::ParseCommandLine(argc, argv);
94   absl::InitializeLog();
95 
96   if (absl::GetFlag(FLAGS_input).empty()) {
97     LOG(ERROR) << "Parameter --input required.";
98     return 1;
99   }
100 
101   // Note: In your own code, use sapi::GetDataDependencyFilePath() instead.
102   const std::string path = sapi::internal::GetSapiDataDependencyFilePath(
103       "sandbox2/examples/crc4/crc4bin");
104   std::vector<std::string> args = {path};
105   if (absl::GetFlag(FLAGS_call_syscall_not_allowed)) {
106     args.push_back("-call_syscall_not_allowed");
107   }
108   std::vector<std::string> envs = {};
109   auto executor = std::make_unique<sandbox2::Executor>(path, args, envs);
110 
111   executor
112       // Sandboxing is enabled by the binary itself (i.e. the crc4bin is capable
113       // of enabling sandboxing on its own).
114       ->set_enable_sandbox_before_exec(false)
115       .limits()
116       // Kill sandboxed processes with a signal (SIGXFSZ) if it writes more than
117       // these many bytes to the file-system.
118       ->set_rlimit_fsize(1024)
119       .set_rlimit_cpu(60)  // The CPU time limit in seconds.
120       .set_walltime_limit(absl::Seconds(5));
121 
122   sandbox2::Sandbox2 s2(std::move(executor), GetPolicy());
123 
124   // Let the sandboxee run.
125   if (!s2.RunAsync()) {
126     sandbox2::Result result = s2.AwaitResult();
127     LOG(ERROR) << "RunAsync failed: " << result.ToString();
128     return 2;
129   }
130 
131   sandbox2::Comms* comms = s2.comms();
132 
133   uint32_t crc4;
134   if (!SandboxedCRC4(comms, &crc4)) {
135     LOG(ERROR) << "GetCRC4 failed";
136     if (!s2.IsTerminated()) {
137       // Kill the sandboxee, because failure to receive the data over the Comms
138       // channel doesn't automatically mean that the sandboxee itself had
139       // already finished. The final reason will not be overwritten, so if
140       // sandboxee finished because of e.g. timeout, the TIMEOUT reason will be
141       // reported.
142       LOG(INFO) << "Killing sandboxee";
143       s2.Kill();
144     }
145   }
146 
147   sandbox2::Result result = s2.AwaitResult();
148   if (result.final_status() != sandbox2::Result::OK) {
149     LOG(ERROR) << "Sandbox error: " << result.ToString();
150     return 3;  // e.g. sandbox violation, signal (sigsegv)
151   }
152   auto code = result.reason_code();
153   if (code) {
154     LOG(ERROR) << "Sandboxee exited with non-zero: " << code;
155     return 4;  // e.g. normal child error
156   }
157   LOG(INFO) << "Sandboxee finished: " << result.ToString();
158   printf("0x%08x\n", crc4);
159   return EXIT_SUCCESS;
160 }
161