mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Do not crash when creating thread group with already-exceeded soft CPU limit.
Reported-by: syzbot+da9595a72d0762aaa48d@syzkaller.appspotmail.com PiperOrigin-RevId: 699425946
This commit is contained in:
committed by
gVisor bot
parent
d118c2b5ca
commit
2b55090a58
@@ -213,6 +213,17 @@ func (ts *TaskSet) newTask(ctx context.Context, cfg *TaskConfig) (*Task, error)
|
||||
}
|
||||
}
|
||||
|
||||
// If the task was the first to be added to the thread group, check if
|
||||
// it needs to be notified of CPU limits being exceeded.
|
||||
// We use a defer here because we need to do this without holding the
|
||||
// TaskSet or signalHandlers lock.
|
||||
var isFirstTask bool
|
||||
defer func() {
|
||||
if isFirstTask {
|
||||
tg.notifyRlimitCPUUpdated(t)
|
||||
}
|
||||
}()
|
||||
|
||||
// Make the new task (and possibly thread group) visible to the rest of
|
||||
// the system atomically.
|
||||
ts.mu.Lock()
|
||||
@@ -259,7 +270,7 @@ func (ts *TaskSet) newTask(ctx context.Context, cfg *TaskConfig) (*Task, error)
|
||||
t.EnterInitialCgroups(srcT, cfg.InitialCgroups)
|
||||
committed = true
|
||||
|
||||
if tg.leader == nil {
|
||||
if isFirstTask = tg.leader == nil; isFirstTask {
|
||||
// New thread group.
|
||||
tg.leader = t
|
||||
if parentPG := tg.parentPG(); parentPG == nil {
|
||||
|
||||
@@ -305,7 +305,6 @@ func (k *Kernel) NewThreadGroup(pidns *PIDNamespace, sh *SignalHandlers, termina
|
||||
tg.rlimitCPUSoftListener.tg = tg
|
||||
tg.rlimitCPUHardTimer.Init(&tg.appSysCPUClock, &tg.rlimitCPUHardListener)
|
||||
tg.rlimitCPUHardListener.tg = tg
|
||||
tg.notifyRlimitCPUUpdated(nil)
|
||||
tg.oldRSeqCritical.Store(&OldRSeqCriticalRegion{})
|
||||
return tg
|
||||
}
|
||||
|
||||
@@ -238,15 +238,18 @@ TEST(TimerTest, RlimitCpuInheritedAcrossFork) {
|
||||
sigemptyset(&new_action.sa_mask);
|
||||
TEST_PCHECK(sigaction(SIGXCPU, &new_action, nullptr) == 0);
|
||||
|
||||
// Set both soft and hard limits to expire a short time from now. (Since we
|
||||
// may not be able to raise RLIMIT_CPU again, this must happen in a
|
||||
// disposable child of the test process.)
|
||||
constexpr int kDelaySeconds = 2;
|
||||
struct timespec ts;
|
||||
TEST_PCHECK(clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0);
|
||||
struct rlimit cpu_limits;
|
||||
// Set soft limit to 0 to expire immediately. This should cause
|
||||
// a SIGXCPU to be sent to the grandchild immediately on fork.
|
||||
cpu_limits.rlim_cur = 0;
|
||||
// Set hard limit to expire a short time from now. (Since we
|
||||
// may not be able to raise RLIMIT_CPU again, this must happen in a
|
||||
// disposable child of the test process.)
|
||||
// +1 to round up, presuming that ts.tv_nsec > 0.
|
||||
cpu_limits.rlim_cur = cpu_limits.rlim_max = ts.tv_sec + kDelaySeconds + 1;
|
||||
cpu_limits.rlim_max = ts.tv_sec + kDelaySeconds + 1;
|
||||
TEST_PCHECK(setrlimit(RLIMIT_CPU, &cpu_limits) == 0);
|
||||
MaybeSave();
|
||||
|
||||
@@ -271,7 +274,7 @@ TEST(TimerTest, RlimitCpuInheritedAcrossFork) {
|
||||
// block in waitid().
|
||||
// TODO: b/315388929 - remove this
|
||||
if (x % 16384 == 0) {
|
||||
TEST_PCHECK(ppoll(&pfd, 1, &timeout, nullptr) == 0);
|
||||
TEST_PCHECK(RetryEINTR(ppoll)(&pfd, 1, &timeout, nullptr) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user