Skip to content

Commit 9865502

Browse files
happyCoder92copybara-github
authored andcommitted
PtraceMonitor: Add a flag to use deadline manager instead of sigtimedwait
As SIGCHLD is process directed in case where there are many sandboxees running it is not reliably delivered (any monitor can get it). Thus the whole relies on the monitors actually polling the status every 500ms. This causes bigger latency and unneccessary CPU load. This change puts the feature behind a flag for easier rollout/rollbacks. PiperOrigin-RevId: 721312381 Change-Id: I7151e9f308fd76e0103539dea93610c164e9db47
1 parent 1e91228 commit 9865502

File tree

3 files changed

+59
-24
lines changed

3 files changed

+59
-24
lines changed

sandboxed_api/sandbox2/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -479,8 +479,7 @@ add_library(sandbox2_monitor_ptrace ${SAPI_LIB_TYPE}
479479
)
480480
add_library(sandbox2::monitor_ptrace ALIAS sandbox2_monitor_ptrace)
481481
target_link_libraries(sandbox2_monitor_ptrace
482-
PRIVATE absl::core_headers
483-
absl::cleanup
482+
PRIVATE absl::cleanup
484483
absl::flat_hash_set
485484
absl::flags
486485
absl::log
@@ -495,14 +494,15 @@ target_link_libraries(sandbox2_monitor_ptrace
495494
sapi::status
496495
sandbox2::client
497496
sandbox2::comms
498-
sandbox2::pid_waiter
499497
sandbox2::result
500498
sandbox2::sanitizer
501499
sandbox2::util
502500
PUBLIC absl::check
501+
absl::core_headers
503502
sandbox2::executor
504503
sandbox2::monitor_base
505504
sandbox2::notify
505+
sandbox2::pid_waiter
506506
sandbox2::policy
507507
sandbox2::regs
508508
sandbox2::syscall

sandboxed_api/sandbox2/monitor_ptrace.cc

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ ABSL_FLAG(bool, sandbox2_log_all_stack_traces, false,
7272
"If set, sandbox2 monitor will log stack traces of all monitored "
7373
"threads/processes that are reported to terminate with a signal.");
7474

75+
ABSL_FLAG(bool, sandbox2_monitor_ptrace_use_deadline_manager, false,
76+
"If set, ptrace monitor will use deadline manager to enforce "
77+
"deadlines and as notification mechanism.");
78+
7579
ABSL_FLAG(bool, sandbox2_log_unobtainable_stack_traces_errors, true,
7680
"If set, unobtainable stack trace will be logged as errors.");
7781

@@ -143,6 +147,8 @@ PtraceMonitor::PtraceMonitor(Executor* executor, Policy* policy, Notify* notify)
143147
}
144148
external_kill_request_flag_.test_and_set(std::memory_order_relaxed);
145149
dump_stack_request_flag_.test_and_set(std::memory_order_relaxed);
150+
use_deadline_manager_ =
151+
absl::GetFlag(FLAGS_sandbox2_monitor_ptrace_use_deadline_manager);
146152
}
147153

