xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/sandbox2/examples/network/network_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 network binary.
16 
17 #include <arpa/inet.h>
18 #include <netinet/in.h>
19 #include <sys/socket.h>
20 #include <syscall.h>
21 #include <unistd.h>
22 
23 #include <cstdlib>
24 #include <memory>
25 #include <string>
26 #include <utility>
27 #include <vector>
28 
29 #include "absl/flags/parse.h"
30 #include "absl/log/globals.h"
31 #include "absl/log/initialize.h"
32 #include "absl/log/log.h"
33 #include "absl/base/log_severity.h"
34 #include "absl/status/statusor.h"
35 #include "absl/strings/string_view.h"
36 #include "absl/time/time.h"
37 #include "sandboxed_api/config.h"
38 #include "sandboxed_api/sandbox2/comms.h"
39 #include "sandboxed_api/sandbox2/executor.h"
40 #include "sandboxed_api/sandbox2/network_proxy/testing.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/util/runfiles.h"
46 
47 namespace {
48 
GetPolicy(absl::string_view sandboxee_path)49 std::unique_ptr<sandbox2::Policy> GetPolicy(absl::string_view sandboxee_path) {
50   return sandbox2::PolicyBuilder()
51       .AllowExit()
52       .AllowMmapWithoutExec()
53       .AllowRead()
54       .AllowWrite()
55       .AllowSyscall(__NR_close)
56       .AllowSyscall(__NR_recvmsg)  // RecvFD
57       .AllowSyscall(__NR_sendto)   // send
58       .AllowStat()                 // printf,puts
59       .AddLibrariesForBinary(sandboxee_path)
60       .AllowTcMalloc()
61       .BuildOrDie();
62 }
63 
ConnectToServer(int port)64 int ConnectToServer(int port) {
65   int s = socket(AF_INET6, SOCK_STREAM, 0);
66   if (s < 0) {
67     PLOG(ERROR) << "socket() failed";
68     return -1;
69   }
70 
71   struct sockaddr_in6 saddr {};
72   saddr.sin6_family = AF_INET6;
73   saddr.sin6_port = htons(port);
74 
75   int err = inet_pton(AF_INET6, "::1", &saddr.sin6_addr);
76   if (err == 0) {
77     LOG(ERROR) << "inet_pton() failed";
78     close(s);
79     return -1;
80   }
81   if (err == -1) {
82     PLOG(ERROR) << "inet_pton() failed";
83     close(s);
84     return -1;
85   }
86 
87   err = connect(s, reinterpret_cast<const struct sockaddr*>(&saddr),
88                 sizeof(saddr));
89   if (err != 0) {
90     LOG(ERROR) << "connect() failed";
91     close(s);
92     return -1;
93   }
94 
95   LOG(INFO) << "Connected to the server";
96   return s;
97 }
98 
HandleSandboxee(sandbox2::Comms * comms,int port)99 bool HandleSandboxee(sandbox2::Comms* comms, int port) {
100   // Connect to the server and pass the file descriptor to sandboxee.
101   int client = ConnectToServer(port);
102   if (client <= 0) {
103     LOG(ERROR) << "connect_to_server() failed";
104     return false;
105   }
106 
107   if (!comms->SendFD(client)) {
108     LOG(ERROR) << "sandboxee_comms->SendFD(client) failed";
109     close(client);
110     return false;
111   }
112   close(client);
113   return true;
114 }
115 
116 }  // namespace
117 
main(int argc,char * argv[])118 int main(int argc, char* argv[]) {
119   // This test is incompatible with sanitizers.
120   // The `SKIP_SANITIZERS_AND_COVERAGE` macro won't work for us here since we
121   // need to return something.
122   if constexpr (sapi::sanitizers::IsAny()) {
123     return EXIT_SUCCESS;
124   }
125 
126   absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
127   absl::ParseCommandLine(argc, argv);
128   absl::InitializeLog();
129 
130   absl::StatusOr<std::unique_ptr<sandbox2::NetworkProxyTestServer>> server =
131       sandbox2::NetworkProxyTestServer::Start();
132   if (!server.ok()) {
133     LOG(ERROR) << server.status();
134     return EXIT_FAILURE;
135   }
136 
137   // Note: In your own code, use sapi::GetDataDependencyFilePath() instead.
138   const std::string path = sapi::internal::GetSapiDataDependencyFilePath(
139       "sandbox2/examples/network/network_bin");
140   std::vector<std::string> args = {path};
141   std::vector<std::string> envs = {};
142 
143   auto executor = std::make_unique<sandbox2::Executor>(path, args, envs);
144   executor
145       // Sandboxing is enabled by the binary itself (i.e. the crc4bin is capable
146       // of enabling sandboxing on its own).
147       ->set_enable_sandbox_before_exec(false)
148       // Set cwd to / to get rids of warnings connected with file namespace.
149       .set_cwd("/");
150 
151   executor
152       ->limits()
153       // Kill sandboxed processes with a signal (SIGXFSZ) if it writes more than
154       // these many bytes to the file-system.
155       ->set_rlimit_fsize(10000)
156       .set_rlimit_cpu(100)  // The CPU time limit in seconds
157       .set_walltime_limit(absl::Seconds(100));
158 
159   auto policy = GetPolicy(path);
160   sandbox2::Sandbox2 s2(std::move(executor), std::move(policy));
161   auto* comms = s2.comms();
162 
163   // Let the sandboxee run.
164   if (!s2.RunAsync()) {
165     auto result = s2.AwaitResult();
166     LOG(ERROR) << "RunAsync failed: " << result.ToString();
167     return 2;
168   }
169 
170   if (!HandleSandboxee(comms, (*server)->port())) {
171     if (!s2.IsTerminated()) {
172       // Kill the sandboxee, because failure to receive the data over the Comms
173       // channel doesn't automatically mean that the sandboxee itself had
174       // already finished. The final reason will not be overwritten, so if
175       // sandboxee finished because of e.g. timeout, the TIMEOUT reason will be
176       // reported.
177       LOG(INFO) << "Killing sandboxee";
178       s2.Kill();
179     }
180   }
181 
182   auto result = s2.AwaitResult();
183   if (result.final_status() != sandbox2::Result::OK) {
184     LOG(ERROR) << "Sandbox error: " << result.ToString();
185     return 3;  // e.g. sandbox violation, signal (sigsegv).
186   }
187   auto code = result.reason_code();
188   if (code) {
189     LOG(ERROR) << "Sandboxee exited with non-zero: " << code;
190     return 4;  // e.g. normal child error.
191   }
192   LOG(INFO) << "Sandboxee finished: " << result.ToString();
193   return EXIT_SUCCESS;
194 }
195