xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/sandbox2/executor.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 of the sandbox2::Executor class
16*ec63e07aSXin Li 
17*ec63e07aSXin Li #include "sandboxed_api/sandbox2/executor.h"
18*ec63e07aSXin Li 
19*ec63e07aSXin Li #include <fcntl.h>
20*ec63e07aSXin Li #include <sys/socket.h>
21*ec63e07aSXin Li #include <unistd.h>
22*ec63e07aSXin Li 
23*ec63e07aSXin Li #include <algorithm>
24*ec63e07aSXin Li #include <cerrno>
25*ec63e07aSXin Li #include <cstdint>
26*ec63e07aSXin Li #include <memory>
27*ec63e07aSXin Li #include <string>
28*ec63e07aSXin Li #include <vector>
29*ec63e07aSXin Li 
30*ec63e07aSXin Li #include "absl/log/log.h"
31*ec63e07aSXin Li #include "absl/status/status.h"
32*ec63e07aSXin Li #include "absl/status/statusor.h"
33*ec63e07aSXin Li #include "absl/strings/match.h"
34*ec63e07aSXin Li #include "absl/strings/str_cat.h"
35*ec63e07aSXin Li #include "absl/strings/string_view.h"
36*ec63e07aSXin Li #include "sandboxed_api/config.h"
37*ec63e07aSXin Li #include "sandboxed_api/sandbox2/fork_client.h"
38*ec63e07aSXin Li #include "sandboxed_api/sandbox2/forkserver.pb.h"
39*ec63e07aSXin Li #include "sandboxed_api/sandbox2/global_forkclient.h"
40*ec63e07aSXin Li #include "sandboxed_api/sandbox2/ipc.h"
41*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util.h"
42*ec63e07aSXin Li #include "sandboxed_api/util/fileops.h"
43*ec63e07aSXin Li #include "sandboxed_api/util/raw_logging.h"
44*ec63e07aSXin Li 
45*ec63e07aSXin Li namespace sandbox2 {
46*ec63e07aSXin Li 
47*ec63e07aSXin Li namespace file_util = ::sapi::file_util;
48*ec63e07aSXin Li 
49*ec63e07aSXin Li namespace {
DisableCompressStackDepot(ForkRequest & request)50*ec63e07aSXin Li void DisableCompressStackDepot(ForkRequest& request) {
51*ec63e07aSXin Li   auto disable_compress_stack_depot = [&request](absl::string_view sanitizer) {
52*ec63e07aSXin Li     auto prefix = absl::StrCat(sanitizer, "_OPTIONS=");
53*ec63e07aSXin Li     auto it = std::find_if(request.mutable_envs()->begin(),
54*ec63e07aSXin Li                            request.mutable_envs()->end(),
55*ec63e07aSXin Li                            [&prefix](const std::string& env) {
56*ec63e07aSXin Li                              return absl::StartsWith(env, prefix);
57*ec63e07aSXin Li                            });
58*ec63e07aSXin Li     constexpr absl::string_view option = "compress_stack_depot=0";
59*ec63e07aSXin Li     if (it != request.mutable_envs()->end()) {
60*ec63e07aSXin Li       // If it's already there, the last value will be used.
61*ec63e07aSXin Li       absl::StrAppend(&*it, ":", option);
62*ec63e07aSXin Li       return;
63*ec63e07aSXin Li     }
64*ec63e07aSXin Li     request.add_envs(absl::StrCat(prefix, option));
65*ec63e07aSXin Li   };
66*ec63e07aSXin Li   if constexpr (sapi::sanitizers::IsASan()) {
67*ec63e07aSXin Li     disable_compress_stack_depot("ASAN");
68*ec63e07aSXin Li   }
69*ec63e07aSXin Li   if constexpr (sapi::sanitizers::IsMSan()) {
70*ec63e07aSXin Li     disable_compress_stack_depot("MSAN");
71*ec63e07aSXin Li   }
72*ec63e07aSXin Li   if constexpr (sapi::sanitizers::IsLSan()) {
73*ec63e07aSXin Li     disable_compress_stack_depot("LSAN");
74*ec63e07aSXin Li   }
75*ec63e07aSXin Li   if constexpr (sapi::sanitizers::IsHwASan()) {
76*ec63e07aSXin Li     disable_compress_stack_depot("HWSAN");
77*ec63e07aSXin Li   }
78*ec63e07aSXin Li   if constexpr (sapi::sanitizers::IsTSan()) {
79*ec63e07aSXin Li     disable_compress_stack_depot("TSAN");
80*ec63e07aSXin Li   }
81*ec63e07aSXin Li }
82*ec63e07aSXin Li }  // namespace
83*ec63e07aSXin Li 
CopyEnviron()84*ec63e07aSXin Li std::vector<std::string> Executor::CopyEnviron() {
85*ec63e07aSXin Li   return util::CharPtrArray(environ).ToStringVector();
86*ec63e07aSXin Li }
87*ec63e07aSXin Li 
StartSubProcess(int32_t clone_flags,const Namespace * ns,MonitorType type)88*ec63e07aSXin Li absl::StatusOr<SandboxeeProcess> Executor::StartSubProcess(int32_t clone_flags,
89*ec63e07aSXin Li                                                            const Namespace* ns,
90*ec63e07aSXin Li                                                            MonitorType type) {
91*ec63e07aSXin Li   if (started_) {
92*ec63e07aSXin Li     return absl::FailedPreconditionError(
93*ec63e07aSXin Li         "This executor has already been started");
94*ec63e07aSXin Li   }
95*ec63e07aSXin Li 
96*ec63e07aSXin Li   if (!path_.empty()) {
97*ec63e07aSXin Li     exec_fd_ = file_util::fileops::FDCloser(open(path_.c_str(), O_PATH));
98*ec63e07aSXin Li     if (exec_fd_.get() < 0) {
99*ec63e07aSXin Li       if (errno == ENOENT) {
100*ec63e07aSXin Li         return absl::ErrnoToStatus(errno, path_);
101*ec63e07aSXin Li       }
102*ec63e07aSXin Li       return absl::ErrnoToStatus(errno,
103*ec63e07aSXin Li                                  absl::StrCat("Could not open file ", path_));
104*ec63e07aSXin Li     }
105*ec63e07aSXin Li   }
106*ec63e07aSXin Li 
107*ec63e07aSXin Li   if (libunwind_sbox_for_pid_ != 0) {
108*ec63e07aSXin Li     VLOG(1) << "StartSubProcces, starting libunwind";
109*ec63e07aSXin Li   } else if (exec_fd_.get() < 0) {
110*ec63e07aSXin Li     VLOG(1) << "StartSubProcess, with [Fork-Server]";
111*ec63e07aSXin Li   } else if (!path_.empty()) {
112*ec63e07aSXin Li     VLOG(1) << "StartSubProcess, with file " << path_;
113*ec63e07aSXin Li   } else {
114*ec63e07aSXin Li     VLOG(1) << "StartSubProcess, with fd " << exec_fd_.get();
115*ec63e07aSXin Li   }
116*ec63e07aSXin Li 
117*ec63e07aSXin Li   ForkRequest request;
118*ec63e07aSXin Li   *request.mutable_args() = {argv_.begin(), argv_.end()};
119*ec63e07aSXin Li   *request.mutable_envs() = {envp_.begin(), envp_.end()};
120*ec63e07aSXin Li 
121*ec63e07aSXin Li   // Add LD_ORIGIN_PATH to envs, as it'll make the amount of syscalls invoked by
122*ec63e07aSXin Li   // ld.so smaller.
123*ec63e07aSXin Li   if (!path_.empty()) {
124*ec63e07aSXin Li     request.add_envs(absl::StrCat("LD_ORIGIN_PATH=",
125*ec63e07aSXin Li                                   file_util::fileops::StripBasename(path_)));
126*ec63e07aSXin Li   }
127*ec63e07aSXin Li 
128*ec63e07aSXin Li   // Disable optimization to avoid related syscalls.
129*ec63e07aSXin Li   if constexpr (sapi::sanitizers::IsAny()) {
130*ec63e07aSXin Li     DisableCompressStackDepot(request);
131*ec63e07aSXin Li   }
132*ec63e07aSXin Li 
133*ec63e07aSXin Li   // If neither the path, nor exec_fd is specified, just assume that we need to
134*ec63e07aSXin Li   // send a fork request.
135*ec63e07aSXin Li   //
136*ec63e07aSXin Li   // Otherwise, it's either sandboxing pre- or post-execve with the global
137*ec63e07aSXin Li   // Fork-Server.
138*ec63e07aSXin Li   if (exec_fd_.get() == -1) {
139*ec63e07aSXin Li     request.set_mode(FORKSERVER_FORK);
140*ec63e07aSXin Li   } else if (enable_sandboxing_pre_execve_) {
141*ec63e07aSXin Li     request.set_mode(FORKSERVER_FORK_EXECVE_SANDBOX);
142*ec63e07aSXin Li   } else {
143*ec63e07aSXin Li     request.set_mode(FORKSERVER_FORK_EXECVE);
144*ec63e07aSXin Li   }
145*ec63e07aSXin Li 
146*ec63e07aSXin Li   if (ns) {
147*ec63e07aSXin Li     clone_flags |= ns->clone_flags();
148*ec63e07aSXin Li     *request.mutable_mount_tree() = ns->mounts().GetMountTree();
149*ec63e07aSXin Li     request.set_hostname(ns->hostname());
150*ec63e07aSXin Li     request.set_allow_mount_propagation(ns->allow_mount_propagation());
151*ec63e07aSXin Li   }
152*ec63e07aSXin Li 
153*ec63e07aSXin Li   request.set_clone_flags(clone_flags);
154*ec63e07aSXin Li   request.set_monitor_type(type);
155*ec63e07aSXin Li 
156*ec63e07aSXin Li   SandboxeeProcess process;
157*ec63e07aSXin Li 
158*ec63e07aSXin Li   if (fork_client_) {
159*ec63e07aSXin Li     process = fork_client_->SendRequest(request, exec_fd_.get(),
160*ec63e07aSXin Li                                         client_comms_fd_.get());
161*ec63e07aSXin Li   } else {
162*ec63e07aSXin Li     process = GlobalForkClient::SendRequest(request, exec_fd_.get(),
163*ec63e07aSXin Li                                             client_comms_fd_.get());
164*ec63e07aSXin Li   }
165*ec63e07aSXin Li 
166*ec63e07aSXin Li   started_ = true;
167*ec63e07aSXin Li 
168*ec63e07aSXin Li   client_comms_fd_.Close();
169*ec63e07aSXin Li   exec_fd_.Close();
170*ec63e07aSXin Li 
171*ec63e07aSXin Li   VLOG(1) << "StartSubProcess returned with: " << process.main_pid;
172*ec63e07aSXin Li   return process;
173*ec63e07aSXin Li }
174*ec63e07aSXin Li 
StartForkServer()175*ec63e07aSXin Li std::unique_ptr<ForkClient> Executor::StartForkServer() {
176*ec63e07aSXin Li   // This flag is set explicitly to 'true' during object instantiation, and
177*ec63e07aSXin Li   // custom fork-servers should never be sandboxed.
178*ec63e07aSXin Li   set_enable_sandbox_before_exec(false);
179*ec63e07aSXin Li   absl::StatusOr<SandboxeeProcess> process = StartSubProcess(0);
180*ec63e07aSXin Li   if (!process.ok()) {
181*ec63e07aSXin Li     return nullptr;
182*ec63e07aSXin Li   }
183*ec63e07aSXin Li   return std::make_unique<ForkClient>(process->main_pid, ipc_.comms());
184*ec63e07aSXin Li }
185*ec63e07aSXin Li 
SetUpServerSideCommsFd()186*ec63e07aSXin Li void Executor::SetUpServerSideCommsFd() {
187*ec63e07aSXin Li   int sv[2];
188*ec63e07aSXin Li   if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
189*ec63e07aSXin Li     PLOG(FATAL) << "socketpair(AF_UNIX, SOCK_STREAM) failed";
190*ec63e07aSXin Li   }
191*ec63e07aSXin Li 
192*ec63e07aSXin Li   client_comms_fd_ = file_util::fileops::FDCloser(sv[0]);
193*ec63e07aSXin Li   ipc_.SetUpServerSideComms(sv[1]);
194*ec63e07aSXin Li }
195*ec63e07aSXin Li 
196*ec63e07aSXin Li }  // namespace sandbox2
197