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 of the sandbox2::ForkServer class.
16*ec63e07aSXin Li
17*ec63e07aSXin Li #include "sandboxed_api/sandbox2/forkserver.h"
18*ec63e07aSXin Li
19*ec63e07aSXin Li #include <fcntl.h>
20*ec63e07aSXin Li #include <linux/filter.h>
21*ec63e07aSXin Li #include <linux/seccomp.h>
22*ec63e07aSXin Li #include <sched.h>
23*ec63e07aSXin Li #include <sys/eventfd.h>
24*ec63e07aSXin Li #include <sys/prctl.h>
25*ec63e07aSXin Li #include <sys/resource.h>
26*ec63e07aSXin Li #include <sys/socket.h>
27*ec63e07aSXin Li #include <sys/uio.h>
28*ec63e07aSXin Li #include <sys/wait.h>
29*ec63e07aSXin Li #include <syscall.h>
30*ec63e07aSXin Li #include <unistd.h>
31*ec63e07aSXin Li
32*ec63e07aSXin Li #include <cerrno>
33*ec63e07aSXin Li #include <csignal>
34*ec63e07aSXin Li #include <cstdint>
35*ec63e07aSXin Li #include <cstdlib>
36*ec63e07aSXin Li #include <cstring>
37*ec63e07aSXin Li #include <fstream>
38*ec63e07aSXin Li #include <initializer_list>
39*ec63e07aSXin Li #include <string>
40*ec63e07aSXin Li #include <utility>
41*ec63e07aSXin Li #include <vector>
42*ec63e07aSXin Li
43*ec63e07aSXin Li #include "absl/base/attributes.h"
44*ec63e07aSXin Li #include "absl/container/flat_hash_map.h"
45*ec63e07aSXin Li #include "absl/container/flat_hash_set.h"
46*ec63e07aSXin Li #include "absl/status/status.h"
47*ec63e07aSXin Li #include "absl/status/statusor.h"
48*ec63e07aSXin Li #include "absl/strings/match.h"
49*ec63e07aSXin Li #include "absl/strings/str_cat.h"
50*ec63e07aSXin Li #include "absl/strings/str_join.h"
51*ec63e07aSXin Li #include "absl/strings/str_split.h"
52*ec63e07aSXin Li #include "absl/strings/string_view.h"
53*ec63e07aSXin Li #include "sys/capability.h" // AOSP: match libcap exported includes
54*ec63e07aSXin Li #include "sandboxed_api/sandbox2/client.h"
55*ec63e07aSXin Li #include "sandboxed_api/sandbox2/comms.h"
56*ec63e07aSXin Li #include "sandboxed_api/sandbox2/fork_client.h"
57*ec63e07aSXin Li #include "sandboxed_api/sandbox2/forkserver.pb.h"
58*ec63e07aSXin Li #include "sandboxed_api/sandbox2/namespace.h"
59*ec63e07aSXin Li #include "sandboxed_api/sandbox2/policy.h"
60*ec63e07aSXin Li #include "sandboxed_api/sandbox2/sanitizer.h"
61*ec63e07aSXin Li #include "sandboxed_api/sandbox2/syscall.h"
62*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util.h"
63*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util/bpf_helper.h"
64*ec63e07aSXin Li #include "sandboxed_api/util/fileops.h"
65*ec63e07aSXin Li #include "sandboxed_api/util/raw_logging.h"
66*ec63e07aSXin Li #include "sandboxed_api/util/strerror.h"
67*ec63e07aSXin Li
68*ec63e07aSXin Li namespace sandbox2 {
69*ec63e07aSXin Li namespace {
70*ec63e07aSXin Li
71*ec63e07aSXin Li using ::sapi::StrError;
72*ec63e07aSXin Li using ::sapi::file_util::fileops::FDCloser;
73*ec63e07aSXin Li
74*ec63e07aSXin Li // "Moves" FDs in move_fds from current to target FD number while keeping FDs
75*ec63e07aSXin Li // in keep_fds open - potentially moving them to another FD number as well in
76*ec63e07aSXin Li // case of colisions.
77*ec63e07aSXin Li // Ignores invalid (-1) fds.
MoveFDs(std::initializer_list<std::pair<int *,int>> move_fds,std::initializer_list<int * > keep_fds)78*ec63e07aSXin Li void MoveFDs(std::initializer_list<std::pair<int*, int>> move_fds,
79*ec63e07aSXin Li std::initializer_list<int*> keep_fds) {
80*ec63e07aSXin Li absl::flat_hash_map<int, int*> fd_map;
81*ec63e07aSXin Li for (int* fd : keep_fds) {
82*ec63e07aSXin Li if (*fd != -1) {
83*ec63e07aSXin Li fd_map.emplace(*fd, fd);
84*ec63e07aSXin Li }
85*ec63e07aSXin Li }
86*ec63e07aSXin Li
87*ec63e07aSXin Li for (auto [old_fd, new_fd] : move_fds) {
88*ec63e07aSXin Li if (*old_fd != -1) {
89*ec63e07aSXin Li fd_map.emplace(*old_fd, old_fd);
90*ec63e07aSXin Li }
91*ec63e07aSXin Li }
92*ec63e07aSXin Li
93*ec63e07aSXin Li for (auto [old_fd, new_fd] : move_fds) {
94*ec63e07aSXin Li if (*old_fd == -1 || *old_fd == new_fd) {
95*ec63e07aSXin Li continue;
96*ec63e07aSXin Li }
97*ec63e07aSXin Li
98*ec63e07aSXin Li // Make sure we won't override another fd
99*ec63e07aSXin Li if (auto it = fd_map.find(new_fd); it != fd_map.end()) {
100*ec63e07aSXin Li int fd = dup(new_fd);
101*ec63e07aSXin Li SAPI_RAW_CHECK(fd != -1, "Duplicating an FD failed.");
102*ec63e07aSXin Li *it->second = fd;
103*ec63e07aSXin Li fd_map.emplace(fd, it->second);
104*ec63e07aSXin Li fd_map.erase(it);
105*ec63e07aSXin Li }
106*ec63e07aSXin Li
107*ec63e07aSXin Li if (dup2(*old_fd, new_fd) == -1) {
108*ec63e07aSXin Li SAPI_RAW_PLOG(FATAL, "Moving temporary to proper FD failed.");
109*ec63e07aSXin Li }
110*ec63e07aSXin Li
111*ec63e07aSXin Li close(*old_fd);
112*ec63e07aSXin Li fd_map.erase(*old_fd);
113*ec63e07aSXin Li *old_fd = new_fd;
114*ec63e07aSXin Li }
115*ec63e07aSXin Li }
116*ec63e07aSXin Li
RunInitProcess(pid_t main_pid,FDCloser pipe_fd)117*ec63e07aSXin Li ABSL_ATTRIBUTE_NORETURN void RunInitProcess(pid_t main_pid, FDCloser pipe_fd) {
118*ec63e07aSXin Li if (prctl(PR_SET_NAME, "S2-INIT-PROC", 0, 0, 0) != 0) {
119*ec63e07aSXin Li SAPI_RAW_PLOG(WARNING, "prctl(PR_SET_NAME, 'S2-INIT-PROC')");
120*ec63e07aSXin Li }
121*ec63e07aSXin Li
122*ec63e07aSXin Li // Clear SA_NOCLDWAIT.
123*ec63e07aSXin Li struct sigaction sa;
124*ec63e07aSXin Li sa.sa_handler = SIG_DFL;
125*ec63e07aSXin Li sa.sa_flags = 0;
126*ec63e07aSXin Li sigemptyset(&sa.sa_mask);
127*ec63e07aSXin Li SAPI_RAW_CHECK(sigaction(SIGCHLD, &sa, nullptr) == 0,
128*ec63e07aSXin Li "clearing SA_NOCLDWAIT");
129*ec63e07aSXin Li
130*ec63e07aSXin Li // Apply seccomp.
131*ec63e07aSXin Li std::vector<sock_filter> code = {
132*ec63e07aSXin Li LOAD_ARCH,
133*ec63e07aSXin Li JNE32(sandbox2::Syscall::GetHostAuditArch(), DENY),
134*ec63e07aSXin Li
135*ec63e07aSXin Li LOAD_SYSCALL_NR,
136*ec63e07aSXin Li SYSCALL(__NR_waitid, ALLOW),
137*ec63e07aSXin Li SYSCALL(__NR_exit, ALLOW),
138*ec63e07aSXin Li };
139*ec63e07aSXin Li if (pipe_fd.get() >= 0) {
140*ec63e07aSXin Li code.insert(code.end(),
141*ec63e07aSXin Li {SYSCALL(__NR_getrusage, ALLOW), SYSCALL(__NR_write, ALLOW)});
142*ec63e07aSXin Li }
143*ec63e07aSXin Li code.push_back(DENY);
144*ec63e07aSXin Li
145*ec63e07aSXin Li struct sock_fprog prog {
146*ec63e07aSXin Li .len = static_cast<uint16_t>(code.size()), .filter = code.data(),
147*ec63e07aSXin Li };
148*ec63e07aSXin Li
149*ec63e07aSXin Li SAPI_RAW_CHECK(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == 0,
150*ec63e07aSXin Li "Denying new privs");
151*ec63e07aSXin Li SAPI_RAW_CHECK(prctl(PR_SET_KEEPCAPS, 0) == 0, "Dropping caps");
152*ec63e07aSXin Li SAPI_RAW_CHECK(
153*ec63e07aSXin Li syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC,
154*ec63e07aSXin Li reinterpret_cast<uintptr_t>(&prog)) == 0,
155*ec63e07aSXin Li "Enabling seccomp filter");
156*ec63e07aSXin Li
157*ec63e07aSXin Li siginfo_t info;
158*ec63e07aSXin Li // Reap children.
159*ec63e07aSXin Li for (;;) {
160*ec63e07aSXin Li int rv = TEMP_FAILURE_RETRY(waitid(P_ALL, -1, &info, WEXITED | __WALL));
161*ec63e07aSXin Li if (rv != 0) {
162*ec63e07aSXin Li _exit(1);
163*ec63e07aSXin Li }
164*ec63e07aSXin Li
165*ec63e07aSXin Li if (info.si_pid == main_pid) {
166*ec63e07aSXin Li if (pipe_fd.get() >= 0) {
167*ec63e07aSXin Li write(pipe_fd.get(), &info.si_code, sizeof(info.si_code));
168*ec63e07aSXin Li write(pipe_fd.get(), &info.si_status, sizeof(info.si_status));
169*ec63e07aSXin Li
170*ec63e07aSXin Li rusage usage{};
171*ec63e07aSXin Li getrusage(RUSAGE_CHILDREN, &usage);
172*ec63e07aSXin Li write(pipe_fd.get(), &usage, sizeof(usage));
173*ec63e07aSXin Li }
174*ec63e07aSXin Li _exit(0);
175*ec63e07aSXin Li }
176*ec63e07aSXin Li }
177*ec63e07aSXin Li }
178*ec63e07aSXin Li
SendPid(int signaling_fd)179*ec63e07aSXin Li absl::Status SendPid(int signaling_fd) {
180*ec63e07aSXin Li // Send our PID (the actual sandboxee process) via SCM_CREDENTIALS.
181*ec63e07aSXin Li // The ancillary message will be attached to the message as SO_PASSCRED is set
182*ec63e07aSXin Li // on the socket.
183*ec63e07aSXin Li char dummy = ' ';
184*ec63e07aSXin Li if (TEMP_FAILURE_RETRY(send(signaling_fd, &dummy, 1, 0)) != 1) {
185*ec63e07aSXin Li return absl::ErrnoToStatus(errno, "Sending PID: send()");
186*ec63e07aSXin Li }
187*ec63e07aSXin Li return absl::OkStatus();
188*ec63e07aSXin Li }
189*ec63e07aSXin Li
ReceivePid(int signaling_fd)190*ec63e07aSXin Li absl::StatusOr<pid_t> ReceivePid(int signaling_fd) {
191*ec63e07aSXin Li union {
192*ec63e07aSXin Li struct cmsghdr cmh;
193*ec63e07aSXin Li char ctrl[CMSG_SPACE(sizeof(struct ucred))];
194*ec63e07aSXin Li } ucred_msg{};
195*ec63e07aSXin Li
196*ec63e07aSXin Li struct msghdr msgh {};
197*ec63e07aSXin Li struct iovec iov {};
198*ec63e07aSXin Li
199*ec63e07aSXin Li msgh.msg_iov = &iov;
200*ec63e07aSXin Li msgh.msg_iovlen = 1;
201*ec63e07aSXin Li msgh.msg_control = ucred_msg.ctrl;
202*ec63e07aSXin Li msgh.msg_controllen = sizeof(ucred_msg);
203*ec63e07aSXin Li
204*ec63e07aSXin Li char dummy;
205*ec63e07aSXin Li iov.iov_base = &dummy;
206*ec63e07aSXin Li iov.iov_len = sizeof(char);
207*ec63e07aSXin Li
208*ec63e07aSXin Li if (TEMP_FAILURE_RETRY(recvmsg(signaling_fd, &msgh, MSG_WAITALL)) != 1) {
209*ec63e07aSXin Li return absl::ErrnoToStatus(errno, "Receiving pid failed: recvmsg");
210*ec63e07aSXin Li }
211*ec63e07aSXin Li struct cmsghdr* cmsgp = CMSG_FIRSTHDR(&msgh);
212*ec63e07aSXin Li if (cmsgp->cmsg_len != CMSG_LEN(sizeof(struct ucred)) ||
213*ec63e07aSXin Li cmsgp->cmsg_level != SOL_SOCKET || cmsgp->cmsg_type != SCM_CREDENTIALS) {
214*ec63e07aSXin Li return absl::InternalError("Receiving pid failed");
215*ec63e07aSXin Li }
216*ec63e07aSXin Li auto* ucredp = reinterpret_cast<struct ucred*>(CMSG_DATA(cmsgp));
217*ec63e07aSXin Li return ucredp->pid;
218*ec63e07aSXin Li }
219*ec63e07aSXin Li
GetRootMountId(const std::string & proc_id)220*ec63e07aSXin Li absl::StatusOr<std::string> GetRootMountId(const std::string& proc_id) {
221*ec63e07aSXin Li std::ifstream mounts(absl::StrCat("/proc/", proc_id, "/mountinfo"));
222*ec63e07aSXin Li if (!mounts.good()) {
223*ec63e07aSXin Li return absl::InternalError("Failed to open mountinfo");
224*ec63e07aSXin Li }
225*ec63e07aSXin Li std::string line;
226*ec63e07aSXin Li while (std::getline(mounts, line)) {
227*ec63e07aSXin Li std::vector<absl::string_view> parts =
228*ec63e07aSXin Li absl::StrSplit(line, absl::MaxSplits(' ', 4));
229*ec63e07aSXin Li if (parts.size() >= 4 && parts[3] == "/") {
230*ec63e07aSXin Li return std::string(parts[0]);
231*ec63e07aSXin Li }
232*ec63e07aSXin Li }
233*ec63e07aSXin Li return absl::NotFoundError("Root entry not found in mountinfo");
234*ec63e07aSXin Li }
235*ec63e07aSXin Li
IsLikelyChrooted()236*ec63e07aSXin Li bool IsLikelyChrooted() {
237*ec63e07aSXin Li absl::StatusOr<std::string> self_root_id = GetRootMountId("self");
238*ec63e07aSXin Li if (!self_root_id.ok()) {
239*ec63e07aSXin Li return absl::IsNotFound(self_root_id.status());
240*ec63e07aSXin Li }
241*ec63e07aSXin Li absl::StatusOr<std::string> init_root_id = GetRootMountId("1");
242*ec63e07aSXin Li if (!init_root_id.ok()) {
243*ec63e07aSXin Li return false;
244*ec63e07aSXin Li }
245*ec63e07aSXin Li return *self_root_id != *init_root_id;
246*ec63e07aSXin Li }
247*ec63e07aSXin Li
248*ec63e07aSXin Li } // namespace
249*ec63e07aSXin Li
PrepareExecveArgs(const ForkRequest & request,std::vector<std::string> * args,std::vector<std::string> * envp)250*ec63e07aSXin Li void ForkServer::PrepareExecveArgs(const ForkRequest& request,
251*ec63e07aSXin Li std::vector<std::string>* args,
252*ec63e07aSXin Li std::vector<std::string>* envp) {
253*ec63e07aSXin Li // Prepare arguments for execve.
254*ec63e07aSXin Li for (const auto& arg : request.args()) {
255*ec63e07aSXin Li args->push_back(arg);
256*ec63e07aSXin Li }
257*ec63e07aSXin Li
258*ec63e07aSXin Li // Prepare environment variables for execve.
259*ec63e07aSXin Li for (const auto& env : request.envs()) {
260*ec63e07aSXin Li envp->push_back(env);
261*ec63e07aSXin Li }
262*ec63e07aSXin Li
263*ec63e07aSXin Li // The child process should not start any fork-servers.
264*ec63e07aSXin Li envp->push_back(absl::StrCat(kForkServerDisableEnv, "=1"));
265*ec63e07aSXin Li
266*ec63e07aSXin Li constexpr char kSapiVlogLevel[] = "SAPI_VLOG_LEVEL";
267*ec63e07aSXin Li char* sapi_vlog = getenv(kSapiVlogLevel);
268*ec63e07aSXin Li if (sapi_vlog && strlen(sapi_vlog) > 0) {
269*ec63e07aSXin Li envp->push_back(absl::StrCat(kSapiVlogLevel, "=", sapi_vlog));
270*ec63e07aSXin Li }
271*ec63e07aSXin Li
272*ec63e07aSXin Li SAPI_RAW_VLOG(1, "Will execute args:['%s'], environment:['%s']",
273*ec63e07aSXin Li absl::StrJoin(*args, "', '").c_str(),
274*ec63e07aSXin Li absl::StrJoin(*envp, "', '").c_str());
275*ec63e07aSXin Li }
276*ec63e07aSXin Li
LaunchChild(const ForkRequest & request,int execve_fd,uid_t uid,gid_t gid,FDCloser signaling_fd,FDCloser status_fd,bool avoid_pivot_root) const277*ec63e07aSXin Li void ForkServer::LaunchChild(const ForkRequest& request, int execve_fd,
278*ec63e07aSXin Li uid_t uid, gid_t gid, FDCloser signaling_fd,
279*ec63e07aSXin Li FDCloser status_fd, bool avoid_pivot_root) const {
280*ec63e07aSXin Li SAPI_RAW_CHECK(request.mode() != FORKSERVER_FORK_UNSPECIFIED,
281*ec63e07aSXin Li "Forkserver mode is unspecified");
282*ec63e07aSXin Li
283*ec63e07aSXin Li const bool will_execve = execve_fd != -1;
284*ec63e07aSXin Li const bool should_sandbox = request.mode() == FORKSERVER_FORK_EXECVE_SANDBOX;
285*ec63e07aSXin Li
286*ec63e07aSXin Li absl::StatusOr<absl::flat_hash_set<int>> open_fds = sanitizer::GetListOfFDs();
287*ec63e07aSXin Li if (!open_fds.ok()) {
288*ec63e07aSXin Li SAPI_RAW_LOG(WARNING, "Could not get list of current open FDs: %s",
289*ec63e07aSXin Li std::string(open_fds.status().message()).c_str());
290*ec63e07aSXin Li open_fds = absl::flat_hash_set<int>();
291*ec63e07aSXin Li }
292*ec63e07aSXin Li SanitizeEnvironment();
293*ec63e07aSXin Li
294*ec63e07aSXin Li InitializeNamespaces(request, uid, gid, avoid_pivot_root);
295*ec63e07aSXin Li
296*ec63e07aSXin Li auto caps = cap_init();
297*ec63e07aSXin Li SAPI_RAW_CHECK(cap_set_proc(caps) == 0, "while dropping capabilities");
298*ec63e07aSXin Li cap_free(caps);
299*ec63e07aSXin Li
300*ec63e07aSXin Li // A custom init process is only needed if a new PID NS is created.
301*ec63e07aSXin Li if (request.clone_flags() & CLONE_NEWPID) {
302*ec63e07aSXin Li // Spawn a child process
303*ec63e07aSXin Li pid_t child = util::ForkWithFlags(SIGCHLD);
304*ec63e07aSXin Li if (child < 0) {
305*ec63e07aSXin Li SAPI_RAW_PLOG(FATAL, "Could not spawn init process");
306*ec63e07aSXin Li }
307*ec63e07aSXin Li if (child != 0) {
308*ec63e07aSXin Li if (status_fd.get() >= 0) {
309*ec63e07aSXin Li open_fds->erase(status_fd.get());
310*ec63e07aSXin Li }
311*ec63e07aSXin Li // Close all open fds (equals to CloseAllFDsExcept but does not require
312*ec63e07aSXin Li // /proc to be available).
313*ec63e07aSXin Li for (const auto& fd : *open_fds) {
314*ec63e07aSXin Li close(fd);
315*ec63e07aSXin Li }
316*ec63e07aSXin Li RunInitProcess(child, std::move(status_fd));
317*ec63e07aSXin Li }
318*ec63e07aSXin Li // Send sandboxee pid
319*ec63e07aSXin Li auto status = SendPid(signaling_fd.get());
320*ec63e07aSXin Li SAPI_RAW_CHECK(status.ok(),
321*ec63e07aSXin Li absl::StrCat("sending pid: ", status.message()).c_str());
322*ec63e07aSXin Li }
323*ec63e07aSXin Li signaling_fd.Close();
324*ec63e07aSXin Li status_fd.Close();
325*ec63e07aSXin Li
326*ec63e07aSXin Li Client c(comms_);
327*ec63e07aSXin Li
328*ec63e07aSXin Li // Prepare the arguments before sandboxing (if needed), as doing it after
329*ec63e07aSXin Li // sandoxing can cause syscall violations (e.g. related to memory management).
330*ec63e07aSXin Li std::vector<std::string> args;
331*ec63e07aSXin Li std::vector<std::string> envs;
332*ec63e07aSXin Li if (will_execve) {
333*ec63e07aSXin Li PrepareExecveArgs(request, &args, &envs);
334*ec63e07aSXin Li }
335*ec63e07aSXin Li
336*ec63e07aSXin Li // Sandboxing can be enabled either here - just before execve, or somewhere
337*ec63e07aSXin Li // inside the executed binary (e.g. after basic structures have been
338*ec63e07aSXin Li // initialized, and resources acquired). In the latter case, it's up to the
339*ec63e07aSXin Li // sandboxed binary to establish proper Comms channel (using
340*ec63e07aSXin Li // Comms::kSandbox2ClientCommsFD) and call sandbox2::Client::SandboxMeHere()
341*ec63e07aSXin Li if (should_sandbox) {
342*ec63e07aSXin Li // The following client calls are basically SandboxMeHere. We split it so
343*ec63e07aSXin Li // that we can set up the envp after we received the file descriptors but
344*ec63e07aSXin Li // before we enable the syscall filter.
345*ec63e07aSXin Li c.PrepareEnvironment(&execve_fd);
346*ec63e07aSXin Li if (comms_->GetConnectionFD() != Comms::kSandbox2ClientCommsFD) {
347*ec63e07aSXin Li envs.push_back(absl::StrCat(Comms::kSandbox2CommsFDEnvVar, "=",
348*ec63e07aSXin Li comms_->GetConnectionFD()));
349*ec63e07aSXin Li }
350*ec63e07aSXin Li envs.push_back(c.GetFdMapEnvVar());
351*ec63e07aSXin Li }
352*ec63e07aSXin Li
353*ec63e07aSXin Li // Convert args and envs before enabling sandbox (it'll allocate which might
354*ec63e07aSXin Li // be blocked).
355*ec63e07aSXin Li util::CharPtrArray argv = util::CharPtrArray::FromStringVector(args);
356*ec63e07aSXin Li util::CharPtrArray envp = util::CharPtrArray::FromStringVector(envs);
357*ec63e07aSXin Li
358*ec63e07aSXin Li if (should_sandbox) {
359*ec63e07aSXin Li c.EnableSandbox();
360*ec63e07aSXin Li }
361*ec63e07aSXin Li
362*ec63e07aSXin Li if (will_execve) {
363*ec63e07aSXin Li ExecuteProcess(execve_fd, argv.data(), envp.data());
364*ec63e07aSXin Li }
365*ec63e07aSXin Li }
366*ec63e07aSXin Li
ServeRequest()367*ec63e07aSXin Li pid_t ForkServer::ServeRequest() {
368*ec63e07aSXin Li ForkRequest fork_request;
369*ec63e07aSXin Li if (!comms_->RecvProtoBuf(&fork_request)) {
370*ec63e07aSXin Li if (comms_->IsTerminated()) {
371*ec63e07aSXin Li return -1;
372*ec63e07aSXin Li }
373*ec63e07aSXin Li SAPI_RAW_LOG(FATAL, "Failed to receive ForkServer request");
374*ec63e07aSXin Li }
375*ec63e07aSXin Li int comms_fd;
376*ec63e07aSXin Li SAPI_RAW_CHECK(comms_->RecvFD(&comms_fd), "Failed to receive Comms FD");
377*ec63e07aSXin Li
378*ec63e07aSXin Li SAPI_RAW_CHECK(fork_request.mode() != FORKSERVER_FORK_UNSPECIFIED,
379*ec63e07aSXin Li "Forkserver mode is unspecified");
380*ec63e07aSXin Li
381*ec63e07aSXin Li int exec_fd = -1;
382*ec63e07aSXin Li if (fork_request.mode() == FORKSERVER_FORK_EXECVE ||
383*ec63e07aSXin Li fork_request.mode() == FORKSERVER_FORK_EXECVE_SANDBOX) {
384*ec63e07aSXin Li SAPI_RAW_CHECK(comms_->RecvFD(&exec_fd), "Failed to receive Exec FD");
385*ec63e07aSXin Li }
386*ec63e07aSXin Li
387*ec63e07aSXin Li // Make the kernel notify us with SIGCHLD when the process terminates.
388*ec63e07aSXin Li // We use sigaction(SIGCHLD, flags=SA_NOCLDWAIT) in combination with
389*ec63e07aSXin Li // this to make sure the zombie process is reaped immediately.
390*ec63e07aSXin Li int clone_flags = fork_request.clone_flags() | SIGCHLD;
391*ec63e07aSXin Li
392*ec63e07aSXin Li // Store uid and gid since they will change if CLONE_NEWUSER is set.
393*ec63e07aSXin Li uid_t uid = getuid();
394*ec63e07aSXin Li uid_t gid = getgid();
395*ec63e07aSXin Li
396*ec63e07aSXin Li FDCloser pipe_fds[2];
397*ec63e07aSXin Li {
398*ec63e07aSXin Li int pfds[2] = {-1, -1};
399*ec63e07aSXin Li if (fork_request.monitor_type() == FORKSERVER_MONITOR_UNOTIFY) {
400*ec63e07aSXin Li SAPI_RAW_PCHECK(pipe(pfds) == 0, "creating status pipe");
401*ec63e07aSXin Li }
402*ec63e07aSXin Li pipe_fds[0] = FDCloser(pfds[0]);
403*ec63e07aSXin Li pipe_fds[1] = FDCloser(pfds[1]);
404*ec63e07aSXin Li }
405*ec63e07aSXin Li
406*ec63e07aSXin Li int socketpair_fds[2];
407*ec63e07aSXin Li SAPI_RAW_PCHECK(
408*ec63e07aSXin Li socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, socketpair_fds) == 0,
409*ec63e07aSXin Li "creating signaling socketpair");
410*ec63e07aSXin Li for (int i = 0; i < 2; i++) {
411*ec63e07aSXin Li int val = 1;
412*ec63e07aSXin Li SAPI_RAW_PCHECK(setsockopt(socketpair_fds[i], SOL_SOCKET, SO_PASSCRED, &val,
413*ec63e07aSXin Li sizeof(val)) == 0,
414*ec63e07aSXin Li "setsockopt failed");
415*ec63e07aSXin Li }
416*ec63e07aSXin Li
417*ec63e07aSXin Li FDCloser signaling_fds[] = {FDCloser(socketpair_fds[0]),
418*ec63e07aSXin Li FDCloser(socketpair_fds[1])};
419*ec63e07aSXin Li
420*ec63e07aSXin Li // Note: init_pid will be overwritten with the actual init pid if the init
421*ec63e07aSXin Li // process was started or stays at 0 if that is not needed - no pidns.
422*ec63e07aSXin Li pid_t init_pid = 0;
423*ec63e07aSXin Li pid_t sandboxee_pid = -1;
424*ec63e07aSXin Li bool avoid_pivot_root = clone_flags & (CLONE_NEWUSER | CLONE_NEWNS);
425*ec63e07aSXin Li if (avoid_pivot_root) {
426*ec63e07aSXin Li // Create initial namespaces only when they're first needed.
427*ec63e07aSXin Li // This allows sandbox2 to be still used without any namespaces support
428*ec63e07aSXin Li if (initial_mntns_fd_ == -1) {
429*ec63e07aSXin Li CreateInitialNamespaces();
430*ec63e07aSXin Li }
431*ec63e07aSXin Li // We first just fork a child, which will join the initial namespaces
432*ec63e07aSXin Li // Note: Not a regular fork() as one really needs to be single-threaded to
433*ec63e07aSXin Li // setns and this is not the case with TSAN.
434*ec63e07aSXin Li pid_t pid = util::ForkWithFlags(SIGCHLD);
435*ec63e07aSXin Li SAPI_RAW_PCHECK(pid != -1, "fork failed");
436*ec63e07aSXin Li if (pid == 0) {
437*ec63e07aSXin Li SAPI_RAW_PCHECK(setns(initial_userns_fd_, CLONE_NEWUSER) != -1,
438*ec63e07aSXin Li "joining initial user namespace");
439*ec63e07aSXin Li SAPI_RAW_PCHECK(setns(initial_mntns_fd_, CLONE_NEWNS) != -1,
440*ec63e07aSXin Li "joining initial mnt namespace");
441*ec63e07aSXin Li close(initial_userns_fd_);
442*ec63e07aSXin Li close(initial_mntns_fd_);
443*ec63e07aSXin Li // Do not create new userns it will be unshared later
444*ec63e07aSXin Li sandboxee_pid =
445*ec63e07aSXin Li util::ForkWithFlags((clone_flags & ~CLONE_NEWUSER) | CLONE_PARENT);
446*ec63e07aSXin Li if (sandboxee_pid == -1) {
447*ec63e07aSXin Li SAPI_RAW_LOG(ERROR, "util::ForkWithFlags(%x)", clone_flags);
448*ec63e07aSXin Li }
449*ec63e07aSXin Li if (sandboxee_pid != 0) {
450*ec63e07aSXin Li _exit(0);
451*ec63e07aSXin Li }
452*ec63e07aSXin Li // Send sandboxee pid
453*ec63e07aSXin Li absl::Status status = SendPid(signaling_fds[1].get());
454*ec63e07aSXin Li SAPI_RAW_CHECK(status.ok(),
455*ec63e07aSXin Li absl::StrCat("sending pid: ", status.message()).c_str());
456*ec63e07aSXin Li }
457*ec63e07aSXin Li } else {
458*ec63e07aSXin Li sandboxee_pid = util::ForkWithFlags(clone_flags);
459*ec63e07aSXin Li if (sandboxee_pid == -1) {
460*ec63e07aSXin Li SAPI_RAW_LOG(ERROR, "util::ForkWithFlags(%x)", clone_flags);
461*ec63e07aSXin Li }
462*ec63e07aSXin Li if (sandboxee_pid == 0) {
463*ec63e07aSXin Li close(initial_userns_fd_);
464*ec63e07aSXin Li close(initial_mntns_fd_);
465*ec63e07aSXin Li }
466*ec63e07aSXin Li }
467*ec63e07aSXin Li
468*ec63e07aSXin Li // Child.
469*ec63e07aSXin Li if (sandboxee_pid == 0) {
470*ec63e07aSXin Li signaling_fds[0].Close();
471*ec63e07aSXin Li pipe_fds[0].Close();
472*ec63e07aSXin Li // Make sure we override the forkserver's comms fd
473*ec63e07aSXin Li comms_->Terminate();
474*ec63e07aSXin Li if (exec_fd != -1) {
475*ec63e07aSXin Li int signaling_fd = signaling_fds[1].Release();
476*ec63e07aSXin Li int pipe_fd = pipe_fds[1].Release();
477*ec63e07aSXin Li MoveFDs({{&exec_fd, Comms::kSandbox2TargetExecFD},
478*ec63e07aSXin Li {&comms_fd, Comms::kSandbox2ClientCommsFD}},
479*ec63e07aSXin Li {&signaling_fd, &pipe_fd});
480*ec63e07aSXin Li signaling_fds[1] = FDCloser(signaling_fd);
481*ec63e07aSXin Li pipe_fds[1] = FDCloser(pipe_fd);
482*ec63e07aSXin Li }
483*ec63e07aSXin Li *comms_ = Comms(comms_fd);
484*ec63e07aSXin Li LaunchChild(fork_request, exec_fd, uid, gid, std::move(signaling_fds[1]),
485*ec63e07aSXin Li std::move(pipe_fds[1]), avoid_pivot_root);
486*ec63e07aSXin Li return sandboxee_pid;
487*ec63e07aSXin Li }
488*ec63e07aSXin Li
489*ec63e07aSXin Li signaling_fds[1].Close();
490*ec63e07aSXin Li
491*ec63e07aSXin Li if (avoid_pivot_root) {
492*ec63e07aSXin Li if (auto pid = ReceivePid(signaling_fds[0].get()); !pid.ok()) {
493*ec63e07aSXin Li SAPI_RAW_LOG(ERROR, "%s", std::string(pid.status().message()).c_str());
494*ec63e07aSXin Li } else {
495*ec63e07aSXin Li sandboxee_pid = pid.value();
496*ec63e07aSXin Li }
497*ec63e07aSXin Li }
498*ec63e07aSXin Li
499*ec63e07aSXin Li if (fork_request.clone_flags() & CLONE_NEWPID) {
500*ec63e07aSXin Li // The pid of the init process is equal to the child process that we've
501*ec63e07aSXin Li // previously forked.
502*ec63e07aSXin Li init_pid = sandboxee_pid;
503*ec63e07aSXin Li sandboxee_pid = -1;
504*ec63e07aSXin Li // And the actual sandboxee is forked from the init process, so we need to
505*ec63e07aSXin Li // receive the actual PID.
506*ec63e07aSXin Li if (auto pid_or = ReceivePid(signaling_fds[0].get()); !pid_or.ok()) {
507*ec63e07aSXin Li SAPI_RAW_LOG(ERROR, "%s", std::string(pid_or.status().message()).c_str());
508*ec63e07aSXin Li if (init_pid != -1) {
509*ec63e07aSXin Li kill(init_pid, SIGKILL);
510*ec63e07aSXin Li }
511*ec63e07aSXin Li init_pid = -1;
512*ec63e07aSXin Li } else {
513*ec63e07aSXin Li sandboxee_pid = pid_or.value();
514*ec63e07aSXin Li }
515*ec63e07aSXin Li }
516*ec63e07aSXin Li
517*ec63e07aSXin Li // Parent.
518*ec63e07aSXin Li pipe_fds[1].Close();
519*ec63e07aSXin Li close(comms_fd);
520*ec63e07aSXin Li if (exec_fd >= 0) {
521*ec63e07aSXin Li close(exec_fd);
522*ec63e07aSXin Li }
523*ec63e07aSXin Li SAPI_RAW_CHECK(comms_->SendInt32(init_pid),
524*ec63e07aSXin Li absl::StrCat("Failed to send init PID: ", init_pid).c_str());
525*ec63e07aSXin Li SAPI_RAW_CHECK(
526*ec63e07aSXin Li comms_->SendInt32(sandboxee_pid),
527*ec63e07aSXin Li absl::StrCat("Failed to send sandboxee PID: ", sandboxee_pid).c_str());
528*ec63e07aSXin Li
529*ec63e07aSXin Li if (pipe_fds[0].get() >= 0) {
530*ec63e07aSXin Li SAPI_RAW_CHECK(comms_->SendFD(pipe_fds[0].get()),
531*ec63e07aSXin Li "Failed to send status pipe");
532*ec63e07aSXin Li }
533*ec63e07aSXin Li return sandboxee_pid;
534*ec63e07aSXin Li }
535*ec63e07aSXin Li
IsTerminated() const536*ec63e07aSXin Li bool ForkServer::IsTerminated() const { return comms_->IsTerminated(); }
537*ec63e07aSXin Li
Initialize()538*ec63e07aSXin Li bool ForkServer::Initialize() {
539*ec63e07aSXin Li // For safety drop as many capabilities as possible.
540*ec63e07aSXin Li // Note that cap_t is actually a pointer.
541*ec63e07aSXin Li cap_t have_caps = cap_get_proc(); // caps we currently have
542*ec63e07aSXin Li SAPI_RAW_CHECK(have_caps, "failed to cap_get_proc()");
543*ec63e07aSXin Li cap_t wanted_caps = cap_init(); // starts as empty set, ie. no caps
544*ec63e07aSXin Li SAPI_RAW_CHECK(wanted_caps, "failed to cap_init()");
545*ec63e07aSXin Li
546*ec63e07aSXin Li // CAP_SYS_PTRACE appears to be needed for apparmor (or possibly yama)
547*ec63e07aSXin Li // CAP_SETFCAP is needed on newer kernels (5.10 needs it, 4.15 does not)
548*ec63e07aSXin Li for (cap_value_t cap : {CAP_SYS_PTRACE, CAP_SETFCAP}) {
549*ec63e07aSXin Li for (cap_flag_t flag : {CAP_EFFECTIVE, CAP_PERMITTED}) {
550*ec63e07aSXin Li cap_flag_value_t value;
551*ec63e07aSXin Li int rc = cap_get_flag(have_caps, cap, flag, &value);
552*ec63e07aSXin Li SAPI_RAW_CHECK(!rc, "cap_get_flag");
553*ec63e07aSXin Li if (value == CAP_SET) {
554*ec63e07aSXin Li cap_value_t caps_to_set[1] = {
555*ec63e07aSXin Li cap,
556*ec63e07aSXin Li };
557*ec63e07aSXin Li rc = cap_set_flag(wanted_caps, flag, 1, caps_to_set, CAP_SET);
558*ec63e07aSXin Li SAPI_RAW_CHECK(!rc, "cap_set_flag");
559*ec63e07aSXin Li }
560*ec63e07aSXin Li }
561*ec63e07aSXin Li }
562*ec63e07aSXin Li
563*ec63e07aSXin Li SAPI_RAW_CHECK(!cap_set_proc(wanted_caps), "while dropping capabilities");
564*ec63e07aSXin Li SAPI_RAW_CHECK(!cap_free(wanted_caps), "while freeing wanted_caps");
565*ec63e07aSXin Li SAPI_RAW_CHECK(!cap_free(have_caps), "while freeing have_caps");
566*ec63e07aSXin Li
567*ec63e07aSXin Li // All processes spawned by the fork'd/execute'd process will see this process
568*ec63e07aSXin Li // as /sbin/init. Therefore it will receive (and ignore) their final status
569*ec63e07aSXin Li // (see the next comment as well). PR_SET_CHILD_SUBREAPER is available since
570*ec63e07aSXin Li // kernel version 3.4, so don't panic if it fails.
571*ec63e07aSXin Li if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0) == -1) {
572*ec63e07aSXin Li SAPI_RAW_VLOG(3, "prctl(PR_SET_CHILD_SUBREAPER, 1): %s [%d]",
573*ec63e07aSXin Li StrError(errno).c_str(), errno);
574*ec63e07aSXin Li }
575*ec63e07aSXin Li
576*ec63e07aSXin Li // Don't convert terminated child processes into zombies. It's up to the
577*ec63e07aSXin Li // sandbox (Monitor) to track them and receive/report their final status.
578*ec63e07aSXin Li struct sigaction sa;
579*ec63e07aSXin Li sa.sa_handler = SIG_DFL;
580*ec63e07aSXin Li sa.sa_flags = SA_NOCLDWAIT;
581*ec63e07aSXin Li sigemptyset(&sa.sa_mask);
582*ec63e07aSXin Li if (sigaction(SIGCHLD, &sa, nullptr) == -1) {
583*ec63e07aSXin Li SAPI_RAW_PLOG(ERROR, "sigaction(SIGCHLD, flags=SA_NOCLDWAIT)");
584*ec63e07aSXin Li return false;
585*ec63e07aSXin Li }
586*ec63e07aSXin Li return true;
587*ec63e07aSXin Li }
588*ec63e07aSXin Li
CreateInitialNamespaces()589*ec63e07aSXin Li void ForkServer::CreateInitialNamespaces() {
590*ec63e07aSXin Li // Spawn a new process to create initial user and mount namespaces to be used
591*ec63e07aSXin Li // as a base for each namespaced sandboxee.
592*ec63e07aSXin Li
593*ec63e07aSXin Li // Store uid and gid to create mappings after CLONE_NEWUSER
594*ec63e07aSXin Li uid_t uid = getuid();
595*ec63e07aSXin Li gid_t gid = getgid();
596*ec63e07aSXin Li
597*ec63e07aSXin Li // Socket to synchronize so that we open ns fds before process dies
598*ec63e07aSXin Li FDCloser create_efd(eventfd(0, EFD_CLOEXEC));
599*ec63e07aSXin Li SAPI_RAW_PCHECK(create_efd.get() != -1, "creating eventfd");
600*ec63e07aSXin Li FDCloser open_efd(eventfd(0, EFD_CLOEXEC));
601*ec63e07aSXin Li SAPI_RAW_PCHECK(open_efd.get() != -1, "creating eventfd");
602*ec63e07aSXin Li pid_t pid = util::ForkWithFlags(CLONE_NEWUSER | CLONE_NEWNS | SIGCHLD);
603*ec63e07aSXin Li if (pid == -1 && errno == EPERM && IsLikelyChrooted()) {
604*ec63e07aSXin Li SAPI_RAW_LOG(FATAL,
605*ec63e07aSXin Li "failed to fork initial namespaces process: parent process is "
606*ec63e07aSXin Li "likely chrooted");
607*ec63e07aSXin Li }
608*ec63e07aSXin Li SAPI_RAW_PCHECK(pid != -1, "failed to fork initial namespaces process");
609*ec63e07aSXin Li uint64_t value = 1;
610*ec63e07aSXin Li if (pid == 0) {
611*ec63e07aSXin Li Namespace::InitializeInitialNamespaces(uid, gid);
612*ec63e07aSXin Li SAPI_RAW_PCHECK(TEMP_FAILURE_RETRY(write(create_efd.get(), &value,
613*ec63e07aSXin Li sizeof(value))) == sizeof(value),
614*ec63e07aSXin Li "synchronizing initial namespaces creation");
615*ec63e07aSXin Li SAPI_RAW_PCHECK(TEMP_FAILURE_RETRY(read(open_efd.get(), &value,
616*ec63e07aSXin Li sizeof(value))) == sizeof(value),
617*ec63e07aSXin Li "synchronizing initial namespaces creation");
618*ec63e07aSXin Li SAPI_RAW_PCHECK(chroot("/realroot") == 0,
619*ec63e07aSXin Li "chrooting prior to dumping coverage");
620*ec63e07aSXin Li util::DumpCoverageData();
621*ec63e07aSXin Li _exit(0);
622*ec63e07aSXin Li }
623*ec63e07aSXin Li SAPI_RAW_PCHECK(TEMP_FAILURE_RETRY(read(create_efd.get(), &value,
624*ec63e07aSXin Li sizeof(value))) == sizeof(value),
625*ec63e07aSXin Li "synchronizing initial namespaces creation");
626*ec63e07aSXin Li initial_userns_fd_ = open(absl::StrCat("/proc/", pid, "/ns/user").c_str(),
627*ec63e07aSXin Li O_RDONLY | O_CLOEXEC);
628*ec63e07aSXin Li SAPI_RAW_PCHECK(initial_userns_fd_ != -1, "getting initial userns fd");
629*ec63e07aSXin Li initial_mntns_fd_ = open(absl::StrCat("/proc/", pid, "/ns/mnt").c_str(),
630*ec63e07aSXin Li O_RDONLY | O_CLOEXEC);
631*ec63e07aSXin Li SAPI_RAW_PCHECK(initial_mntns_fd_ != -1, "getting initial mntns fd");
632*ec63e07aSXin Li SAPI_RAW_PCHECK(TEMP_FAILURE_RETRY(write(open_efd.get(), &value,
633*ec63e07aSXin Li sizeof(value))) == sizeof(value),
634*ec63e07aSXin Li "synchronizing initial namespaces creation");
635*ec63e07aSXin Li }
636*ec63e07aSXin Li
SanitizeEnvironment() const637*ec63e07aSXin Li void ForkServer::SanitizeEnvironment() const {
638*ec63e07aSXin Li // Mark all file descriptors, except the standard ones (needed
639*ec63e07aSXin Li // for proper sandboxed process operations), as close-on-exec.
640*ec63e07aSXin Li absl::Status status = sanitizer::SanitizeCurrentProcess(
641*ec63e07aSXin Li {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, comms_->GetConnectionFD()},
642*ec63e07aSXin Li /* close_fds = */ false);
643*ec63e07aSXin Li SAPI_RAW_CHECK(
644*ec63e07aSXin Li status.ok(),
645*ec63e07aSXin Li absl::StrCat("while sanitizing process: ", status.message()).c_str());
646*ec63e07aSXin Li }
647*ec63e07aSXin Li
ExecuteProcess(int execve_fd,const char * const * argv,const char * const * envp)648*ec63e07aSXin Li void ForkServer::ExecuteProcess(int execve_fd, const char* const* argv,
649*ec63e07aSXin Li const char* const* envp) {
650*ec63e07aSXin Li // Do not add any code before execve(), as it's subject to seccomp policies.
651*ec63e07aSXin Li // Indicate that it's a special execve(), by setting 4th, 5th and 6th syscall
652*ec63e07aSXin Li // argument to magic values.
653*ec63e07aSXin Li util::Execveat(execve_fd, "", argv, envp, AT_EMPTY_PATH,
654*ec63e07aSXin Li internal::kExecveMagic);
655*ec63e07aSXin Li
656*ec63e07aSXin Li int saved_errno = errno;
657*ec63e07aSXin Li SAPI_RAW_PLOG(ERROR, "execveat failed");
658*ec63e07aSXin Li if (argv[0]) {
659*ec63e07aSXin Li SAPI_RAW_LOG(ERROR, "argv[0]=%s", argv[0]);
660*ec63e07aSXin Li }
661*ec63e07aSXin Li
662*ec63e07aSXin Li if (saved_errno == ENOSYS) {
663*ec63e07aSXin Li SAPI_RAW_LOG(ERROR,
664*ec63e07aSXin Li "This is likely caused by running on a kernel that is too old."
665*ec63e07aSXin Li );
666*ec63e07aSXin Li } else if (saved_errno == ENOENT && execve_fd >= 0) {
667*ec63e07aSXin Li // Since we know the file exists, it must be that the file is dynamically
668*ec63e07aSXin Li // linked and the ELF interpreter is what's actually missing.
669*ec63e07aSXin Li SAPI_RAW_LOG(
670*ec63e07aSXin Li ERROR,
671*ec63e07aSXin Li "This is likely caused by running dynamically-linked sandboxee without "
672*ec63e07aSXin Li "calling .AddLibrariesForBinary() on the policy builder.");
673*ec63e07aSXin Li }
674*ec63e07aSXin Li
675*ec63e07aSXin Li util::Syscall(__NR_exit_group, EXIT_FAILURE);
676*ec63e07aSXin Li abort();
677*ec63e07aSXin Li }
678*ec63e07aSXin Li
InitializeNamespaces(const ForkRequest & request,uid_t uid,gid_t gid,bool avoid_pivot_root)679*ec63e07aSXin Li void ForkServer::InitializeNamespaces(const ForkRequest& request, uid_t uid,
680*ec63e07aSXin Li gid_t gid, bool avoid_pivot_root) {
681*ec63e07aSXin Li if (!request.has_mount_tree()) {
682*ec63e07aSXin Li return;
683*ec63e07aSXin Li }
684*ec63e07aSXin Li Namespace::InitializeNamespaces(
685*ec63e07aSXin Li uid, gid, request.clone_flags(), Mounts(request.mount_tree()),
686*ec63e07aSXin Li request.hostname(), avoid_pivot_root, request.allow_mount_propagation());
687*ec63e07aSXin Li }
688*ec63e07aSXin Li
689*ec63e07aSXin Li } // namespace sandbox2
690