mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Always wait on tracee children
After bf959931ddb88c4e4366e96dd22e68fa0db9527c ("wait/ptrace: assume
__WALL if the child is traced") (Linux 4.7), tracees are always eligible
for waiting, regardless of type.
PiperOrigin-RevId: 250399527
This commit is contained in:
@@ -803,13 +803,17 @@ type WaitOptions struct {
|
||||
}
|
||||
|
||||
// Preconditions: The TaskSet mutex must be locked (for reading or writing).
|
||||
func (o *WaitOptions) matchesTask(t *Task, pidns *PIDNamespace) bool {
|
||||
func (o *WaitOptions) matchesTask(t *Task, pidns *PIDNamespace, tracee bool) bool {
|
||||
if o.SpecificTID != 0 && o.SpecificTID != pidns.tids[t] {
|
||||
return false
|
||||
}
|
||||
if o.SpecificPGID != 0 && o.SpecificPGID != pidns.pgids[t.tg.processGroup] {
|
||||
return false
|
||||
}
|
||||
// Tracees are always eligible.
|
||||
if tracee {
|
||||
return true
|
||||
}
|
||||
if t == t.tg.leader && t.tg.terminationSignal == linux.SIGCHLD {
|
||||
return o.NonCloneTasks
|
||||
}
|
||||
@@ -903,7 +907,7 @@ func (t *Task) waitParentLocked(opts *WaitOptions, parent *Task) (*WaitResult, b
|
||||
anyWaitableTasks := false
|
||||
|
||||
for child := range parent.children {
|
||||
if !opts.matchesTask(child, parent.tg.pidns) {
|
||||
if !opts.matchesTask(child, parent.tg.pidns, false) {
|
||||
continue
|
||||
}
|
||||
// Non-leaders don't notify parents on exit and aren't eligible to
|
||||
@@ -946,7 +950,7 @@ func (t *Task) waitParentLocked(opts *WaitOptions, parent *Task) (*WaitResult, b
|
||||
}
|
||||
}
|
||||
for tracee := range parent.ptraceTracees {
|
||||
if !opts.matchesTask(tracee, parent.tg.pidns) {
|
||||
if !opts.matchesTask(tracee, parent.tg.pidns, true) {
|
||||
continue
|
||||
}
|
||||
// Non-leaders do notify tracers on exit.
|
||||
|
||||
@@ -3179,6 +3179,7 @@ cc_binary(
|
||||
linkstatic = 1,
|
||||
deps = [
|
||||
"//test/util:cleanup",
|
||||
"//test/util:file_descriptor",
|
||||
"//test/util:logging",
|
||||
"//test/util:multiprocess_util",
|
||||
"//test/util:posix_error",
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
@@ -31,6 +32,7 @@
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "test/util/cleanup.h"
|
||||
#include "test/util/file_descriptor.h"
|
||||
#include "test/util/logging.h"
|
||||
#include "test/util/multiprocess_util.h"
|
||||
#include "test/util/posix_error.h"
|
||||
@@ -861,6 +863,50 @@ TEST(WaitTest, WaitidRusage) {
|
||||
EXPECT_GE(RusageCpuTime(rusage), kSpin);
|
||||
}
|
||||
|
||||
// After bf959931ddb88c4e4366e96dd22e68fa0db9527c ("wait/ptrace: assume __WALL
|
||||
// if the child is traced") (Linux 4.7), tracees are always eligible for
|
||||
// waiting, regardless of type.
|
||||
TEST(WaitTest, TraceeWALL) {
|
||||
int fds[2];
|
||||
ASSERT_THAT(pipe(fds), SyscallSucceeds());
|
||||
FileDescriptor rfd(fds[0]);
|
||||
FileDescriptor wfd(fds[1]);
|
||||
|
||||
pid_t child = fork();
|
||||
if (child == 0) {
|
||||
// Child.
|
||||
rfd.reset();
|
||||
|
||||
TEST_PCHECK(ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == 0);
|
||||
|
||||
// Notify parent that we're now a tracee.
|
||||
wfd.reset();
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
ASSERT_THAT(child, SyscallSucceeds());
|
||||
|
||||
wfd.reset();
|
||||
|
||||
// Wait for child to become tracee.
|
||||
char c;
|
||||
EXPECT_THAT(ReadFd(rfd.get(), &c, sizeof(c)), SyscallSucceedsWithValue(0));
|
||||
|
||||
// We can wait on the fork child with WCLONE, as it is a tracee.
|
||||
int status;
|
||||
if (IsRunningOnGvisor()) {
|
||||
ASSERT_THAT(Wait4(child, &status, __WCLONE, nullptr),
|
||||
SyscallSucceedsWithValue(child));
|
||||
|
||||
EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0) << status;
|
||||
} else {
|
||||
// On older versions of Linux, we may get ECHILD.
|
||||
ASSERT_THAT(Wait4(child, &status, __WCLONE, nullptr),
|
||||
::testing::AnyOf(SyscallSucceedsWithValue(child),
|
||||
SyscallFailsWithErrno(ECHILD)));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace testing
|
||||
|
||||
Reference in New Issue
Block a user