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 file for the sandbox2::Sandbox class.
16
17 #include "sandboxed_api/sandbox2/sandbox2.h"
18
19 #include <memory>
20 #include <utility>
21
22 #include "absl/base/call_once.h"
23 #include "absl/log/check.h"
24 #include "absl/log/log.h"
25 #include "absl/status/status.h"
26 #include "absl/status/statusor.h"
27 #include "absl/time/time.h"
28 #include "sandboxed_api/sandbox2/monitor_base.h"
29 #include "sandboxed_api/sandbox2/monitor_ptrace.h"
30 #include "sandboxed_api/sandbox2/monitor_unotify.h"
31 #include "sandboxed_api/sandbox2/result.h"
32 #include "sandboxed_api/sandbox2/stack_trace.h"
33
34 namespace sandbox2 {
35
36 namespace {
37
38 class Sandbox2Peer : public internal::SandboxPeer {
39 public:
Spawn(std::unique_ptr<Executor> executor,std::unique_ptr<Policy> policy)40 static std::unique_ptr<SandboxPeer> Spawn(std::unique_ptr<Executor> executor,
41 std::unique_ptr<Policy> policy) {
42 return std::make_unique<Sandbox2Peer>(std::move(executor),
43 std::move(policy));
44 }
45
Sandbox2Peer(std::unique_ptr<Executor> executor,std::unique_ptr<Policy> policy)46 Sandbox2Peer(std::unique_ptr<Executor> executor,
47 std::unique_ptr<Policy> policy)
48 : sandbox_(std::move(executor), std::move(policy)) {
49 sandbox_.RunAsync();
50 }
51
comms()52 Comms* comms() override { return sandbox_.comms(); }
Kill()53 void Kill() override { sandbox_.Kill(); }
AwaitResult()54 Result AwaitResult() override { return sandbox_.AwaitResult(); }
55
56 private:
57 Sandbox2 sandbox_;
58 };
59
60 } // namespace
61
AwaitResultWithTimeout(absl::Duration timeout)62 absl::StatusOr<Result> Sandbox2::AwaitResultWithTimeout(
63 absl::Duration timeout) {
64 CHECK(monitor_ != nullptr) << "Sandbox was not launched yet";
65 return monitor_->AwaitResultWithTimeout(timeout);
66 }
67
AwaitResult()68 Result Sandbox2::AwaitResult() {
69 return AwaitResultWithTimeout(absl::InfiniteDuration()).value();
70 }
71
RunAsync()72 bool Sandbox2::RunAsync() {
73 CHECK(monitor_ == nullptr) << "Sandbox was launched already";
74 Launch();
75
76 // If the sandboxee setup failed we return 'false' here.
77 if (monitor_->IsDone() &&
78 monitor_->result().final_status() == Result::SETUP_ERROR) {
79 return false;
80 }
81 return true;
82 }
83
Kill()84 void Sandbox2::Kill() {
85 CHECK(monitor_ != nullptr) << "Sandbox was not launched yet";
86 monitor_->Kill();
87 }
88
DumpStackTrace()89 void Sandbox2::DumpStackTrace() {
90 CHECK(monitor_ != nullptr) << "Sandbox was not launched yet";
91 monitor_->DumpStackTrace();
92 }
93
IsTerminated() const94 bool Sandbox2::IsTerminated() const {
95 CHECK(monitor_ != nullptr) << "Sandbox was not launched yet";
96 return monitor_->IsDone();
97 }
98
set_walltime_limit(absl::Duration limit) const99 void Sandbox2::set_walltime_limit(absl::Duration limit) const {
100 CHECK(monitor_ != nullptr) << "Sandbox was not launched yet";
101 monitor_->SetWallTimeLimit(limit);
102 }
103
Launch()104 void Sandbox2::Launch() {
105 static absl::once_flag init_sandbox_peer_flag;
106 absl::call_once(init_sandbox_peer_flag, []() {
107 internal::SandboxPeer::spawn_fn_ = Sandbox2Peer::Spawn;
108 });
109
110 // This is a technical limitation in our stack trace collection
111 // functionality.
112 LOG_IF(WARNING, !policy_->GetNamespace())
113 << "Using policy without namespaces, disabling stack traces on crash";
114
115 monitor_ = CreateMonitor();
116 monitor_->Launch();
117 }
118
EnableUnotifyMonitor()119 absl::Status Sandbox2::EnableUnotifyMonitor() {
120 if (notify_) {
121 LOG(WARNING) << "Running UnotifyMonitor with sandbox2::Notify is not fully "
122 "supported. Runtime syscall decisions via "
123 "EventSyscallTrap/EventSyscallTrace, notifications about "
124 "signals via EventSignal will not work";
125 }
126 if (!policy_->GetNamespace()) {
127 return absl::FailedPreconditionError(
128 "Unotify monitor can only be used together with namespaces");
129 }
130 if (policy_->collect_stacktrace_on_signal()) {
131 return absl::FailedPreconditionError(
132 "Unotify monitor cannot collect stack traces on signal");
133 }
134
135 if (policy_->collect_stacktrace_on_exit()) {
136 return absl::FailedPreconditionError(
137 "Unotify monitor cannot collect stack traces on normal exit");
138 }
139 use_unotify_monitor_ = true;
140 return absl::OkStatus();
141 }
142
CreateMonitor()143 std::unique_ptr<MonitorBase> Sandbox2::CreateMonitor() {
144 if (!notify_) {
145 notify_ = std::make_unique<Notify>();
146 }
147 if (use_unotify_monitor_) {
148 return std::make_unique<UnotifyMonitor>(executor_.get(), policy_.get(),
149 notify_.get());
150 }
151 return std::make_unique<PtraceMonitor>(executor_.get(), policy_.get(),
152 notify_.get());
153 }
154
155 } // namespace sandbox2
156