Skip to content

Commit

Permalink
Do not crash when creating thread group with already-exceeded soft CP…
Browse files Browse the repository at this point in the history
…U limit.

Reported-by: [email protected]
PiperOrigin-RevId: 698982765
  • Loading branch information
EtiennePerot authored and gvisor-bot committed Nov 22, 2024
1 parent b15656d commit 5dba7db
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 1 deletion.
4 changes: 3 additions & 1 deletion pkg/sentry/kernel/task_acct.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,9 @@ type rlimitCPUSoftListener struct {

// NotifyTimer implements ktime.Listener.NotifyTimer.
func (l *rlimitCPUSoftListener) NotifyTimer(exp uint64) {
l.tg.appSysCPUClockLast.Load().SendGroupSignal(SignalInfoPriv(linux.SIGXCPU))
if t := l.tg.appSysCPUClockLast.Load(); t != nil { // May be nil during thread group creation.
t.SendGroupSignal(SignalInfoPriv(linux.SIGXCPU))
}
}

// +stateify savable
Expand Down
38 changes: 38 additions & 0 deletions test/syscalls/linux/timers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,44 @@ TEST(TimerTest, RlimitCpuInheritedAcrossFork) {
<< "status = " << status;
}

TEST(TimerTest, RlimitCpuSoftLimitExceededOnFork) {
pid_t child_pid = fork();
MaybeSave();
if (child_pid == 0) {
// Ignore SIGXCPU from the RLIMIT_CPU soft limit.
struct sigaction new_action;
new_action.sa_handler = NoopSignalHandler;
new_action.sa_flags = 0;
sigemptyset(&new_action.sa_mask);
TEST_PCHECK(sigaction(SIGXCPU, &new_action, nullptr) == 0);

// Set hard limit to expire a short time from now.
struct timespec ts;
TEST_PCHECK(clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0);
struct rlimit cpu_limits;
cpu_limits.rlim_cur = ts.tv_sec; // Exceeded immediately.
cpu_limits.rlim_max = ts.tv_sec + 1;
TEST_PCHECK(setrlimit(RLIMIT_CPU, &cpu_limits) == 0);
MaybeSave();
pid_t grandchild_pid = fork();
MaybeSave();
if (grandchild_pid == 0) {
_exit(0);
}
TEST_PCHECK(grandchild_pid > 0);
int status;
TEST_PCHECK(waitpid(grandchild_pid, &status, 0) == grandchild_pid);
TEST_PCHECK(WIFEXITED(status) && (WEXITSTATUS(status) == 0));
_exit(0);
}

int status;
ASSERT_THAT(waitpid(child_pid, &status, 0),
SyscallSucceedsWithValue(child_pid));
EXPECT_TRUE(WIFEXITED(status) && (WEXITSTATUS(status) == 0))
<< "child status = " << status;
}

// See timerfd.cc:TimerSlack() for rationale.
constexpr absl::Duration kTimerSlack = absl::Milliseconds(500);

Expand Down

0 comments on commit 5dba7db

Please sign in to comment.