xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/sandbox.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 #include "sandboxed_api/sandbox.h"
16*ec63e07aSXin Li 
17*ec63e07aSXin Li #include <sys/resource.h>
18*ec63e07aSXin Li #include <sys/types.h>
19*ec63e07aSXin Li #include <sys/uio.h>
20*ec63e07aSXin Li #include <syscall.h>
21*ec63e07aSXin Li 
22*ec63e07aSXin Li #include <cstdio>
23*ec63e07aSXin Li #include <initializer_list>
24*ec63e07aSXin Li #include <memory>
25*ec63e07aSXin Li #include <string>
26*ec63e07aSXin Li #include <utility>
27*ec63e07aSXin Li #include <vector>
28*ec63e07aSXin Li 
29*ec63e07aSXin Li #include "absl/base/dynamic_annotations.h"
30*ec63e07aSXin Li #include "absl/base/macros.h"
31*ec63e07aSXin Li #include "absl/log/log.h"
32*ec63e07aSXin Li #include "absl/status/status.h"
33*ec63e07aSXin Li #include "absl/status/statusor.h"
34*ec63e07aSXin Li #include "absl/strings/str_cat.h"
35*ec63e07aSXin Li #include "absl/strings/str_format.h"
36*ec63e07aSXin Li #include "absl/time/time.h"
37*ec63e07aSXin Li #include "sandboxed_api/config.h"
38*ec63e07aSXin Li #include "sandboxed_api/embed_file.h"
39*ec63e07aSXin Li #include "sandboxed_api/rpcchannel.h"
40*ec63e07aSXin Li #include "sandboxed_api/sandbox2/executor.h"
41*ec63e07aSXin Li #include "sandboxed_api/sandbox2/policy.h"
42*ec63e07aSXin Li #include "sandboxed_api/sandbox2/policybuilder.h"
43*ec63e07aSXin Li #include "sandboxed_api/sandbox2/result.h"
44*ec63e07aSXin Li #include "sandboxed_api/sandbox2/sandbox2.h"
45*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util/bpf_helper.h"
46*ec63e07aSXin Li #include "sandboxed_api/util/fileops.h"
47*ec63e07aSXin Li #include "sandboxed_api/util/path.h"
48*ec63e07aSXin Li #include "sandboxed_api/util/raw_logging.h"
49*ec63e07aSXin Li #include "sandboxed_api/util/runfiles.h"
50*ec63e07aSXin Li #include "sandboxed_api/util/status_macros.h"
51*ec63e07aSXin Li 
52*ec63e07aSXin Li namespace sapi {
53*ec63e07aSXin Li 
~Sandbox()54*ec63e07aSXin Li Sandbox::~Sandbox() {
55*ec63e07aSXin Li   Terminate();
56*ec63e07aSXin Li   // The forkserver will die automatically when the executor goes out of scope
57*ec63e07aSXin Li   // and closes the comms object.
58*ec63e07aSXin Li }
59*ec63e07aSXin Li 
60*ec63e07aSXin Li // A generic policy which should work with majority of typical libraries, which
61*ec63e07aSXin Li // are single-threaded and require ~30 basic syscalls.
InitDefaultPolicyBuilder(sandbox2::PolicyBuilder * builder)62*ec63e07aSXin Li void InitDefaultPolicyBuilder(sandbox2::PolicyBuilder* builder) {
63*ec63e07aSXin Li   (*builder)
64*ec63e07aSXin Li       .AllowRead()
65*ec63e07aSXin Li       .AllowWrite()
66*ec63e07aSXin Li       .AllowExit()
67*ec63e07aSXin Li       .AllowGetRlimit()
68*ec63e07aSXin Li       .AllowGetIDs()
69*ec63e07aSXin Li       .AllowTCGETS()
70*ec63e07aSXin Li       .AllowTime()
71*ec63e07aSXin Li       .AllowOpen()
72*ec63e07aSXin Li       .AllowStat()
73*ec63e07aSXin Li       .AllowHandleSignals()
74*ec63e07aSXin Li       .AllowSystemMalloc()
75*ec63e07aSXin Li       .AllowSafeFcntl()
76*ec63e07aSXin Li       .AllowGetPIDs()
77*ec63e07aSXin Li       .AllowSleep()
78*ec63e07aSXin Li       .AllowReadlink()
79*ec63e07aSXin Li       .AllowAccess()
80*ec63e07aSXin Li       .AllowSyscalls({
81*ec63e07aSXin Li           __NR_recvmsg,
82*ec63e07aSXin Li           __NR_sendmsg,
83*ec63e07aSXin Li           __NR_futex,
84*ec63e07aSXin Li           __NR_close,
85*ec63e07aSXin Li           __NR_lseek,
86*ec63e07aSXin Li           __NR_uname,
87*ec63e07aSXin Li           __NR_kill,
88*ec63e07aSXin Li           __NR_tgkill,
89*ec63e07aSXin Li           __NR_tkill,
90*ec63e07aSXin Li       });
91*ec63e07aSXin Li 
92*ec63e07aSXin Li #ifdef __NR_arch_prctl  // x86-64 only
93*ec63e07aSXin Li   builder->AllowSyscall(__NR_arch_prctl);
94*ec63e07aSXin Li #endif
95*ec63e07aSXin Li 
96*ec63e07aSXin Li   if constexpr (sanitizers::IsAny()) {
97*ec63e07aSXin Li     LOG(WARNING) << "Allowing additional calls to support the LLVM "
98*ec63e07aSXin Li                  << "(ASAN/MSAN/TSAN) sanitizer";
99*ec63e07aSXin Li     builder->AllowLlvmSanitizers();
100*ec63e07aSXin Li   }
101*ec63e07aSXin Li     builder->AddFile("/etc/localtime")
102*ec63e07aSXin Li         .AddTmpfs("/tmp", 1ULL << 30 /* 1GiB tmpfs (max size */);
103*ec63e07aSXin Li }
104*ec63e07aSXin Li 
Terminate(bool attempt_graceful_exit)105*ec63e07aSXin Li void Sandbox::Terminate(bool attempt_graceful_exit) {
106*ec63e07aSXin Li   if (!is_active()) {
107*ec63e07aSXin Li     return;
108*ec63e07aSXin Li   }
109*ec63e07aSXin Li 
110*ec63e07aSXin Li   absl::StatusOr<sandbox2::Result> result;
111*ec63e07aSXin Li   if (attempt_graceful_exit) {
112*ec63e07aSXin Li     if (absl::Status requested_exit = rpc_channel_->Exit();
113*ec63e07aSXin Li         !requested_exit.ok()) {
114*ec63e07aSXin Li       LOG(WARNING)
115*ec63e07aSXin Li           << "rpc_channel->Exit() failed, calling AwaitResultWithTimeout(1) "
116*ec63e07aSXin Li           << requested_exit;
117*ec63e07aSXin Li     }
118*ec63e07aSXin Li     result = s2_->AwaitResultWithTimeout(absl::Seconds(1));
119*ec63e07aSXin Li     if (!result.ok()) {
120*ec63e07aSXin Li       LOG(WARNING) << "s2_->AwaitResultWithTimeout failed, status: "
121*ec63e07aSXin Li                    << result.status() << " Killing PID: " << pid();
122*ec63e07aSXin Li     }
123*ec63e07aSXin Li   }
124*ec63e07aSXin Li 
125*ec63e07aSXin Li   if (!attempt_graceful_exit || !result.ok()) {
126*ec63e07aSXin Li     s2_->Kill();
127*ec63e07aSXin Li     result = s2_->AwaitResult();
128*ec63e07aSXin Li   }
129*ec63e07aSXin Li 
130*ec63e07aSXin Li   if (result->final_status() == sandbox2::Result::OK &&
131*ec63e07aSXin Li       result->reason_code() == 0) {
132*ec63e07aSXin Li     VLOG(2) << "Sandbox2 finished with: " << result->ToString();
133*ec63e07aSXin Li   } else {
134*ec63e07aSXin Li     LOG(WARNING) << "Sandbox2 finished with: " << result->ToString();
135*ec63e07aSXin Li   }
136*ec63e07aSXin Li }
137*ec63e07aSXin Li 
PathToSAPILib(const std::string & lib_path)138*ec63e07aSXin Li static std::string PathToSAPILib(const std::string& lib_path) {
139*ec63e07aSXin Li   return file::IsAbsolutePath(lib_path) ? lib_path
140*ec63e07aSXin Li                                         : GetDataDependencyFilePath(lib_path);
141*ec63e07aSXin Li }
142*ec63e07aSXin Li 
Init(bool use_unotify_monitor)143*ec63e07aSXin Li absl::Status Sandbox::Init(bool use_unotify_monitor) {
144*ec63e07aSXin Li   // It's already initialized
145*ec63e07aSXin Li   if (is_active()) {
146*ec63e07aSXin Li     return absl::OkStatus();
147*ec63e07aSXin Li   }
148*ec63e07aSXin Li 
149*ec63e07aSXin Li   // Initialize the forkserver if it is not already running.
150*ec63e07aSXin Li   if (!fork_client_) {
151*ec63e07aSXin Li     // If FileToc was specified, it will be used over any paths to the SAPI
152*ec63e07aSXin Li     // library.
153*ec63e07aSXin Li     std::string lib_path;
154*ec63e07aSXin Li     int embed_lib_fd = -1;
155*ec63e07aSXin Li     if (embed_lib_toc_ && !sapi::host_os::IsAndroid()) {
156*ec63e07aSXin Li       embed_lib_fd = EmbedFile::instance()->GetDupFdForFileToc(embed_lib_toc_);
157*ec63e07aSXin Li       if (embed_lib_fd == -1) {
158*ec63e07aSXin Li         PLOG(ERROR) << "Cannot create executable FD for TOC:'"
159*ec63e07aSXin Li                     << embed_lib_toc_->name << "'";
160*ec63e07aSXin Li         return absl::UnavailableError("Could not create executable FD");
161*ec63e07aSXin Li       }
162*ec63e07aSXin Li       lib_path = embed_lib_toc_->name;
163*ec63e07aSXin Li     } else {
164*ec63e07aSXin Li       lib_path = PathToSAPILib(GetLibPath());
165*ec63e07aSXin Li       if (lib_path.empty()) {
166*ec63e07aSXin Li         LOG(ERROR) << "SAPI library path is empty";
167*ec63e07aSXin Li         return absl::FailedPreconditionError("No SAPI library path given");
168*ec63e07aSXin Li       }
169*ec63e07aSXin Li     }
170*ec63e07aSXin Li     std::vector<std::string> args = {lib_path};
171*ec63e07aSXin Li     // Additional arguments, if needed.
172*ec63e07aSXin Li     GetArgs(&args);
173*ec63e07aSXin Li     std::vector<std::string> envs{};
174*ec63e07aSXin Li     // Additional envvars, if needed.
175*ec63e07aSXin Li     GetEnvs(&envs);
176*ec63e07aSXin Li 
177*ec63e07aSXin Li     forkserver_executor_ =
178*ec63e07aSXin Li         (embed_lib_fd >= 0)
179*ec63e07aSXin Li             ? std::make_unique<sandbox2::Executor>(embed_lib_fd, args, envs)
180*ec63e07aSXin Li             : std::make_unique<sandbox2::Executor>(lib_path, args, envs);
181*ec63e07aSXin Li 
182*ec63e07aSXin Li     fork_client_ = forkserver_executor_->StartForkServer();
183*ec63e07aSXin Li 
184*ec63e07aSXin Li     if (!fork_client_) {
185*ec63e07aSXin Li       LOG(ERROR) << "Could not start forkserver";
186*ec63e07aSXin Li       return absl::UnavailableError("Could not start the forkserver");
187*ec63e07aSXin Li     }
188*ec63e07aSXin Li   }
189*ec63e07aSXin Li 
190*ec63e07aSXin Li     sandbox2::PolicyBuilder policy_builder;
191*ec63e07aSXin Li     InitDefaultPolicyBuilder(&policy_builder);
192*ec63e07aSXin Li   if (use_unotify_monitor) {
193*ec63e07aSXin Li     policy_builder.CollectStacktracesOnSignal(false);
194*ec63e07aSXin Li   }
195*ec63e07aSXin Li   auto s2p = ModifyPolicy(&policy_builder);
196*ec63e07aSXin Li 
197*ec63e07aSXin Li   // Spawn new process from the forkserver.
198*ec63e07aSXin Li   auto executor = std::make_unique<sandbox2::Executor>(fork_client_.get());
199*ec63e07aSXin Li 
200*ec63e07aSXin Li   executor
201*ec63e07aSXin Li       // The client.cc code is capable of enabling sandboxing on its own.
202*ec63e07aSXin Li       ->set_enable_sandbox_before_exec(false)
203*ec63e07aSXin Li       // By default, set cwd to "/", can be changed in ModifyExecutor().
204*ec63e07aSXin Li       .set_cwd("/")
205*ec63e07aSXin Li       .limits()
206*ec63e07aSXin Li       // Disable time limits.
207*ec63e07aSXin Li       ->set_walltime_limit(absl::ZeroDuration())
208*ec63e07aSXin Li       .set_rlimit_cpu(RLIM64_INFINITY);
209*ec63e07aSXin Li 
210*ec63e07aSXin Li   // Modify the executor, e.g. by setting custom limits and IPC.
211*ec63e07aSXin Li   ModifyExecutor(executor.get());
212*ec63e07aSXin Li 
213*ec63e07aSXin Li   s2_ = std::make_unique<sandbox2::Sandbox2>(std::move(executor),
214*ec63e07aSXin Li                                              std::move(s2p), CreateNotifier());
215*ec63e07aSXin Li   if (use_unotify_monitor) {
216*ec63e07aSXin Li     SAPI_RETURN_IF_ERROR(s2_->EnableUnotifyMonitor());
217*ec63e07aSXin Li   }
218*ec63e07aSXin Li   s2_awaited_ = false;
219*ec63e07aSXin Li   auto res = s2_->RunAsync();
220*ec63e07aSXin Li 
221*ec63e07aSXin Li   comms_ = s2_->comms();
222*ec63e07aSXin Li   pid_ = s2_->pid();
223*ec63e07aSXin Li 
224*ec63e07aSXin Li   rpc_channel_ = std::make_unique<RPCChannel>(comms_);
225*ec63e07aSXin Li 
226*ec63e07aSXin Li   if (!res) {
227*ec63e07aSXin Li     Terminate();
228*ec63e07aSXin Li     return absl::UnavailableError("Could not start the sandbox");
229*ec63e07aSXin Li   }
230*ec63e07aSXin Li   return absl::OkStatus();
231*ec63e07aSXin Li }
232*ec63e07aSXin Li 
is_active() const233*ec63e07aSXin Li bool Sandbox::is_active() const { return s2_ && !s2_->IsTerminated(); }
234*ec63e07aSXin Li 
Allocate(v::Var * var,bool automatic_free)235*ec63e07aSXin Li absl::Status Sandbox::Allocate(v::Var* var, bool automatic_free) {
236*ec63e07aSXin Li   if (!is_active()) {
237*ec63e07aSXin Li     return absl::UnavailableError("Sandbox not active");
238*ec63e07aSXin Li   }
239*ec63e07aSXin Li   return var->Allocate(rpc_channel(), automatic_free);
240*ec63e07aSXin Li }
241*ec63e07aSXin Li 
Free(v::Var * var)242*ec63e07aSXin Li absl::Status Sandbox::Free(v::Var* var) {
243*ec63e07aSXin Li   if (!is_active()) {
244*ec63e07aSXin Li     return absl::UnavailableError("Sandbox not active");
245*ec63e07aSXin Li   }
246*ec63e07aSXin Li   return var->Free(rpc_channel());
247*ec63e07aSXin Li }
248*ec63e07aSXin Li 
SynchronizePtrBefore(v::Callable * ptr)249*ec63e07aSXin Li absl::Status Sandbox::SynchronizePtrBefore(v::Callable* ptr) {
250*ec63e07aSXin Li   if (!is_active()) {
251*ec63e07aSXin Li     return absl::UnavailableError("Sandbox not active");
252*ec63e07aSXin Li   }
253*ec63e07aSXin Li   if (ptr->GetType() != v::Type::kPointer) {
254*ec63e07aSXin Li     return absl::OkStatus();
255*ec63e07aSXin Li   }
256*ec63e07aSXin Li   // Cast is safe, since type is v::Type::kPointer
257*ec63e07aSXin Li   auto* p = static_cast<v::Ptr*>(ptr);
258*ec63e07aSXin Li   // NOLINTNEXTLINE(clang-diagnostic-deprecated-declarations)
259*ec63e07aSXin Li   if (p->GetSyncType() == v::Pointable::kSyncNone) {
260*ec63e07aSXin Li     return absl::OkStatus();
261*ec63e07aSXin Li   }
262*ec63e07aSXin Li 
263*ec63e07aSXin Li   if (p->GetPointedVar()->GetRemote() == nullptr) {
264*ec63e07aSXin Li     // Allocate the memory, and make it automatically free-able, upon this
265*ec63e07aSXin Li     // object's (p->GetPointedVar()) end of life-time.
266*ec63e07aSXin Li     SAPI_RETURN_IF_ERROR(Allocate(p->GetPointedVar(), /*automatic_free=*/true));
267*ec63e07aSXin Li   }
268*ec63e07aSXin Li 
269*ec63e07aSXin Li   // Allocation occurs during both before/after synchronization modes. But the
270*ec63e07aSXin Li   // memory is transferred to the sandboxee only if v::Pointable::kSyncBefore
271*ec63e07aSXin Li   // was requested.
272*ec63e07aSXin Li   // NOLINTNEXTLINE(clang-diagnostic-deprecated-declarations)
273*ec63e07aSXin Li   if ((p->GetSyncType() & v::Pointable::kSyncBefore) == 0) {
274*ec63e07aSXin Li     return absl::OkStatus();
275*ec63e07aSXin Li   }
276*ec63e07aSXin Li 
277*ec63e07aSXin Li   VLOG(3) << "Synchronization (TO), ptr " << p << ", Type: " << p->GetSyncType()
278*ec63e07aSXin Li           << " for var: " << p->GetPointedVar()->ToString();
279*ec63e07aSXin Li 
280*ec63e07aSXin Li   return p->GetPointedVar()->TransferToSandboxee(rpc_channel(), pid());
281*ec63e07aSXin Li }
282*ec63e07aSXin Li 
SynchronizePtrAfter(v::Callable * ptr) const283*ec63e07aSXin Li absl::Status Sandbox::SynchronizePtrAfter(v::Callable* ptr) const {
284*ec63e07aSXin Li   if (!is_active()) {
285*ec63e07aSXin Li     return absl::UnavailableError("Sandbox not active");
286*ec63e07aSXin Li   }
287*ec63e07aSXin Li   if (ptr->GetType() != v::Type::kPointer) {
288*ec63e07aSXin Li     return absl::OkStatus();
289*ec63e07aSXin Li   }
290*ec63e07aSXin Li   v::Ptr* p = reinterpret_cast<v::Ptr*>(ptr);
291*ec63e07aSXin Li   // NOLINTNEXTLINE(clang-diagnostic-deprecated-declarations)
292*ec63e07aSXin Li   if ((p->GetSyncType() & v::Pointable::kSyncAfter) == 0) {
293*ec63e07aSXin Li     return absl::OkStatus();
294*ec63e07aSXin Li   }
295*ec63e07aSXin Li 
296*ec63e07aSXin Li   VLOG(3) << "Synchronization (FROM), ptr " << p
297*ec63e07aSXin Li           << ", Type: " << p->GetSyncType()
298*ec63e07aSXin Li           << " for var: " << p->GetPointedVar()->ToString();
299*ec63e07aSXin Li 
300*ec63e07aSXin Li   if (p->GetPointedVar()->GetRemote() == nullptr) {
301*ec63e07aSXin Li     LOG(ERROR) << "Trying to synchronize a variable which is not allocated in "
302*ec63e07aSXin Li                << "the sandboxee p=" << p->ToString();
303*ec63e07aSXin Li     return absl::FailedPreconditionError(absl::StrCat(
304*ec63e07aSXin Li         "Trying to synchronize a variable which is not allocated in the "
305*ec63e07aSXin Li         "sandboxee p=",
306*ec63e07aSXin Li         p->ToString()));
307*ec63e07aSXin Li   }
308*ec63e07aSXin Li 
309*ec63e07aSXin Li   return p->GetPointedVar()->TransferFromSandboxee(rpc_channel(), pid());
310*ec63e07aSXin Li }
311*ec63e07aSXin Li 
Call(const std::string & func,v::Callable * ret,std::initializer_list<v::Callable * > args)312*ec63e07aSXin Li absl::Status Sandbox::Call(const std::string& func, v::Callable* ret,
313*ec63e07aSXin Li                            std::initializer_list<v::Callable*> args) {
314*ec63e07aSXin Li   if (!is_active()) {
315*ec63e07aSXin Li     return absl::UnavailableError("Sandbox not active");
316*ec63e07aSXin Li   }
317*ec63e07aSXin Li   // Send data.
318*ec63e07aSXin Li   FuncCall rfcall{};
319*ec63e07aSXin Li   rfcall.argc = args.size();
320*ec63e07aSXin Li   absl::SNPrintF(rfcall.func, ABSL_ARRAYSIZE(rfcall.func), "%s", func);
321*ec63e07aSXin Li 
322*ec63e07aSXin Li   VLOG(1) << "CALL ENTRY: '" << func << "' with " << args.size()
323*ec63e07aSXin Li           << " argument(s)";
324*ec63e07aSXin Li 
325*ec63e07aSXin Li   // Copy all arguments into rfcall.
326*ec63e07aSXin Li   int i = 0;
327*ec63e07aSXin Li   for (auto* arg : args) {
328*ec63e07aSXin Li     if (arg == nullptr) {
329*ec63e07aSXin Li       rfcall.arg_type[i] = v::Type::kPointer;
330*ec63e07aSXin Li       rfcall.arg_size[i] = sizeof(void*);
331*ec63e07aSXin Li       rfcall.args[i].arg_int = 0;
332*ec63e07aSXin Li       VLOG(1) << "CALL ARG: (" << i << "): nullptr";
333*ec63e07aSXin Li       ++i;
334*ec63e07aSXin Li       continue;
335*ec63e07aSXin Li     }
336*ec63e07aSXin Li     rfcall.arg_size[i] = arg->GetSize();
337*ec63e07aSXin Li     rfcall.arg_type[i] = arg->GetType();
338*ec63e07aSXin Li 
339*ec63e07aSXin Li     // For pointers, set the auxiliary type and size.
340*ec63e07aSXin Li     if (rfcall.arg_type[i] == v::Type::kPointer) {
341*ec63e07aSXin Li       // Cast is safe, since type is v::Type::kPointer
342*ec63e07aSXin Li       auto* p = static_cast<v::Ptr*>(arg);
343*ec63e07aSXin Li       rfcall.aux_type[i] = p->GetPointedVar()->GetType();
344*ec63e07aSXin Li       rfcall.aux_size[i] = p->GetPointedVar()->GetSize();
345*ec63e07aSXin Li     }
346*ec63e07aSXin Li 
347*ec63e07aSXin Li     // Synchronize all pointers before the call if it's needed.
348*ec63e07aSXin Li     SAPI_RETURN_IF_ERROR(SynchronizePtrBefore(arg));
349*ec63e07aSXin Li 
350*ec63e07aSXin Li     if (arg->GetType() == v::Type::kFloat) {
351*ec63e07aSXin Li       arg->GetDataFromPtr(&rfcall.args[i].arg_float,
352*ec63e07aSXin Li                           sizeof(rfcall.args[0].arg_float));
353*ec63e07aSXin Li       // Make MSAN happy with long double.
354*ec63e07aSXin Li       ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(&rfcall.args[i].arg_float,
355*ec63e07aSXin Li                                           sizeof(rfcall.args[0].arg_float));
356*ec63e07aSXin Li     } else {
357*ec63e07aSXin Li       arg->GetDataFromPtr(&rfcall.args[i].arg_int,
358*ec63e07aSXin Li                           sizeof(rfcall.args[0].arg_int));
359*ec63e07aSXin Li     }
360*ec63e07aSXin Li 
361*ec63e07aSXin Li     if (rfcall.arg_type[i] == v::Type::kFd) {
362*ec63e07aSXin Li       // Cast is safe, since type is v::Type::kFd
363*ec63e07aSXin Li       auto* fd = static_cast<v::Fd*>(arg);
364*ec63e07aSXin Li       if (fd->GetRemoteFd() < 0) {
365*ec63e07aSXin Li         SAPI_RETURN_IF_ERROR(TransferToSandboxee(fd));
366*ec63e07aSXin Li       }
367*ec63e07aSXin Li       rfcall.args[i].arg_int = fd->GetRemoteFd();
368*ec63e07aSXin Li     }
369*ec63e07aSXin Li     VLOG(1) << "CALL ARG: (" << i << "), Type: " << arg->GetTypeString()
370*ec63e07aSXin Li             << ", Size: " << arg->GetSize() << ", Val: " << arg->ToString();
371*ec63e07aSXin Li     ++i;
372*ec63e07aSXin Li   }
373*ec63e07aSXin Li   rfcall.ret_type = ret->GetType();
374*ec63e07aSXin Li   rfcall.ret_size = ret->GetSize();
375*ec63e07aSXin Li 
376*ec63e07aSXin Li   // Call & receive data.
377*ec63e07aSXin Li   FuncRet fret;
378*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(
379*ec63e07aSXin Li       rpc_channel()->Call(rfcall, comms::kMsgCall, &fret, rfcall.ret_type));
380*ec63e07aSXin Li 
381*ec63e07aSXin Li   if (fret.ret_type == v::Type::kFloat) {
382*ec63e07aSXin Li     ret->SetDataFromPtr(&fret.float_val, sizeof(fret.float_val));
383*ec63e07aSXin Li   } else {
384*ec63e07aSXin Li     ret->SetDataFromPtr(&fret.int_val, sizeof(fret.int_val));
385*ec63e07aSXin Li   }
386*ec63e07aSXin Li 
387*ec63e07aSXin Li   if (fret.ret_type == v::Type::kFd) {
388*ec63e07aSXin Li     SAPI_RETURN_IF_ERROR(TransferFromSandboxee(reinterpret_cast<v::Fd*>(ret)));
389*ec63e07aSXin Li   }
390*ec63e07aSXin Li 
391*ec63e07aSXin Li   // Synchronize all pointers after the call if it's needed.
392*ec63e07aSXin Li   for (auto* arg : args) {
393*ec63e07aSXin Li     if (arg != nullptr) {
394*ec63e07aSXin Li       SAPI_RETURN_IF_ERROR(SynchronizePtrAfter(arg));
395*ec63e07aSXin Li     }
396*ec63e07aSXin Li   }
397*ec63e07aSXin Li 
398*ec63e07aSXin Li   VLOG(1) << "CALL EXIT: Type: " << ret->GetTypeString()
399*ec63e07aSXin Li           << ", Size: " << ret->GetSize() << ", Val: " << ret->ToString();
400*ec63e07aSXin Li 
401*ec63e07aSXin Li   return absl::OkStatus();
402*ec63e07aSXin Li }
403*ec63e07aSXin Li 
Symbol(const char * symname,void ** addr)404*ec63e07aSXin Li absl::Status Sandbox::Symbol(const char* symname, void** addr) {
405*ec63e07aSXin Li   if (!is_active()) {
406*ec63e07aSXin Li     return absl::UnavailableError("Sandbox not active");
407*ec63e07aSXin Li   }
408*ec63e07aSXin Li   return rpc_channel_->Symbol(symname, addr);
409*ec63e07aSXin Li }
410*ec63e07aSXin Li 
TransferToSandboxee(v::Var * var)411*ec63e07aSXin Li absl::Status Sandbox::TransferToSandboxee(v::Var* var) {
412*ec63e07aSXin Li   if (!is_active()) {
413*ec63e07aSXin Li     return absl::UnavailableError("Sandbox not active");
414*ec63e07aSXin Li   }
415*ec63e07aSXin Li   return var->TransferToSandboxee(rpc_channel(), pid());
416*ec63e07aSXin Li }
417*ec63e07aSXin Li 
TransferFromSandboxee(v::Var * var)418*ec63e07aSXin Li absl::Status Sandbox::TransferFromSandboxee(v::Var* var) {
419*ec63e07aSXin Li   if (!is_active()) {
420*ec63e07aSXin Li     return absl::UnavailableError("Sandbox not active");
421*ec63e07aSXin Li   }
422*ec63e07aSXin Li   return var->TransferFromSandboxee(rpc_channel(), pid());
423*ec63e07aSXin Li }
424*ec63e07aSXin Li 
GetCString(const v::RemotePtr & str,size_t max_length)425*ec63e07aSXin Li absl::StatusOr<std::string> Sandbox::GetCString(const v::RemotePtr& str,
426*ec63e07aSXin Li                                                 size_t max_length) {
427*ec63e07aSXin Li   if (!is_active()) {
428*ec63e07aSXin Li     return absl::UnavailableError("Sandbox not active");
429*ec63e07aSXin Li   }
430*ec63e07aSXin Li 
431*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(auto len, rpc_channel()->Strlen(str.GetValue()));
432*ec63e07aSXin Li   if (len > max_length) {
433*ec63e07aSXin Li     return absl::InvalidArgumentError(
434*ec63e07aSXin Li         absl::StrCat("Target string too large: ", len, " > ", max_length));
435*ec63e07aSXin Li   }
436*ec63e07aSXin Li   std::string buffer(len, '\0');
437*ec63e07aSXin Li   struct iovec local = {
438*ec63e07aSXin Li       .iov_base = &buffer[0],
439*ec63e07aSXin Li       .iov_len = len,
440*ec63e07aSXin Li   };
441*ec63e07aSXin Li   struct iovec remote = {
442*ec63e07aSXin Li       .iov_base = str.GetValue(),
443*ec63e07aSXin Li       .iov_len = len,
444*ec63e07aSXin Li   };
445*ec63e07aSXin Li 
446*ec63e07aSXin Li   ssize_t ret = process_vm_readv(pid_, &local, 1, &remote, 1, 0);
447*ec63e07aSXin Li   if (ret == -1) {
448*ec63e07aSXin Li     PLOG(WARNING) << "reading c-string failed: process_vm_readv(pid: " << pid_
449*ec63e07aSXin Li                   << " raddr: " << str.GetValue() << " size: " << len << ")";
450*ec63e07aSXin Li     return absl::UnavailableError("process_vm_readv failed");
451*ec63e07aSXin Li   }
452*ec63e07aSXin Li   if (ret != len) {
453*ec63e07aSXin Li     LOG(WARNING) << "partial read when reading c-string: process_vm_readv(pid: "
454*ec63e07aSXin Li                  << pid_ << " raddr: " << str.GetValue() << " size: " << len
455*ec63e07aSXin Li                  << ") transferred " << ret << " bytes";
456*ec63e07aSXin Li     return absl::UnavailableError("process_vm_readv succeeded partially");
457*ec63e07aSXin Li   }
458*ec63e07aSXin Li 
459*ec63e07aSXin Li   return buffer;
460*ec63e07aSXin Li }
461*ec63e07aSXin Li 
AwaitResult()462*ec63e07aSXin Li const sandbox2::Result& Sandbox::AwaitResult() {
463*ec63e07aSXin Li   if (s2_ && !s2_awaited_) {
464*ec63e07aSXin Li     result_ = s2_->AwaitResult();
465*ec63e07aSXin Li     s2_awaited_ = true;
466*ec63e07aSXin Li   }
467*ec63e07aSXin Li   return result_;
468*ec63e07aSXin Li }
469*ec63e07aSXin Li 
SetWallTimeLimit(absl::Duration limit) const470*ec63e07aSXin Li absl::Status Sandbox::SetWallTimeLimit(absl::Duration limit) const {
471*ec63e07aSXin Li   if (!is_active()) {
472*ec63e07aSXin Li     return absl::UnavailableError("Sandbox not active");
473*ec63e07aSXin Li   }
474*ec63e07aSXin Li   s2_->set_walltime_limit(limit);
475*ec63e07aSXin Li   return absl::OkStatus();
476*ec63e07aSXin Li }
477*ec63e07aSXin Li 
Exit() const478*ec63e07aSXin Li void Sandbox::Exit() const {
479*ec63e07aSXin Li   if (!is_active()) {
480*ec63e07aSXin Li     return;
481*ec63e07aSXin Li   }
482*ec63e07aSXin Li   s2_->set_walltime_limit(absl::Seconds(1));
483*ec63e07aSXin Li   if (!rpc_channel_->Exit().ok()) {
484*ec63e07aSXin Li     LOG(WARNING) << "rpc_channel->Exit() failed, killing PID: " << pid();
485*ec63e07aSXin Li     s2_->Kill();
486*ec63e07aSXin Li   }
487*ec63e07aSXin Li }
488*ec63e07aSXin Li 
ModifyPolicy(sandbox2::PolicyBuilder * builder)489*ec63e07aSXin Li std::unique_ptr<sandbox2::Policy> Sandbox::ModifyPolicy(
490*ec63e07aSXin Li     sandbox2::PolicyBuilder* builder) {
491*ec63e07aSXin Li   return builder->BuildOrDie();
492*ec63e07aSXin Li }
493*ec63e07aSXin Li 
494*ec63e07aSXin Li }  // namespace sapi
495