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