xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/sandbox2/client.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1*ec63e07aSXin Li // Copyright 2019 Google LLC
2*ec63e07aSXin Li //
3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License");
4*ec63e07aSXin Li // you may not use this file except in compliance with the License.
5*ec63e07aSXin Li // You may obtain a copy of the License at
6*ec63e07aSXin Li //
7*ec63e07aSXin Li //     https://www.apache.org/licenses/LICENSE-2.0
8*ec63e07aSXin Li //
9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software
10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS,
11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*ec63e07aSXin Li // See the License for the specific language governing permissions and
13*ec63e07aSXin Li // limitations under the License.
14*ec63e07aSXin Li 
15*ec63e07aSXin Li // Implementation file for the sandbox2::Client class.
16*ec63e07aSXin Li 
17*ec63e07aSXin Li #include "sandboxed_api/sandbox2/client.h"
18*ec63e07aSXin Li 
19*ec63e07aSXin Li #include <fcntl.h>
20*ec63e07aSXin Li #include <linux/bpf_common.h>
21*ec63e07aSXin Li #include <linux/filter.h>
22*ec63e07aSXin Li #include <linux/seccomp.h>
23*ec63e07aSXin Li #include <sys/prctl.h>
24*ec63e07aSXin Li #include <syscall.h>
25*ec63e07aSXin Li #include <unistd.h>
26*ec63e07aSXin Li 
27*ec63e07aSXin Li #include <atomic>
28*ec63e07aSXin Li #include <cerrno>
29*ec63e07aSXin Li #include <cinttypes>
30*ec63e07aSXin Li #include <cstdint>
31*ec63e07aSXin Li #include <cstdlib>
32*ec63e07aSXin Li #include <limits>
33*ec63e07aSXin Li #include <memory>
34*ec63e07aSXin Li #include <string>
35*ec63e07aSXin Li #include <thread>  // NOLINT(build/c++11)
36*ec63e07aSXin Li #include <utility>
37*ec63e07aSXin Li #include <vector>
38*ec63e07aSXin Li 
39*ec63e07aSXin Li #include "absl/base/attributes.h"
40*ec63e07aSXin Li #include "absl/base/macros.h"
41*ec63e07aSXin Li #include "absl/container/flat_hash_map.h"
42*ec63e07aSXin Li #include "absl/status/status.h"
43*ec63e07aSXin Li #include "absl/strings/numbers.h"
44*ec63e07aSXin Li #include "absl/strings/str_cat.h"
45*ec63e07aSXin Li #include "absl/strings/str_join.h"
46*ec63e07aSXin Li #include "absl/strings/str_split.h"
47*ec63e07aSXin Li #include "absl/strings/string_view.h"
48*ec63e07aSXin Li #include "sandboxed_api/sandbox2/comms.h"
49*ec63e07aSXin Li #include "sandboxed_api/sandbox2/policy.h"
50*ec63e07aSXin Li #include "sandboxed_api/sandbox2/sanitizer.h"
51*ec63e07aSXin Li #include "sandboxed_api/sandbox2/syscall.h"
52*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util/bpf_helper.h"
53*ec63e07aSXin Li #include "sandboxed_api/util/raw_logging.h"
54*ec63e07aSXin Li 
55*ec63e07aSXin Li #ifndef SECCOMP_FILTER_FLAG_NEW_LISTENER
56*ec63e07aSXin Li #define SECCOMP_FILTER_FLAG_NEW_LISTENER (1UL << 3)
57*ec63e07aSXin Li #endif
58*ec63e07aSXin Li 
59*ec63e07aSXin Li namespace sandbox2 {
60*ec63e07aSXin Li namespace {
61*ec63e07aSXin Li 
InitSeccompUnotify(sock_fprog prog,Comms * comms)62*ec63e07aSXin Li void InitSeccompUnotify(sock_fprog prog, Comms* comms) {
63*ec63e07aSXin Li   // The policy might not allow sending the notify FD.
64*ec63e07aSXin Li   // Create a separate thread that won't get the seccomp policy to send the FD.
65*ec63e07aSXin Li   // Synchronize with it using plain atomics + seccomp TSYNC, so we don't need
66*ec63e07aSXin Li   // any additional syscalls.
67*ec63e07aSXin Li   std::atomic<int> fd(-1);
68*ec63e07aSXin Li   std::atomic<int> tid(-1);
69*ec63e07aSXin Li 
70*ec63e07aSXin Li   std::thread th([comms, &fd, &tid]() {
71*ec63e07aSXin Li     int notify_fd = -1;
72*ec63e07aSXin Li     while (notify_fd == -1) {
73*ec63e07aSXin Li       notify_fd = fd.load(std::memory_order_seq_cst);
74*ec63e07aSXin Li     }
75*ec63e07aSXin Li     SAPI_RAW_CHECK(comms->SendFD(notify_fd), "sending unotify fd");
76*ec63e07aSXin Li     SAPI_RAW_CHECK(close(notify_fd) == 0, "closing unotify fd");
77*ec63e07aSXin Li     sock_filter filter = ALLOW;
78*ec63e07aSXin Li     struct sock_fprog allow_prog = {
79*ec63e07aSXin Li         .len = 1,
80*ec63e07aSXin Li         .filter = &filter,
81*ec63e07aSXin Li     };
82*ec63e07aSXin Li     int result = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, 0,
83*ec63e07aSXin Li                          reinterpret_cast<uintptr_t>(&allow_prog));
84*ec63e07aSXin Li     SAPI_RAW_PCHECK(result != -1, "setting seccomp filter");
85*ec63e07aSXin Li     tid.store(syscall(__NR_gettid), std::memory_order_seq_cst);
86*ec63e07aSXin Li   });
87*ec63e07aSXin Li   th.detach();
88*ec63e07aSXin Li   int result = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER,
89*ec63e07aSXin Li                        SECCOMP_FILTER_FLAG_NEW_LISTENER,
90*ec63e07aSXin Li                        reinterpret_cast<uintptr_t>(&prog));
91*ec63e07aSXin Li   SAPI_RAW_PCHECK(result != -1, "setting seccomp filter");
92*ec63e07aSXin Li   fd.store(result, std::memory_order_seq_cst);
93*ec63e07aSXin Li   pid_t child = -1;
94*ec63e07aSXin Li   while (child == -1) {
95*ec63e07aSXin Li     child = tid.load(std::memory_order_seq_cst);
96*ec63e07aSXin Li   }
97*ec63e07aSXin Li   // Apply seccomp.
98*ec63e07aSXin Li   struct sock_filter code[] = {
99*ec63e07aSXin Li       LOAD_ARCH,
100*ec63e07aSXin Li       JNE32(sandbox2::Syscall::GetHostAuditArch(), ALLOW),
101*ec63e07aSXin Li       LOAD_SYSCALL_NR,
102*ec63e07aSXin Li       BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_seccomp, 0, 3),
103*ec63e07aSXin Li       ARG_32(3),
104*ec63e07aSXin Li       BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, internal::kExecveMagic, 0, 1),
105*ec63e07aSXin Li       DENY,
106*ec63e07aSXin Li       ALLOW,
107*ec63e07aSXin Li   };
108*ec63e07aSXin Li   prog.len = ABSL_ARRAYSIZE(code);
109*ec63e07aSXin Li   prog.filter = code;
110*ec63e07aSXin Li   do {
111*ec63e07aSXin Li     result = syscall(
112*ec63e07aSXin Li         __NR_seccomp, SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
113*ec63e07aSXin Li         reinterpret_cast<uintptr_t>(&prog), internal::kExecveMagic);
114*ec63e07aSXin Li   } while (result == child);
115*ec63e07aSXin Li   SAPI_RAW_CHECK(result == 0, "Enabling seccomp filter");
116*ec63e07aSXin Li }
117*ec63e07aSXin Li 
InitSeccompRegular(sock_fprog prog)118*ec63e07aSXin Li void InitSeccompRegular(sock_fprog prog) {
119*ec63e07aSXin Li   int result =
120*ec63e07aSXin Li       syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
121*ec63e07aSXin Li               reinterpret_cast<uintptr_t>(&prog));
122*ec63e07aSXin Li   SAPI_RAW_PCHECK(result != -1, "setting seccomp filter");
123*ec63e07aSXin Li   SAPI_RAW_PCHECK(result == 0,
124*ec63e07aSXin Li                   "synchronizing threads using SECCOMP_FILTER_FLAG_TSYNC flag "
125*ec63e07aSXin Li                   "for thread=%d",
126*ec63e07aSXin Li                   result);
127*ec63e07aSXin Li }
128*ec63e07aSXin Li 
129*ec63e07aSXin Li }  // namespace
130*ec63e07aSXin Li 
Client(Comms * comms)131*ec63e07aSXin Li Client::Client(Comms* comms) : comms_(comms) {
132*ec63e07aSXin Li   char* fdmap_envvar = getenv(kFDMapEnvVar);
133*ec63e07aSXin Li   if (!fdmap_envvar) {
134*ec63e07aSXin Li     return;
135*ec63e07aSXin Li   }
136*ec63e07aSXin Li   absl::flat_hash_map<absl::string_view, absl::string_view> vars =
137*ec63e07aSXin Li       absl::StrSplit(fdmap_envvar, ',', absl::SkipEmpty());
138*ec63e07aSXin Li   for (const auto& [name, mapped_fd] : vars) {
139*ec63e07aSXin Li     int fd;
140*ec63e07aSXin Li     SAPI_RAW_CHECK(absl::SimpleAtoi(mapped_fd, &fd), "failed to parse fd map");
141*ec63e07aSXin Li     SAPI_RAW_CHECK(fd_map_.emplace(std::string(name), fd).second,
142*ec63e07aSXin Li                    "could not insert mapping into fd map (duplicate)");
143*ec63e07aSXin Li   }
144*ec63e07aSXin Li   unsetenv(kFDMapEnvVar);
145*ec63e07aSXin Li }
146*ec63e07aSXin Li 
GetFdMapEnvVar() const147*ec63e07aSXin Li std::string Client::GetFdMapEnvVar() const {
148*ec63e07aSXin Li   return absl::StrCat(kFDMapEnvVar, "=",
149*ec63e07aSXin Li                       absl::StrJoin(fd_map_, ",", absl::PairFormatter(",")));
150*ec63e07aSXin Li }
151*ec63e07aSXin Li 
PrepareEnvironment(int * preserved_fd)152*ec63e07aSXin Li void Client::PrepareEnvironment(int* preserved_fd) {
153*ec63e07aSXin Li   SetUpIPC(preserved_fd);
154*ec63e07aSXin Li   SetUpCwd();
155*ec63e07aSXin Li }
156*ec63e07aSXin Li 
EnableSandbox()157*ec63e07aSXin Li void Client::EnableSandbox() {
158*ec63e07aSXin Li   ReceivePolicy();
159*ec63e07aSXin Li   ApplyPolicyAndBecomeTracee();
160*ec63e07aSXin Li }
161*ec63e07aSXin Li 
SandboxMeHere()162*ec63e07aSXin Li void Client::SandboxMeHere() {
163*ec63e07aSXin Li   PrepareEnvironment();
164*ec63e07aSXin Li   EnableSandbox();
165*ec63e07aSXin Li }
166*ec63e07aSXin Li 
SetUpCwd()167*ec63e07aSXin Li void Client::SetUpCwd() {
168*ec63e07aSXin Li   {
169*ec63e07aSXin Li     // Get the current working directory to check if we are in a mount
170*ec63e07aSXin Li     // namespace.
171*ec63e07aSXin Li     // Note: glibc 2.27 no longer returns a relative path in that case, but
172*ec63e07aSXin Li     //       fails with ENOENT and returns a nullptr instead. The code still
173*ec63e07aSXin Li     //       needs to run on lower version for the time being.
174*ec63e07aSXin Li     char cwd_buf[PATH_MAX + 1] = {0};
175*ec63e07aSXin Li     char* cwd = getcwd(cwd_buf, ABSL_ARRAYSIZE(cwd_buf));
176*ec63e07aSXin Li     SAPI_RAW_PCHECK(cwd != nullptr || errno == ENOENT,
177*ec63e07aSXin Li                     "no current working directory");
178*ec63e07aSXin Li 
179*ec63e07aSXin Li     // Outside of the mount namespace, the path is of the form
180*ec63e07aSXin Li     // '(unreachable)/...'. Only check for the slash, since Linux might make up
181*ec63e07aSXin Li     // other prefixes in the future.
182*ec63e07aSXin Li     if (errno == ENOENT || cwd_buf[0] != '/') {
183*ec63e07aSXin Li       SAPI_RAW_VLOG(1, "chdir into mount namespace, cwd was '%s'", cwd_buf);
184*ec63e07aSXin Li       // If we are in a mount namespace but fail to chdir, then it can lead to a
185*ec63e07aSXin Li       // sandbox escape -- we need to fail with FATAL if the chdir fails.
186*ec63e07aSXin Li       SAPI_RAW_PCHECK(chdir("/") != -1, "corrective chdir");
187*ec63e07aSXin Li     }
188*ec63e07aSXin Li   }
189*ec63e07aSXin Li 
190*ec63e07aSXin Li   // Receive the user-supplied current working directory and change into it.
191*ec63e07aSXin Li   std::string cwd;
192*ec63e07aSXin Li   SAPI_RAW_CHECK(comms_->RecvString(&cwd), "receiving working directory");
193*ec63e07aSXin Li   if (!cwd.empty()) {
194*ec63e07aSXin Li     // On the other hand this chdir can fail without a sandbox escape. It will
195*ec63e07aSXin Li     // probably not have the intended behavior though.
196*ec63e07aSXin Li     if (chdir(cwd.c_str()) == -1 && SAPI_RAW_VLOG_IS_ON(1)) {
197*ec63e07aSXin Li       SAPI_RAW_PLOG(
198*ec63e07aSXin Li           INFO,
199*ec63e07aSXin Li           "chdir(%s) failed, falling back to previous cwd or / (with "
200*ec63e07aSXin Li           "namespaces). Use Executor::SetCwd() to set a working directory",
201*ec63e07aSXin Li           cwd.c_str());
202*ec63e07aSXin Li     }
203*ec63e07aSXin Li   }
204*ec63e07aSXin Li }
205*ec63e07aSXin Li 
SetUpIPC(int * preserved_fd)206*ec63e07aSXin Li void Client::SetUpIPC(int* preserved_fd) {
207*ec63e07aSXin Li   uint32_t num_of_fd_pairs;
208*ec63e07aSXin Li   SAPI_RAW_CHECK(comms_->RecvUint32(&num_of_fd_pairs),
209*ec63e07aSXin Li                  "receiving number of fd pairs");
210*ec63e07aSXin Li   SAPI_RAW_CHECK(fd_map_.empty(), "fd map not empty");
211*ec63e07aSXin Li 
212*ec63e07aSXin Li   SAPI_RAW_VLOG(1, "Will receive %d file descriptor pairs", num_of_fd_pairs);
213*ec63e07aSXin Li 
214*ec63e07aSXin Li   absl::flat_hash_map<int, int*> preserve_fds_map;
215*ec63e07aSXin Li   if (preserved_fd) {
216*ec63e07aSXin Li     preserve_fds_map.emplace(*preserved_fd, preserved_fd);
217*ec63e07aSXin Li   }
218*ec63e07aSXin Li 
219*ec63e07aSXin Li   for (uint32_t i = 0; i < num_of_fd_pairs; ++i) {
220*ec63e07aSXin Li     int32_t requested_fd;
221*ec63e07aSXin Li     int32_t fd;
222*ec63e07aSXin Li     std::string name;
223*ec63e07aSXin Li 
224*ec63e07aSXin Li     SAPI_RAW_CHECK(comms_->RecvInt32(&requested_fd), "receiving requested fd");
225*ec63e07aSXin Li     SAPI_RAW_CHECK(comms_->RecvFD(&fd), "receiving current fd");
226*ec63e07aSXin Li     SAPI_RAW_CHECK(comms_->RecvString(&name), "receiving name string");
227*ec63e07aSXin Li 
228*ec63e07aSXin Li     if (auto it = preserve_fds_map.find(requested_fd);
229*ec63e07aSXin Li         it != preserve_fds_map.end()) {
230*ec63e07aSXin Li       int old_fd = it->first;
231*ec63e07aSXin Li       int new_fd = dup(old_fd);
232*ec63e07aSXin Li       SAPI_RAW_PCHECK(new_fd != -1, "Failed to duplicate preserved fd=%d",
233*ec63e07aSXin Li                       old_fd);
234*ec63e07aSXin Li       SAPI_RAW_LOG(INFO, "Moved preserved fd=%d to %d", old_fd, new_fd);
235*ec63e07aSXin Li       close(old_fd);
236*ec63e07aSXin Li       int* pfd = it->second;
237*ec63e07aSXin Li       *pfd = new_fd;
238*ec63e07aSXin Li       preserve_fds_map.erase(it);
239*ec63e07aSXin Li       preserve_fds_map.emplace(new_fd, pfd);
240*ec63e07aSXin Li     }
241*ec63e07aSXin Li 
242*ec63e07aSXin Li     if (requested_fd == comms_->GetConnectionFD()) {
243*ec63e07aSXin Li       comms_->MoveToAnotherFd();
244*ec63e07aSXin Li       SAPI_RAW_LOG(INFO,
245*ec63e07aSXin Li                    "Trying to map over comms fd (%d). Remapped comms to %d",
246*ec63e07aSXin Li                    requested_fd, comms_->GetConnectionFD());
247*ec63e07aSXin Li     }
248*ec63e07aSXin Li 
249*ec63e07aSXin Li     if (requested_fd != -1 && fd != requested_fd) {
250*ec63e07aSXin Li       if (requested_fd > STDERR_FILENO && fcntl(requested_fd, F_GETFD) != -1) {
251*ec63e07aSXin Li         // Dup2 will silently close the FD if one is already at requested_fd.
252*ec63e07aSXin Li         // If someone is using the deferred sandbox entry, ie. SandboxMeHere,
253*ec63e07aSXin Li         // the application might have something actually using that fd.
254*ec63e07aSXin Li         // Therefore let's log a big warning if that FD is already in use.
255*ec63e07aSXin Li         // Note: this check doesn't happen for STDIN,STDOUT,STDERR.
256*ec63e07aSXin Li         SAPI_RAW_LOG(
257*ec63e07aSXin Li             WARNING,
258*ec63e07aSXin Li             "Cloning received fd %d over %d which is already open and will "
259*ec63e07aSXin Li             "be silently closed. This may lead to unexpected behavior!",
260*ec63e07aSXin Li             fd, requested_fd);
261*ec63e07aSXin Li       }
262*ec63e07aSXin Li 
263*ec63e07aSXin Li       SAPI_RAW_VLOG(1, "Cloning received fd=%d onto fd=%d", fd, requested_fd);
264*ec63e07aSXin Li       SAPI_RAW_PCHECK(dup2(fd, requested_fd) != -1, "");
265*ec63e07aSXin Li 
266*ec63e07aSXin Li       // Close the newly received FD if it differs from the new one.
267*ec63e07aSXin Li       close(fd);
268*ec63e07aSXin Li       fd = requested_fd;
269*ec63e07aSXin Li     }
270*ec63e07aSXin Li 
271*ec63e07aSXin Li     if (!name.empty()) {
272*ec63e07aSXin Li       SAPI_RAW_CHECK(fd_map_.emplace(name, fd).second, "duplicate fd mapping");
273*ec63e07aSXin Li     }
274*ec63e07aSXin Li   }
275*ec63e07aSXin Li }
276*ec63e07aSXin Li 
ReceivePolicy()277*ec63e07aSXin Li void Client::ReceivePolicy() {
278*ec63e07aSXin Li   std::vector<uint8_t> bytes;
279*ec63e07aSXin Li   SAPI_RAW_CHECK(comms_->RecvBytes(&bytes), "receive bytes");
280*ec63e07aSXin Li   policy_ = std::move(bytes);
281*ec63e07aSXin Li }
282*ec63e07aSXin Li 
ApplyPolicyAndBecomeTracee()283*ec63e07aSXin Li void Client::ApplyPolicyAndBecomeTracee() {
284*ec63e07aSXin Li   // When running under *SAN, we need to notify *SANs background thread that we
285*ec63e07aSXin Li   // want it to exit and wait for it to be done. When not running under *SAN,
286*ec63e07aSXin Li   // this function does nothing.
287*ec63e07aSXin Li   sanitizer::WaitForSanitizer();
288*ec63e07aSXin Li 
289*ec63e07aSXin Li   // Creds can be received w/o synchronization, once the connection is
290*ec63e07aSXin Li   // established.
291*ec63e07aSXin Li   pid_t cred_pid;
292*ec63e07aSXin Li   uid_t cred_uid ABSL_ATTRIBUTE_UNUSED;
293*ec63e07aSXin Li   gid_t cred_gid ABSL_ATTRIBUTE_UNUSED;
294*ec63e07aSXin Li   SAPI_RAW_CHECK(comms_->RecvCreds(&cred_pid, &cred_uid, &cred_gid),
295*ec63e07aSXin Li                  "receiving credentials");
296*ec63e07aSXin Li 
297*ec63e07aSXin Li   SAPI_RAW_CHECK(prctl(PR_SET_DUMPABLE, 1) == 0,
298*ec63e07aSXin Li                  "setting PR_SET_DUMPABLE flag");
299*ec63e07aSXin Li   if (prctl(PR_SET_PTRACER, cred_pid) == -1) {
300*ec63e07aSXin Li     SAPI_RAW_VLOG(1, "No YAMA on this system. Continuing");
301*ec63e07aSXin Li   }
302*ec63e07aSXin Li 
303*ec63e07aSXin Li   SAPI_RAW_CHECK(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == 0,
304*ec63e07aSXin Li                  "setting PR_SET_NO_NEW_PRIVS flag");
305*ec63e07aSXin Li   SAPI_RAW_CHECK(prctl(PR_SET_KEEPCAPS, 0) == 0,
306*ec63e07aSXin Li                  "setting PR_SET_KEEPCAPS flag");
307*ec63e07aSXin Li 
308*ec63e07aSXin Li   sock_fprog prog;
309*ec63e07aSXin Li   SAPI_RAW_CHECK(policy_.size() / sizeof(sock_filter) <=
310*ec63e07aSXin Li                      std::numeric_limits<uint16_t>::max(),
311*ec63e07aSXin Li                  "seccomp policy too long");
312*ec63e07aSXin Li   prog.len = static_cast<uint16_t>(policy_.size() / sizeof(sock_filter));
313*ec63e07aSXin Li   prog.filter = reinterpret_cast<sock_filter*>(&policy_.front());
314*ec63e07aSXin Li 
315*ec63e07aSXin Li   SAPI_RAW_VLOG(1,
316*ec63e07aSXin Li                 "Applying policy in PID %zd, sock_fprog.len: %" PRId16
317*ec63e07aSXin Li                 " entries (%" PRIuPTR " bytes)",
318*ec63e07aSXin Li                 syscall(__NR_gettid), prog.len, policy_.size());
319*ec63e07aSXin Li 
320*ec63e07aSXin Li   // Signal executor we are ready to have limits applied on us and be ptraced.
321*ec63e07aSXin Li   // We want limits at the last moment to avoid triggering them too early and we
322*ec63e07aSXin Li   // want ptrace at the last moment to avoid synchronization deadlocks.
323*ec63e07aSXin Li   SAPI_RAW_CHECK(comms_->SendUint32(kClient2SandboxReady),
324*ec63e07aSXin Li                  "receiving ready signal from executor");
325*ec63e07aSXin Li   uint32_t ret;  // wait for confirmation
326*ec63e07aSXin Li   SAPI_RAW_CHECK(comms_->RecvUint32(&ret),
327*ec63e07aSXin Li                  "receving confirmation from executor");
328*ec63e07aSXin Li   if (ret == kSandbox2ClientUnotify) {
329*ec63e07aSXin Li     InitSeccompUnotify(prog, comms_);
330*ec63e07aSXin Li   } else {
331*ec63e07aSXin Li     SAPI_RAW_CHECK(ret == kSandbox2ClientDone,
332*ec63e07aSXin Li                    "invalid confirmation from executor");
333*ec63e07aSXin Li     InitSeccompRegular(prog);
334*ec63e07aSXin Li   }
335*ec63e07aSXin Li }
336*ec63e07aSXin Li 
GetMappedFD(const std::string & name)337*ec63e07aSXin Li int Client::GetMappedFD(const std::string& name) {
338*ec63e07aSXin Li   auto it = fd_map_.find(name);
339*ec63e07aSXin Li   SAPI_RAW_CHECK(it != fd_map_.end(),
340*ec63e07aSXin Li                  "mapped fd not found (function called twice?)");
341*ec63e07aSXin Li   int fd = it->second;
342*ec63e07aSXin Li   fd_map_.erase(it);
343*ec63e07aSXin Li   return fd;
344*ec63e07aSXin Li }
345*ec63e07aSXin Li 
HasMappedFD(const std::string & name)346*ec63e07aSXin Li bool Client::HasMappedFD(const std::string& name) {
347*ec63e07aSXin Li   return fd_map_.find(name) != fd_map_.end();
348*ec63e07aSXin Li }
349*ec63e07aSXin Li 
SendLogsToSupervisor()350*ec63e07aSXin Li void Client::SendLogsToSupervisor() {
351*ec63e07aSXin Li   // This LogSink will register itself and send all logs to the executor until
352*ec63e07aSXin Li   // the object is destroyed.
353*ec63e07aSXin Li   logsink_ = std::make_unique<LogSink>(GetMappedFD(LogSink::kLogFDName));
354*ec63e07aSXin Li }
355*ec63e07aSXin Li 
GetNetworkProxyClient()356*ec63e07aSXin Li NetworkProxyClient* Client::GetNetworkProxyClient() {
357*ec63e07aSXin Li   if (proxy_client_ == nullptr) {
358*ec63e07aSXin Li     proxy_client_ = std::make_unique<NetworkProxyClient>(
359*ec63e07aSXin Li         GetMappedFD(NetworkProxyClient::kFDName));
360*ec63e07aSXin Li   }
361*ec63e07aSXin Li   return proxy_client_.get();
362*ec63e07aSXin Li }
363*ec63e07aSXin Li 
InstallNetworkProxyHandler()364*ec63e07aSXin Li absl::Status Client::InstallNetworkProxyHandler() {
365*ec63e07aSXin Li   if (fd_map_.find(NetworkProxyClient::kFDName) == fd_map_.end()) {
366*ec63e07aSXin Li     return absl::FailedPreconditionError(
367*ec63e07aSXin Li         "InstallNetworkProxyHandler() must be called at most once after the "
368*ec63e07aSXin Li         "sandbox is installed. Also, the NetworkProxyServer needs to be "
369*ec63e07aSXin Li         "enabled.");
370*ec63e07aSXin Li   }
371*ec63e07aSXin Li   return NetworkProxyHandler::InstallNetworkProxyHandler(
372*ec63e07aSXin Li       GetNetworkProxyClient());
373*ec63e07aSXin Li }
374*ec63e07aSXin Li 
375*ec63e07aSXin Li }  // namespace sandbox2
376