mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Global deadline for ptrace attach instead of per process
PiperOrigin-RevId: 286196033 Change-Id: Ic456b881c18518c4b52ca051fa5c58590794da17
This commit is contained in:
parent
7125458c5d
commit
e969deea33
|
@ -550,6 +550,11 @@ bool Monitor::InitPtraceAttach() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tasks.find(pid_) == tasks.end()) {
|
||||||
|
LOG(ERROR) << "The pid " << pid_ << " was not found in its own tasklist.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// With TSYNC, we can allow threads: seccomp applies to all threads.
|
// With TSYNC, we can allow threads: seccomp applies to all threads.
|
||||||
|
|
||||||
if (tasks.size() > 1) {
|
if (tasks.size() > 1) {
|
||||||
|
@ -560,83 +565,70 @@ bool Monitor::InitPtraceAttach() {
|
||||||
<< ".";
|
<< ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
intptr_t ptrace_opts =
|
std::set<int> tasks_attached;
|
||||||
PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK |
|
int retries = 0;
|
||||||
PTRACE_O_TRACEVFORKDONE | PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC |
|
absl::Time deadline = absl::Now() + absl::Seconds(2);
|
||||||
PTRACE_O_TRACEEXIT | PTRACE_O_TRACESECCOMP | PTRACE_O_EXITKILL;
|
|
||||||
|
|
||||||
bool main_pid_found = false;
|
// In some situations we allow ptrace to try again when it fails.
|
||||||
for (auto task : tasks) {
|
while (!tasks.empty()) {
|
||||||
if (task == pid_) {
|
std::set<int> tasks_left;
|
||||||
main_pid_found = true;
|
for (int task : tasks) {
|
||||||
}
|
constexpr intptr_t options =
|
||||||
|
PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK |
|
||||||
// In some situations we allow ptrace to try again when it fails.
|
PTRACE_O_TRACEVFORKDONE | PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC |
|
||||||
bool ptrace_succeeded = false;
|
PTRACE_O_TRACEEXIT | PTRACE_O_TRACESECCOMP | PTRACE_O_EXITKILL;
|
||||||
int retries = 0;
|
int ret = ptrace(PTRACE_SEIZE, task, 0, options);
|
||||||
auto deadline = absl::Now() + absl::Seconds(2);
|
if (ret != 0) {
|
||||||
while (absl::Now() < deadline) {
|
if (errno == EPERM) {
|
||||||
int ret = ptrace(PTRACE_SEIZE, task, 0, ptrace_opts);
|
// Sometimes when a task is exiting we can get an EPERM from ptrace.
|
||||||
if (ret == 0) {
|
// Let's try again up until the timeout in this situation.
|
||||||
ptrace_succeeded = true;
|
PLOG(WARNING) << "ptrace(PTRACE_SEIZE, " << task << ", "
|
||||||
break;
|
<< absl::StrCat("0x", absl::Hex(options))
|
||||||
|
<< "), trying again...";
|
||||||
|
tasks_left.insert(task);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (errno == ESRCH) {
|
||||||
|
// A task may have exited since we captured the task list, we will
|
||||||
|
// allow things to continue after we log a warning.
|
||||||
|
PLOG(WARNING)
|
||||||
|
<< "ptrace(PTRACE_SEIZE, " << task << ", "
|
||||||
|
<< absl::StrCat("0x", absl::Hex(options))
|
||||||
|
<< ") skipping exited task. Continuing with other tasks.";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Any other errno will be considered a failure.
|
||||||
|
PLOG(ERROR) << "ptrace(PTRACE_SEIZE, " << task << ", "
|
||||||
|
<< absl::StrCat("0x", absl::Hex(options)) << ") failed.";
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (ret != 0 && errno == ESRCH) {
|
tasks_attached.insert(task);
|
||||||
// A task may have exited since we captured the task list, we will allow
|
|
||||||
// things to continue after we log a warning.
|
|
||||||
PLOG(WARNING) << "ptrace(PTRACE_SEIZE, " << task << ", "
|
|
||||||
<< absl::StrCat("0x", absl::Hex(ptrace_opts))
|
|
||||||
<< ") skipping exited task. Continuing with other tasks.";
|
|
||||||
ptrace_succeeded = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ret != 0 && errno == EPERM) {
|
|
||||||
// Sometimes when a task is exiting we can get an EPERM from ptrace.
|
|
||||||
// Let's try again up until the timeout in this situation.
|
|
||||||
PLOG(WARNING) << "ptrace(PTRACE_SEIZE, " << task << ", "
|
|
||||||
<< absl::StrCat("0x", absl::Hex(ptrace_opts))
|
|
||||||
<< "), trying again...";
|
|
||||||
|
|
||||||
// Exponential Backoff.
|
|
||||||
constexpr auto kInitialRetry = absl::Milliseconds(1);
|
|
||||||
constexpr auto kMaxRetry = absl::Milliseconds(20);
|
|
||||||
const auto retry_interval =
|
|
||||||
kInitialRetry * (1 << std::min(10, retries++));
|
|
||||||
absl::SleepFor(std::min(retry_interval, kMaxRetry));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any other errno will be considered a failure.
|
|
||||||
PLOG(ERROR) << "ptrace(PTRACE_SEIZE, " << task << ", "
|
|
||||||
<< absl::StrCat("0x", absl::Hex(ptrace_opts)) << ") failed.";
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
if (!tasks_left.empty()) {
|
||||||
if (!ptrace_succeeded) {
|
if (absl::Now() < deadline) {
|
||||||
LOG(ERROR) << "ptrace(PTRACE_SEIZE, " << task << ", "
|
LOG(ERROR) << "Attaching to sandboxee timed out: could not attach to "
|
||||||
<< absl::StrCat("0x", absl::Hex(ptrace_opts))
|
<< tasks_left.size() << " tasks";
|
||||||
<< ") failed after retrying until the timeout.";
|
return false;
|
||||||
return false;
|
}
|
||||||
|
// Exponential Backoff.
|
||||||
|
constexpr absl::Duration kInitialRetry = absl::Milliseconds(1);
|
||||||
|
constexpr absl::Duration kMaxRetry = absl::Milliseconds(20);
|
||||||
|
const absl::Duration retry_interval =
|
||||||
|
kInitialRetry * (1 << std::min(10, retries++));
|
||||||
|
absl::SleepFor(
|
||||||
|
std::min({retry_interval, kMaxRetry, deadline - absl::Now()}));
|
||||||
}
|
}
|
||||||
}
|
tasks = std::move(tasks_left);
|
||||||
|
|
||||||
if (!main_pid_found) {
|
|
||||||
LOG(ERROR) << "The pid " << pid_ << " was not found in its own tasklist.";
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a list of tasks after attaching.
|
// Get a list of tasks after attaching.
|
||||||
std::set<int> tasks_after;
|
if (!sanitizer::GetListOfTasks(pid_, &tasks)) {
|
||||||
if (!sanitizer::GetListOfTasks(pid_, &tasks_after)) {
|
|
||||||
LOG(ERROR) << "Could not get list of tasks";
|
LOG(ERROR) << "Could not get list of tasks";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that no new threads have shown up. Note: tasks_after can have fewer
|
// Check that we attached to all the threads
|
||||||
// tasks than before but no new tasks can be added as they would be missing
|
if (tasks_attached != tasks) {
|
||||||
// from the initial task list.
|
|
||||||
if (!std::includes(tasks.begin(), tasks.end(), tasks_after.begin(),
|
|
||||||
tasks_after.end())) {
|
|
||||||
LOG(ERROR) << "The pid " << pid_
|
LOG(ERROR) << "The pid " << pid_
|
||||||
<< " spawned new threads while we were trying to attach to it.";
|
<< " spawned new threads while we were trying to attach to it.";
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user