summaryrefslogtreecommitdiffhomepage
path: root/pkg
diff options
context:
space:
mode:
authorJamie Liu <jamieliu@google.com>2021-07-08 13:36:49 -0700
committergVisor bot <gvisor-bot@google.com>2021-07-08 13:39:15 -0700
commit052eb90dc15e04dfd8397ca305c507399360dd0e (patch)
tree7e9e5b12b72e53ced002a206bff572f6e6ce9243 /pkg
parentfbd4ccf33339a261812521fbc54554850a70676c (diff)
Replace kernel.ExitStatus with linux.WaitStatus.
PiperOrigin-RevId: 383705129
Diffstat (limited to 'pkg')
-rw-r--r--pkg/abi/linux/wait.go125
-rw-r--r--pkg/sentry/control/proc.go2
-rw-r--r--pkg/sentry/control/state.go3
-rw-r--r--pkg/sentry/kernel/kernel.go6
-rw-r--r--pkg/sentry/kernel/ptrace.go2
-rw-r--r--pkg/sentry/kernel/task.go2
-rw-r--r--pkg/sentry/kernel/task_exit.go106
-rw-r--r--pkg/sentry/kernel/task_log.go2
-rw-r--r--pkg/sentry/kernel/task_run.go2
-rw-r--r--pkg/sentry/kernel/task_signals.go13
-rw-r--r--pkg/sentry/kernel/task_syscall.go6
-rw-r--r--pkg/sentry/kernel/thread_group.go2
-rw-r--r--pkg/sentry/syscalls/linux/sys_thread.go28
13 files changed, 186 insertions, 113 deletions
diff --git a/pkg/abi/linux/wait.go b/pkg/abi/linux/wait.go
index 4bdc280d1..710729138 100644
--- a/pkg/abi/linux/wait.go
+++ b/pkg/abi/linux/wait.go
@@ -14,6 +14,10 @@
package linux
+import (
+ "fmt"
+)
+
// Options for waitpid(2), wait4(2), and/or waitid(2), from
// include/uapi/linux/wait.h.
const (
@@ -34,3 +38,124 @@ const (
P_PID = 0x1
P_PGID = 0x2
)
+
+// WaitStatus represents a thread status, as returned by the wait* family of
+// syscalls.
+type WaitStatus uint32
+
+// WaitStatusExit returns a WaitStatus representing the given exit status.
+func WaitStatusExit(status int32) WaitStatus {
+ return WaitStatus(uint32(status) << 8)
+}
+
+// WaitStatusTerminationSignal returns a WaitStatus representing termination by
+// the given signal.
+func WaitStatusTerminationSignal(sig Signal) WaitStatus {
+ return WaitStatus(uint32(sig))
+}
+
+// WaitStatusStopped returns a WaitStatus representing stoppage by the given
+// signal or ptrace trap code.
+func WaitStatusStopped(code uint32) WaitStatus {
+ return WaitStatus(code<<8 | 0x7f)
+}
+
+// WaitStatusContinued returns a WaitStatus representing continuation by
+// SIGCONT.
+func WaitStatusContinued() WaitStatus {
+ return WaitStatus(0xffff)
+}
+
+// WithCoreDump returns a copy of ws that indicates that a core dump was
+// generated.
+//
+// Preconditions: ws.Signaled().
+func (ws WaitStatus) WithCoreDump() WaitStatus {
+ return ws | 0x80
+}
+
+// Exited returns true if ws represents an exit status, consistent with
+// WIFEXITED.
+func (ws WaitStatus) Exited() bool {
+ return ws&0x7f == 0
+}
+
+// Signaled returns true if ws represents a termination by signal, consistent
+// with WIFSIGNALED.
+func (ws WaitStatus) Signaled() bool {
+ // ws&0x7f != 0 (exited) and ws&0x7f != 0x7f (stopped or continued)
+ return ((ws&0x7f)+1)>>1 != 0
+}
+
+// CoreDumped returns true if ws indicates that a core dump was produced,
+// consistent with WCOREDUMP.
+//
+// Preconditions: ws.Signaled().
+func (ws WaitStatus) CoreDumped() bool {
+ return ws&0x80 != 0
+}
+
+// Stopped returns true if ws represents a stoppage, consistent with
+// WIFSTOPPED.
+func (ws WaitStatus) Stopped() bool {
+ return ws&0xff == 0x7f
+}
+
+// Continued returns true if ws represents a continuation by SIGCONT,
+// consistent with WIFCONTINUED.
+func (ws WaitStatus) Continued() bool {
+ return ws == 0xffff
+}
+
+// ExitStatus returns the lower 8 bits of the exit status represented by ws,
+// consistent with WEXITSTATUS.
+//
+// Preconditions: ws.Exited().
+func (ws WaitStatus) ExitStatus() uint32 {
+ return uint32((ws & 0xff00) >> 8)
+}
+
+// TerminationSignal returns the termination signal represented by ws,
+// consistent with WTERMSIG.
+//
+// Preconditions: ws.Signaled().
+func (ws WaitStatus) TerminationSignal() Signal {
+ return Signal(ws & 0x7f)
+}
+
+// StopSignal returns the stop signal represented by ws, consistent with
+// WSTOPSIG.
+//
+// Preconditions: ws.Stopped().
+func (ws WaitStatus) StopSignal() Signal {
+ return Signal((ws & 0xff00) >> 8)
+}
+
+// PtraceEvent returns the PTRACE_EVENT_* field in ws.
+//
+// Preconditions: ws.Stopped().
+func (ws WaitStatus) PtraceEvent() uint32 {
+ return uint32(ws >> 16)
+}
+
+// String implements fmt.Stringer.String.
+func (ws WaitStatus) String() string {
+ switch {
+ case ws.Exited():
+ return fmt.Sprintf("exit status %d", ws.ExitStatus())
+ case ws.Signaled():
+ if ws.CoreDumped() {
+ return fmt.Sprintf("killed by signal %d (core dumped)", ws.TerminationSignal())
+ }
+ return fmt.Sprintf("killed by signal %d", ws.TerminationSignal())
+ case ws.Stopped():
+ if ev := ws.PtraceEvent(); ev != 0 {
+ return fmt.Sprintf("stopped by signal %d (PTRACE_EVENT %d)", ws.StopSignal(), ev)
+ }
+ return fmt.Sprintf("stopped by signal %d", ws.StopSignal())
+ case ws.Continued():
+ return "continued"
+ default:
+ return fmt.Sprintf("unknown status %#x", uint32(ws))
+ }
+}
diff --git a/pkg/sentry/control/proc.go b/pkg/sentry/control/proc.go
index 221e98a01..b7ee5425d 100644
--- a/pkg/sentry/control/proc.go
+++ b/pkg/sentry/control/proc.go
@@ -126,7 +126,7 @@ func (proc *Proc) Exec(args *ExecArgs, waitStatus *uint32) error {
// Wait for completion.
newTG.WaitExited()
- *waitStatus = newTG.ExitStatus().Status()
+ *waitStatus = uint32(newTG.ExitStatus())
return nil
}
diff --git a/pkg/sentry/control/state.go b/pkg/sentry/control/state.go
index 62eaca965..4c83b8e8e 100644
--- a/pkg/sentry/control/state.go
+++ b/pkg/sentry/control/state.go
@@ -17,6 +17,7 @@ package control
import (
"errors"
+ "gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/state"
@@ -67,7 +68,7 @@ func (s *State) Save(o *SaveOpts, _ *struct{}) error {
log.Warningf("Save failed: exiting...")
s.Kernel.SetSaveError(err)
}
- s.Kernel.Kill(kernel.ExitStatus{})
+ s.Kernel.Kill(linux.WaitStatusExit(0))
},
}
return saveOpts.Save(s.Kernel.SupervisorContext(), s.Kernel, s.Watchdog)
diff --git a/pkg/sentry/kernel/kernel.go b/pkg/sentry/kernel/kernel.go
index 352c36ba9..df5160b67 100644
--- a/pkg/sentry/kernel/kernel.go
+++ b/pkg/sentry/kernel/kernel.go
@@ -1299,11 +1299,11 @@ func (k *Kernel) WaitExited() {
}
// Kill requests that all tasks in k immediately exit as if group exiting with
-// status es. Kill does not wait for tasks to exit.
-func (k *Kernel) Kill(es ExitStatus) {
+// status ws. Kill does not wait for tasks to exit.
+func (k *Kernel) Kill(ws linux.WaitStatus) {
k.extMu.Lock()
defer k.extMu.Unlock()
- k.tasks.Kill(es)
+ k.tasks.Kill(ws)
}
// Pause requests that all tasks in k temporarily stop executing, and blocks
diff --git a/pkg/sentry/kernel/ptrace.go b/pkg/sentry/kernel/ptrace.go
index 161140980..52ea5b44b 100644
--- a/pkg/sentry/kernel/ptrace.go
+++ b/pkg/sentry/kernel/ptrace.go
@@ -912,7 +912,7 @@ func (t *Task) ptraceExit() {
return
}
t.tg.signalHandlers.mu.Lock()
- status := t.exitStatus.Status()
+ status := t.exitStatus
t.tg.signalHandlers.mu.Unlock()
t.Debugf("Entering PTRACE_EVENT_EXIT stop")
t.ptraceEventLocked(linux.PTRACE_EVENT_EXIT, uint64(status))
diff --git a/pkg/sentry/kernel/task.go b/pkg/sentry/kernel/task.go
index d211e4d82..59eeb253d 100644
--- a/pkg/sentry/kernel/task.go
+++ b/pkg/sentry/kernel/task.go
@@ -232,7 +232,7 @@ type Task struct {
// exitStatus is the task's exit status.
//
// exitStatus is protected by the signal mutex.
- exitStatus ExitStatus
+ exitStatus linux.WaitStatus
// syscallRestartBlock represents a custom restart function to run in
// restart_syscall(2) to resume an interrupted syscall.
diff --git a/pkg/sentry/kernel/task_exit.go b/pkg/sentry/kernel/task_exit.go
index fe08c7519..fbfcc19e5 100644
--- a/pkg/sentry/kernel/task_exit.go
+++ b/pkg/sentry/kernel/task_exit.go
@@ -28,7 +28,6 @@ import (
"errors"
"fmt"
"strconv"
- "strings"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
@@ -37,58 +36,6 @@ import (
"gvisor.dev/gvisor/pkg/waiter"
)
-// An ExitStatus is a value communicated from an exiting task or thread group
-// to the party that reaps it.
-//
-// +stateify savable
-type ExitStatus struct {
- // Code is the numeric value passed to the call to exit or exit_group that
- // caused the exit. If the exit was not caused by such a call, Code is 0.
- Code int
-
- // Signo is the signal that caused the exit. If the exit was not caused by
- // a signal, Signo is 0.
- Signo int
-}
-
-func (es ExitStatus) String() string {
- var b strings.Builder
- if code := es.Code; code != 0 {
- if b.Len() != 0 {
- b.WriteByte(' ')
- }
- _, _ = fmt.Fprintf(&b, "Code=%d", code)
- }
- if signal := es.Signo; signal != 0 {
- if b.Len() != 0 {
- b.WriteByte(' ')
- }
- _, _ = fmt.Fprintf(&b, "Signal=%d", signal)
- }
- return b.String()
-}
-
-// Signaled returns true if the ExitStatus indicates that the exiting task or
-// thread group was killed by a signal.
-func (es ExitStatus) Signaled() bool {
- return es.Signo != 0
-}
-
-// Status returns the numeric representation of the ExitStatus returned by e.g.
-// the wait4() system call.
-func (es ExitStatus) Status() uint32 {
- return ((uint32(es.Code) & 0xff) << 8) | (uint32(es.Signo) & 0xff)
-}
-
-// ShellExitCode returns the numeric exit code that Bash would return for an
-// exit status of es.
-func (es ExitStatus) ShellExitCode() int {
- if es.Signaled() {
- return 128 + es.Signo
- }
- return es.Code
-}
-
// TaskExitState represents a step in the task exit path.
//
// "Exiting" and "exited" are often ambiguous; prefer to name specific states.
@@ -164,13 +111,13 @@ func (t *Task) killedLocked() bool {
return t.pendingSignals.pendingSet&linux.SignalSetOf(linux.SIGKILL) != 0
}
-// PrepareExit indicates an exit with status es.
+// PrepareExit indicates an exit with the given status.
//
// Preconditions: The caller must be running on the task goroutine.
-func (t *Task) PrepareExit(es ExitStatus) {
+func (t *Task) PrepareExit(ws linux.WaitStatus) {
t.tg.signalHandlers.mu.Lock()
defer t.tg.signalHandlers.mu.Unlock()
- t.exitStatus = es
+ t.exitStatus = ws
}
// PrepareGroupExit indicates a group exit with status es to t's thread group.
@@ -181,7 +128,7 @@ func (t *Task) PrepareExit(es ExitStatus) {
// ptrace.)
//
// Preconditions: The caller must be running on the task goroutine.
-func (t *Task) PrepareGroupExit(es ExitStatus) {
+func (t *Task) PrepareGroupExit(ws linux.WaitStatus) {
t.tg.signalHandlers.mu.Lock()
defer t.tg.signalHandlers.mu.Unlock()
if t.tg.exiting || t.tg.execing != nil {
@@ -199,8 +146,8 @@ func (t *Task) PrepareGroupExit(es ExitStatus) {
return
}
t.tg.exiting = true
- t.tg.exitStatus = es
- t.exitStatus = es
+ t.tg.exitStatus = ws
+ t.exitStatus = ws
for sibling := t.tg.tasks.Front(); sibling != nil; sibling = sibling.Next() {
if sibling != t {
sibling.killLocked()
@@ -208,11 +155,11 @@ func (t *Task) PrepareGroupExit(es ExitStatus) {
}
}
-// Kill requests that all tasks in ts exit as if group exiting with status es.
+// Kill requests that all tasks in ts exit as if group exiting with status ws.
// Kill does not wait for tasks to exit.
//
// Kill has no analogue in Linux; it's provided for save/restore only.
-func (ts *TaskSet) Kill(es ExitStatus) {
+func (ts *TaskSet) Kill(ws linux.WaitStatus) {
ts.mu.Lock()
defer ts.mu.Unlock()
ts.Root.exiting = true
@@ -220,7 +167,7 @@ func (ts *TaskSet) Kill(es ExitStatus) {
t.tg.signalHandlers.mu.Lock()
if !t.tg.exiting {
t.tg.exiting = true
- t.tg.exitStatus = es
+ t.tg.exitStatus = ws
}
t.killLocked()
t.tg.signalHandlers.mu.Unlock()
@@ -731,10 +678,10 @@ func (t *Task) exitNotificationSignal(sig linux.Signal, receiver *Task) *linux.S
info.SetUID(int32(t.Credentials().RealKUID.In(receiver.UserNamespace()).OrOverflow()))
if t.exitStatus.Signaled() {
info.Code = linux.CLD_KILLED
- info.SetStatus(int32(t.exitStatus.Signo))
+ info.SetStatus(int32(t.exitStatus.TerminationSignal()))
} else {
info.Code = linux.CLD_EXITED
- info.SetStatus(int32(t.exitStatus.Code))
+ info.SetStatus(int32(t.exitStatus.ExitStatus()))
}
// TODO(b/72102453): Set utime, stime.
return info
@@ -742,7 +689,7 @@ func (t *Task) exitNotificationSignal(sig linux.Signal, receiver *Task) *linux.S
// ExitStatus returns t's exit status, which is only guaranteed to be
// meaningful if t.ExitState() != TaskExitNone.
-func (t *Task) ExitStatus() ExitStatus {
+func (t *Task) ExitStatus() linux.WaitStatus {
t.tg.pidns.owner.mu.RLock()
defer t.tg.pidns.owner.mu.RUnlock()
t.tg.signalHandlers.mu.Lock()
@@ -752,7 +699,7 @@ func (t *Task) ExitStatus() ExitStatus {
// ExitStatus returns the exit status that would be returned by a consuming
// wait*() on tg.
-func (tg *ThreadGroup) ExitStatus() ExitStatus {
+func (tg *ThreadGroup) ExitStatus() linux.WaitStatus {
tg.pidns.owner.mu.RLock()
defer tg.pidns.owner.mu.RUnlock()
tg.signalHandlers.mu.Lock()
@@ -763,7 +710,9 @@ func (tg *ThreadGroup) ExitStatus() ExitStatus {
return tg.leader.exitStatus
}
-// TerminationSignal returns the thread group's termination signal.
+// TerminationSignal returns the thread group's termination signal, which is
+// the signal that will be sent to its leader's parent when all threads have
+// exited.
func (tg *ThreadGroup) TerminationSignal() linux.Signal {
tg.pidns.owner.mu.RLock()
defer tg.pidns.owner.mu.RUnlock()
@@ -889,8 +838,8 @@ type WaitResult struct {
// Event is exactly one of the events defined above.
Event waiter.EventMask
- // Status is the numeric status associated with the event.
- Status uint32
+ // Status is the wait status associated with the event.
+ Status linux.WaitStatus
}
// Wait waits for an event from a thread group that is a child of t's thread
@@ -1043,7 +992,7 @@ func (t *Task) waitCollectZombieLocked(target *Task, opts *WaitOptions, asPtrace
}
pid := t.tg.pidns.tids[target]
uid := target.Credentials().RealKUID.In(t.UserNamespace()).OrOverflow()
- status := target.exitStatus.Status()
+ status := target.exitStatus
if !opts.ConsumeEvent {
return &WaitResult{
Task: target,
@@ -1057,7 +1006,7 @@ func (t *Task) waitCollectZombieLocked(target *Task, opts *WaitOptions, asPtrace
// differ from that reported by a consuming wait; the latter will return
// the group exit code if one is available.
if target.tg.exiting {
- status = target.tg.exitStatus.Status()
+ status = target.tg.exitStatus
}
// t may be (in the thread group of) target's parent, tracer, or both. We
// don't need to check for !exitTracerAcked because tracees are detached
@@ -1123,12 +1072,11 @@ func (t *Task) waitCollectChildGroupStopLocked(target *Task, opts *WaitOptions)
target.tg.groupStopWaitable = false
}
return &WaitResult{
- Task: target,
- TID: pid,
- UID: uid,
- Event: EventChildGroupStop,
- // There is no name for these status constants.
- Status: (uint32(sig)&0xff)<<8 | 0x7f,
+ Task: target,
+ TID: pid,
+ UID: uid,
+ Event: EventChildGroupStop,
+ Status: linux.WaitStatusStopped(uint32(sig)),
}
}
@@ -1149,7 +1097,7 @@ func (t *Task) waitCollectGroupContinueLocked(target *Task, opts *WaitOptions) *
TID: pid,
UID: uid,
Event: EventGroupContinue,
- Status: 0xffff,
+ Status: linux.WaitStatusContinued(),
}
}
@@ -1177,7 +1125,7 @@ func (t *Task) waitCollectTraceeStopLocked(target *Task, opts *WaitOptions) *Wai
TID: pid,
UID: uid,
Event: EventTraceeStop,
- Status: uint32(code)<<8 | 0x7f,
+ Status: linux.WaitStatusStopped(uint32(code)),
}
}
diff --git a/pkg/sentry/kernel/task_log.go b/pkg/sentry/kernel/task_log.go
index 72b9a0384..8de08151a 100644
--- a/pkg/sentry/kernel/task_log.go
+++ b/pkg/sentry/kernel/task_log.go
@@ -235,7 +235,7 @@ func (t *Task) traceExitEvent() {
if !trace.IsEnabled() {
return
}
- trace.Logf(t.traceContext, traceCategory, "exit status: 0x%x", t.exitStatus.Status())
+ trace.Logf(t.traceContext, traceCategory, "exit status: %s", t.exitStatus)
}
// traceExecEvent is called when a task calls exec.
diff --git a/pkg/sentry/kernel/task_run.go b/pkg/sentry/kernel/task_run.go
index 068f25af1..054ff212f 100644
--- a/pkg/sentry/kernel/task_run.go
+++ b/pkg/sentry/kernel/task_run.go
@@ -377,7 +377,7 @@ func (app *runApp) execute(t *Task) taskRunState {
default:
// What happened? Can't continue.
t.Warningf("Unexpected SwitchToApp error: %v", err)
- t.PrepareExit(ExitStatus{Code: ExtractErrno(err, -1)})
+ t.PrepareExit(linux.WaitStatusExit(int32(ExtractErrno(err, -1))))
return (*runExit)(nil)
}
}
diff --git a/pkg/sentry/kernel/task_signals.go b/pkg/sentry/kernel/task_signals.go
index 72dce7cd9..7ce57ec97 100644
--- a/pkg/sentry/kernel/task_signals.go
+++ b/pkg/sentry/kernel/task_signals.go
@@ -157,7 +157,8 @@ func (t *Task) PendingSignals() linux.SignalSet {
// deliverSignal delivers the given signal and returns the following run state.
func (t *Task) deliverSignal(info *linux.SignalInfo, act linux.SigAction) taskRunState {
- sigact := computeAction(linux.Signal(info.Signo), act)
+ sig := linux.Signal(info.Signo)
+ sigact := computeAction(sig, act)
if t.haveSyscallReturn {
if sre, ok := syserror.SyscallRestartErrnoFromReturn(t.Arch().Return()); ok {
@@ -198,14 +199,14 @@ func (t *Task) deliverSignal(info *linux.SignalInfo, act linux.SigAction) taskRu
}
// Attach an fault address if appropriate.
- switch linux.Signal(info.Signo) {
+ switch sig {
case linux.SIGSEGV, linux.SIGFPE, linux.SIGILL, linux.SIGTRAP, linux.SIGBUS:
ucs.FaultAddr = info.Addr()
}
eventchannel.Emit(ucs)
- t.PrepareGroupExit(ExitStatus{Signo: int(info.Signo)})
+ t.PrepareGroupExit(linux.WaitStatusTerminationSignal(sig))
return (*runExit)(nil)
case SignalActionStop:
@@ -225,12 +226,12 @@ func (t *Task) deliverSignal(info *linux.SignalInfo, act linux.SigAction) taskRu
// Send a forced SIGSEGV. If the signal that couldn't be delivered
// was a SIGSEGV, force the handler to SIG_DFL.
- t.forceSignal(linux.SIGSEGV, linux.Signal(info.Signo) == linux.SIGSEGV /* unconditional */)
+ t.forceSignal(linux.SIGSEGV, sig == linux.SIGSEGV /* unconditional */)
t.SendSignal(SignalInfoPriv(linux.SIGSEGV))
}
default:
- panic(fmt.Sprintf("Unknown signal action %+v, %d?", info, computeAction(linux.Signal(info.Signo), act)))
+ panic(fmt.Sprintf("Unknown signal action %+v, %d?", info, computeAction(sig, act)))
}
return (*runInterrupt)(nil)
}
@@ -506,7 +507,7 @@ func (tg *ThreadGroup) applySignalSideEffectsLocked(sig linux.Signal) {
// ignores tg.execing.
if !tg.exiting {
tg.exiting = true
- tg.exitStatus = ExitStatus{Signo: int(linux.SIGKILL)}
+ tg.exitStatus = linux.WaitStatusTerminationSignal(linux.SIGKILL)
}
for t := tg.tasks.Front(); t != nil; t = t.Next() {
t.killLocked()
diff --git a/pkg/sentry/kernel/task_syscall.go b/pkg/sentry/kernel/task_syscall.go
index 409b712d8..0586c9def 100644
--- a/pkg/sentry/kernel/task_syscall.go
+++ b/pkg/sentry/kernel/task_syscall.go
@@ -161,7 +161,7 @@ func (t *Task) doSyscall() taskRunState {
// ok
case linux.SECCOMP_RET_KILL_THREAD:
t.Debugf("Syscall %d: killed by seccomp", sysno)
- t.PrepareExit(ExitStatus{Signo: int(linux.SIGSYS)})
+ t.PrepareExit(linux.WaitStatusTerminationSignal(linux.SIGSYS))
return (*runExit)(nil)
case linux.SECCOMP_RET_TRACE:
t.Debugf("Syscall %d: stopping for PTRACE_EVENT_SECCOMP", sysno)
@@ -311,7 +311,7 @@ func (t *Task) doVsyscall(addr hostarch.Addr, sysno uintptr) taskRunState {
return &runVsyscallAfterPtraceEventSeccomp{addr, sysno, caller}
case linux.SECCOMP_RET_KILL_THREAD:
t.Debugf("vsyscall %d: killed by seccomp", sysno)
- t.PrepareExit(ExitStatus{Signo: int(linux.SIGSYS)})
+ t.PrepareExit(linux.WaitStatusTerminationSignal(linux.SIGSYS))
return (*runExit)(nil)
default:
panic(fmt.Sprintf("Unknown seccomp result %d", r))
@@ -338,7 +338,7 @@ func (r *runVsyscallAfterPtraceEventSeccomp) execute(t *Task) taskRunState {
// Documentation/prctl/seccomp_filter.txt. On Linux, changing orig_ax or ip
// causes do_exit(SIGSYS), and changing sp is ignored.
if (sysno != ^uintptr(0) && sysno != r.sysno) || hostarch.Addr(t.Arch().IP()) != r.addr {
- t.PrepareExit(ExitStatus{Signo: int(linux.SIGSYS)})
+ t.PrepareExit(linux.WaitStatusTerminationSignal(linux.SIGSYS))
return (*runExit)(nil)
}
if sysno == ^uintptr(0) {
diff --git a/pkg/sentry/kernel/thread_group.go b/pkg/sentry/kernel/thread_group.go
index 3ce11f542..b61142e53 100644
--- a/pkg/sentry/kernel/thread_group.go
+++ b/pkg/sentry/kernel/thread_group.go
@@ -144,7 +144,7 @@ type ThreadGroup struct {
//
// While exiting is false, exitStatus is protected by the signal mutex.
// When exiting becomes true, exitStatus becomes immutable.
- exitStatus ExitStatus
+ exitStatus linux.WaitStatus
// terminationSignal is the signal that this thread group's leader will
// send to its parent when it exits.
diff --git a/pkg/sentry/syscalls/linux/sys_thread.go b/pkg/sentry/syscalls/linux/sys_thread.go
index fe08c931f..9f0eeb466 100644
--- a/pkg/sentry/syscalls/linux/sys_thread.go
+++ b/pkg/sentry/syscalls/linux/sys_thread.go
@@ -17,7 +17,6 @@ package linux
import (
"path"
- "golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/hostarch"
@@ -188,15 +187,15 @@ func execveat(t *kernel.Task, dirFD int32, pathnameAddr, argvAddr, envvAddr host
// Exit implements linux syscall exit(2).
func Exit(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
- status := int(args[0].Int())
- t.PrepareExit(kernel.ExitStatus{Code: status})
+ status := args[0].Int()
+ t.PrepareExit(linux.WaitStatusExit(status & 0xff))
return 0, kernel.CtrlDoExit, nil
}
// ExitGroup implements linux syscall exit_group(2).
func ExitGroup(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
- status := int(args[0].Int())
- t.PrepareGroupExit(kernel.ExitStatus{Code: status})
+ status := args[0].Int()
+ t.PrepareGroupExit(linux.WaitStatusExit(status & 0xff))
return 0, kernel.CtrlDoExit, nil
}
@@ -316,7 +315,7 @@ func wait4(t *kernel.Task, pid int, statusAddr hostarch.Addr, options int, rusag
return 0, err
}
if statusAddr != 0 {
- if _, err := primitive.CopyUint32Out(t, statusAddr, wr.Status); err != nil {
+ if _, err := primitive.CopyUint32Out(t, statusAddr, uint32(wr.Status)); err != nil {
return 0, err
}
}
@@ -419,23 +418,22 @@ func Waitid(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
}
si.SetPID(int32(wr.TID))
si.SetUID(int32(wr.UID))
- // TODO(b/73541790): convert kernel.ExitStatus to functions and make
- // WaitResult.Status a linux.WaitStatus.
- s := unix.WaitStatus(wr.Status)
+ s := wr.Status
switch {
case s.Exited():
si.Code = linux.CLD_EXITED
si.SetStatus(int32(s.ExitStatus()))
case s.Signaled():
- si.Code = linux.CLD_KILLED
- si.SetStatus(int32(s.Signal()))
- case s.CoreDump():
- si.Code = linux.CLD_DUMPED
- si.SetStatus(int32(s.Signal()))
+ if s.CoreDumped() {
+ si.Code = linux.CLD_DUMPED
+ } else {
+ si.Code = linux.CLD_KILLED
+ }
+ si.SetStatus(int32(s.TerminationSignal()))
case s.Stopped():
if wr.Event == kernel.EventTraceeStop {
si.Code = linux.CLD_TRAPPED
- si.SetStatus(int32(s.TrapCause()))
+ si.SetStatus(int32(s.PtraceEvent()))
} else {
si.Code = linux.CLD_STOPPED
si.SetStatus(int32(s.StopSignal()))