• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // A demo sandbox for the network binary.
2 
3 #include <arpa/inet.h>
4 #include <netinet/in.h>
5 #include <sys/socket.h>
6 #include <syscall.h>
7 #include <unistd.h>
8 
9 #include <cstdlib>
10 #include <memory>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include "absl/flags/flag.h"
16 #include "absl/flags/parse.h"
17 #include "absl/log/globals.h"
18 #include "absl/log/initialize.h"
19 #include "absl/log/log.h"
20 #include "absl/base/log_severity.h"
21 #include "absl/status/statusor.h"
22 #include "absl/strings/string_view.h"
23 #include "absl/time/time.h"
24 #include "sandboxed_api/config.h"
25 #include "sandboxed_api/sandbox2/comms.h"
26 #include "sandboxed_api/sandbox2/executor.h"
27 #include "sandboxed_api/sandbox2/network_proxy/testing.h"
28 #include "sandboxed_api/sandbox2/policy.h"
29 #include "sandboxed_api/sandbox2/policybuilder.h"
30 #include "sandboxed_api/sandbox2/result.h"
31 #include "sandboxed_api/sandbox2/sandbox2.h"
32 #include "sandboxed_api/util/runfiles.h"
33 
34 ABSL_FLAG(bool, connect_with_handler, true, "Connect using automatic mode.");
35 
36 namespace {
37 
38 constexpr char kSandboxeePath[] =
39     "sandbox2/examples/network_proxy/networkproxy_bin";
40 
GetPolicy(absl::string_view sandboxee_path)41 std::unique_ptr<sandbox2::Policy> GetPolicy(absl::string_view sandboxee_path) {
42   sandbox2::PolicyBuilder builder;
43   builder.AllowExit()
44       .AllowMmapWithoutExec()
45       .AllowRead()
46       .AllowWrite()
47       .AllowStat()  // printf, puts
48       .AllowOpen()
49       .AllowSyscall(__NR_sendto)  // send
50       .AllowSyscall(__NR_lseek)
51       .AllowSyscall(__NR_munmap)
52       .AllowSyscall(__NR_getpid)
53       .AllowSyscall(__NR_sigaltstack)
54       .AllowTcMalloc()
55       .AddLibrariesForBinary(sandboxee_path);
56   if (absl::GetFlag(FLAGS_connect_with_handler)) {
57     builder.AddNetworkProxyHandlerPolicy();
58   } else {
59     builder.AddNetworkProxyPolicy();
60   }
61   return builder.AllowIPv6("::1").BuildOrDie();
62 }
63 
64 }  // namespace
65 
main(int argc,char * argv[])66 int main(int argc, char* argv[]) {
67   // This test is incompatible with sanitizers.
68   // The `SKIP_SANITIZERS_AND_COVERAGE` macro won't work for us here since we
69   // need to return something.
70   if constexpr (sapi::sanitizers::IsAny()) {
71     return EXIT_SUCCESS;
72   }
73 
74   absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
75   absl::ParseCommandLine(argc, argv);
76   absl::InitializeLog();
77 
78   absl::StatusOr<std::unique_ptr<sandbox2::NetworkProxyTestServer>> server =
79       sandbox2::NetworkProxyTestServer::Start();
80   if (!server.ok()) {
81     LOG(ERROR) << server.status();
82     return EXIT_FAILURE;
83   }
84 
85   // Note: In your own code, use sapi::GetDataDependencyFilePath() instead.
86   const std::string path =
87       sapi::internal::GetSapiDataDependencyFilePath(kSandboxeePath);
88   std::vector<std::string> args = {path};
89   if (!absl::GetFlag(FLAGS_connect_with_handler)) {
90     args.push_back("--noconnect_with_handler");
91   }
92   std::vector<std::string> envs = {};
93 
94   auto executor = std::make_unique<sandbox2::Executor>(path, args, envs);
95 
96   executor
97       // Sandboxing is enabled by the binary itself (i.e. the networkproxy_bin
98       // is capable of enabling sandboxing on its own).
99       ->set_enable_sandbox_before_exec(false)
100       // Set cwd to / to get rids of warnings connected with file namespace.
101       .set_cwd("/");
102   executor
103       ->limits()
104       // Kill sandboxed processes with a signal (SIGXFSZ) if it writes more than
105       // these many bytes to the file-system.
106       ->set_rlimit_fsize(10000)
107       // The CPU time limit in seconds.
108       .set_rlimit_cpu(100)
109       .set_walltime_limit(absl::Seconds(100));
110 
111   auto policy = GetPolicy(path);
112   sandbox2::Sandbox2 s2(std::move(executor), std::move(policy));
113   sandbox2::Comms* comms = s2.comms();
114 
115   // Let the sandboxee run.
116   if (!s2.RunAsync()) {
117     auto result = s2.AwaitResult();
118     LOG(ERROR) << "RunAsync failed: " << result.ToString();
119     return 2;
120   }
121 
122   // Send the port number via comms
123   if (!comms->SendInt32((*server)->port())) {
124     LOG(ERROR) << "sandboxee_comms->SendInt32() failed";
125     return 3;
126   }
127 
128   auto result = s2.AwaitResult();
129   if (result.final_status() != sandbox2::Result::OK) {
130     LOG(ERROR) << "Sandbox error: " << result.ToString();
131     return 4;  // e.g. sandbox violation, signal (sigsegv)
132   }
133   auto code = result.reason_code();
134   if (code) {
135     LOG(ERROR) << "Sandboxee exited with non-zero: " << code;
136     return 5;  // e.g. normal child error
137   }
138 
139   LOG(INFO) << "Sandboxee finished: " << result.ToString();
140   return EXIT_SUCCESS;
141 }
142