summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/kernel/task_sched.go
diff options
context:
space:
mode:
authorJamie Liu <jamieliu@google.com>2021-06-10 12:38:21 -0700
committergVisor bot <gvisor-bot@google.com>2021-06-10 12:46:15 -0700
commit450692e03fe651d75d017c7e2faf4cba10e26f0b (patch)
tree579c71303ff410c284dbf0f3fa16c4e61689e097 /pkg/sentry/kernel/task_sched.go
parent9ede1a6058131b50340427c8d0fd3a9ccef5e300 (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/kernel/task_sched.go')
-rw-r--r--pkg/sentry/kernel/task_sched.go10
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)"