148154
bool PtraceMonitor::IsActivelyMonitoring() {
@@ -200,14 +206,18 @@ bool PtraceMonitor::InterruptSandboxee() {
200206
#define __WPTRACEEVENT(x) ((x & 0xff0000) >> 16)
201207

202208
void PtraceMonitor::NotifyMonitor() {
203-
absl::ReaderMutexLock lock(&notify_mutex_);
204-
if (thread_.IsJoinable()) {
205-
pthread_kill(thread_.handle(), SIGCHLD);
209+
if (use_deadline_manager_) {
210+
pid_waiter_.Notify();
211+
} else {
212+
absl::MutexLock lock(&thread_mutex_);
213+
if (thread_.IsJoinable()) {
214+
pthread_kill(thread_.handle(), SIGCHLD);
215+
}
206216
}
207217
}
208218

209219
void PtraceMonitor::Join() {
210-
absl::MutexLock lock(&notify_mutex_);
220+
absl::MutexLock lock(&thread_mutex_);
211221
if (thread_.IsJoinable()) {
212222
thread_.Join();
213223
CHECK(IsDone()) << "Monitor did not terminate";
@@ -217,7 +227,10 @@ void PtraceMonitor::Join() {
217227
}
218228

219229
void PtraceMonitor::RunInternal() {
220-
thread_ = sapi::Thread(this, &PtraceMonitor::Run, "sandbox2-Monitor");
230+
{
231+
absl::MutexLock lock(&thread_mutex_);
232+
thread_ = sapi::Thread(this, &PtraceMonitor::Run, "sandbox2-Monitor");
233+
}
221234

222235
// Wait for the Monitor to set-up the sandboxee correctly (or fail while
223236
// doing that). From here on, it is safe to use the IPC object for
@@ -234,7 +247,7 @@ void PtraceMonitor::Run() {
234247
absl::Cleanup setup_notify = [this] { setup_notification_.Notify(); };
235248
// It'd be costly to initialize the sigset_t for each sigtimedwait()
236249
// invocation, so do it once per Monitor.
237-
if (!InitSetupSignals()) {
250+
if (!use_deadline_manager_ && !InitSetupSignals()) {
238251
SetExitStatusCode(Result::SETUP_ERROR, Result::FAILED_SIGNALS);
239252
return;
240253
}
@@ -251,7 +264,7 @@ void PtraceMonitor::Run() {
251264
std::move(setup_notify).Invoke();
252265

253266
bool sandboxee_exited = false;
254-
PidWaiter pid_waiter(process_.main_pid);
267+
pid_waiter_.SetPriorityPid(process_.main_pid);
255268
int status;
256269
// All possible still running children of main process, will be killed due to
257270
// PTRACE_O_EXITKILL ptrace() flag.
@@ -295,13 +308,21 @@ void PtraceMonitor::Run() {
295308
break;
296309
}
297310
}
298-
299-
pid_t ret = pid_waiter.Wait(&status);
311+
if (use_deadline_manager_) {
312+
absl::Time effective_deadline = hard_deadline_;
313+
if (deadline != 0 && hard_deadline_ == absl::InfiniteFuture()) {
314+
effective_deadline = absl::FromUnixMillis(deadline);
315+
}
316+
pid_waiter_.SetDeadline(effective_deadline);
317+
}
318+
pid_t ret = pid_waiter_.Wait(&status);
300319
if (ret == 0) {
301-
constexpr timespec ts = {kWakeUpPeriodSec, kWakeUpPeriodNSec};
302-
int signo = sigtimedwait(&sset_, nullptr, &ts);
303-
LOG_IF(ERROR, signo != -1 && signo != SIGCHLD)
304-
<< "Unknown signal received: " << signo;
320+
if (!use_deadline_manager_) {
321+
constexpr timespec ts = {kWakeUpPeriodSec, kWakeUpPeriodNSec};
322+
int signo = sigtimedwait(&sset_, nullptr, &ts);
323+
LOG_IF(ERROR, signo != -1 && signo != SIGCHLD)
324+
<< "Unknown signal received: " << signo;
325+
}
305326
continue;
306327
}
307328

@@ -310,7 +331,7 @@ void PtraceMonitor::Run() {
310331
LOG(ERROR) << "PANIC(). The main process has not exited yet, "
311332
<< "yet we haven't seen its exit event";
312333
SetExitStatusCode(Result::INTERNAL_ERROR, Result::FAILED_CHILD);
313-
} else {
334+
} else if (!use_deadline_manager_ || errno != EINTR) {
314335
PLOG(ERROR) << "waitpid() failed";
315336
}
316337
continue;
@@ -381,8 +402,14 @@ void PtraceMonitor::Run() {
381402
<< result_.ToString();
382403
break;
383404
}
384-
pid_t ret = pid_waiter.Wait(&status);
405+
if (use_deadline_manager_) {
406+
pid_waiter_.SetDeadline(deadline);
407+
}
408+
pid_t ret = pid_waiter_.Wait(&status);
385409
if (ret == -1) {
410+
if (use_deadline_manager_ && errno == EINTR) {
411+
continue;
412+
}
386413
if (!log_stack_traces || ret != ECHILD) {
387414
PLOG(ERROR) << "waitpid() failed";
388415
}
@@ -397,8 +424,10 @@ void PtraceMonitor::Run() {
397424
}
398425

399426
if (ret == 0) {
400-
auto ts = absl::ToTimespec(left);
401-
sigtimedwait(&sset_, nullptr, &ts);
427+
if (!use_deadline_manager_) {
428+
auto ts = absl::ToTimespec(left);
429+
sigtimedwait(&sset_, nullptr, &ts);
430+
}
402431
continue;
403432
}
404433

sandboxed_api/sandbox2/monitor_ptrace.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <cstdint>
2323
#include <memory>
2424

25+
#include "absl/base/thread_annotations.h"
2526
#include "absl/container/flat_hash_map.h"
2627
#include "absl/log/log.h"
2728
#include "absl/synchronization/mutex.h"
@@ -34,6 +35,7 @@
3435
#include "sandboxed_api/sandbox2/policy.h"
3536
#include "sandboxed_api/sandbox2/regs.h"
3637
#include "sandboxed_api/sandbox2/syscall.h"
38+
#include "sandboxed_api/sandbox2/util/pid_waiter.h"
3739
#include "sandboxed_api/util/thread.h"
3840

3941
namespace sandbox2 {
@@ -62,6 +64,7 @@ class PtraceMonitor : public MonitorBase {
6264
absl::Time deadline = absl::Now() + limit;
6365
deadline_millis_.store(absl::ToUnixMillis(deadline),
6466
std::memory_order_relaxed);
67+
NotifyMonitor();
6568
}
6669
}
6770

@@ -159,12 +162,15 @@ class PtraceMonitor : public MonitorBase {
159162
sigset_t sset_;
160163
// Deadline after which sandboxee get terminated via PTRACE_O_EXITKILL.
161164
absl::Time hard_deadline_ = absl::InfiniteFuture();
165+
// PidWaiter for waiting for sandboxee events.
166+
PidWaiter pid_waiter_;
167+
// Whether to use deadline manager for deadline enforcement and notifications.
168+
bool use_deadline_manager_ = false;
162169

170+
// Synchronizes joining the monitor thread.
171+
absl::Mutex thread_mutex_;
163172
// Monitor thread object.
164-
sapi::Thread thread_;
165-
166-
// Synchronizes monitor thread deletion and notifying the monitor.
167-
absl::Mutex notify_mutex_;
173+
sapi::Thread ABSL_GUARDED_BY(thread_mutex_) thread_;
168174
};
169175

170176
} // namespace sandbox2

0 commit comments

Comments
 (0)