diff options
author | Jamie Liu <jamieliu@google.com> | 2021-06-10 12:38:21 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-06-10 12:46:15 -0700 |
commit | 450692e03fe651d75d017c7e2faf4cba10e26f0b (patch) | |
tree | 579c71303ff410c284dbf0f3fa16c4e61689e097 /pkg/sentry | |
parent | 9ede1a6058131b50340427c8d0fd3a9ccef5e300 (diff) |
Report task exit in /proc/[pid]/{stat,status} before task goroutine exit.
Between when runExitNotify.execute() returns nil (indicating that the task
goroutine should exit) and when Task.run() advances Task.gosched.State to
TaskGoroutineNonexistent (indicating that the task goroutine is exiting), there
is a race window in which the Task is waitable (since TaskSet.mu is unlocked
and Task.exitParentNotified is true) but will be reported by /proc/[pid]/status
as running. Close the window by checking Task.exitState before task goroutine
exit.
PiperOrigin-RevId: 378711484
Diffstat (limited to 'pkg/sentry')
-rw-r--r-- | pkg/sentry/kernel/task_sched.go | 10 |
1 files changed, 5 insertions, 5 deletions
diff --git a/pkg/sentry/kernel/task_sched.go b/pkg/sentry/kernel/task_sched.go index 9ba5f8d78..f142feab4 100644 --- a/pkg/sentry/kernel/task_sched.go +++ b/pkg/sentry/kernel/task_sched.go @@ -536,7 +536,7 @@ func (tg *ThreadGroup) updateCPUTimersEnabledLocked() { // appropriate for /proc/[pid]/status. func (t *Task) StateStatus() string { switch s := t.TaskGoroutineSchedInfo().State; s { - case TaskGoroutineNonexistent: + case TaskGoroutineNonexistent, TaskGoroutineRunningSys: t.tg.pidns.owner.mu.RLock() defer t.tg.pidns.owner.mu.RUnlock() switch t.exitState { @@ -546,16 +546,16 @@ func (t *Task) StateStatus() string { return "X (dead)" default: // The task goroutine can't exit before passing through - // runExitNotify, so this indicates that the task has been created, - // but the task goroutine hasn't yet started. The Linux equivalent - // is struct task_struct::state == TASK_NEW + // runExitNotify, so if s == TaskGoroutineNonexistent, the task has + // been created but the task goroutine hasn't yet started. The + // Linux equivalent is struct task_struct::state == TASK_NEW // (kernel/fork.c:copy_process() => // kernel/sched/core.c:sched_fork()), but the TASK_NEW bit is // masked out by TASK_REPORT for /proc/[pid]/status, leaving only // TASK_RUNNING. return "R (running)" } - case TaskGoroutineRunningSys, TaskGoroutineRunningApp: + case TaskGoroutineRunningApp: return "R (running)" case TaskGoroutineBlockedInterruptible: return "S (sleeping)" |