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