// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package kernel

// This file defines the behavior of task signal handling.

import (
	"fmt"
	"sync/atomic"
	"time"

	"gvisor.dev/gvisor/pkg/abi/linux"
	"gvisor.dev/gvisor/pkg/eventchannel"
	"gvisor.dev/gvisor/pkg/sentry/arch"
	"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
	ucspb "gvisor.dev/gvisor/pkg/sentry/kernel/uncaught_signal_go_proto"
	"gvisor.dev/gvisor/pkg/sentry/usermem"
	"gvisor.dev/gvisor/pkg/syserror"
	"gvisor.dev/gvisor/pkg/waiter"
)

// SignalAction is an internal signal action.
type SignalAction int

// Available signal actions.
// Note that although we refer the complete set internally,
// the application is only capable of using the Default and
// Ignore actions from the system call interface.
const (
	SignalActionTerm SignalAction = iota
	SignalActionCore
	SignalActionStop
	SignalActionIgnore
	SignalActionHandler
)

// Default signal handler actions. Note that for most signals,
// (except SIGKILL and SIGSTOP) these can be overridden by the app.
var defaultActions = map[linux.Signal]SignalAction{
	// POSIX.1-1990 standard.
	linux.SIGHUP:  SignalActionTerm,
	linux.SIGINT:  SignalActionTerm,
	linux.SIGQUIT: SignalActionCore,
	linux.SIGILL:  SignalActionCore,
	linux.SIGABRT: SignalActionCore,
	linux.SIGFPE:  SignalActionCore,
	linux.SIGKILL: SignalActionTerm, // but see ThreadGroup.applySignalSideEffects
	linux.SIGSEGV: SignalActionCore,
	linux.SIGPIPE: SignalActionTerm,
	linux.SIGALRM: SignalActionTerm,
	linux.SIGTERM: SignalActionTerm,
	linux.SIGUSR1: SignalActionTerm,
	linux.SIGUSR2: SignalActionTerm,
	linux.SIGCHLD: SignalActionIgnore,
	linux.SIGCONT: SignalActionIgnore, // but see ThreadGroup.applySignalSideEffects
	linux.SIGSTOP: SignalActionStop,
	linux.SIGTSTP: SignalActionStop,
	linux.SIGTTIN: SignalActionStop,
	linux.SIGTTOU: SignalActionStop,
	// POSIX.1-2001 standard.
	linux.SIGBUS:    SignalActionCore,
	linux.SIGPROF:   SignalActionTerm,
	linux.SIGSYS:    SignalActionCore,
	linux.SIGTRAP:   SignalActionCore,
	linux.SIGURG:    SignalActionIgnore,
	linux.SIGVTALRM: SignalActionTerm,
	linux.SIGXCPU:   SignalActionCore,
	linux.SIGXFSZ:   SignalActionCore,
	// The rest on linux.
	linux.SIGSTKFLT: SignalActionTerm,
	linux.SIGIO:     SignalActionTerm,
	linux.SIGPWR:    SignalActionTerm,
	linux.SIGWINCH:  SignalActionIgnore,
}

// computeAction figures out what to do given a signal number
// and an arch.SignalAct. SIGSTOP always results in a SignalActionStop,
// and SIGKILL always results in a SignalActionTerm.
// Signal 0 is always ignored as many programs use it for various internal functions
// and don't expect it to do anything.
//
// In the event the signal is not one of these, act.Handler determines what
// happens next.
// If act.Handler is:
// 0, the default action is taken;
// 1, the signal is ignored;
// anything else, the function returns SignalActionHandler.
func computeAction(sig linux.Signal, act arch.SignalAct) SignalAction {
	switch sig {
	case linux.SIGSTOP:
		return SignalActionStop
	case linux.SIGKILL:
		return SignalActionTerm
	case linux.Signal(0):
		return SignalActionIgnore
	}

	switch act.Handler {
	case arch.SignalActDefault:
		return defaultActions[sig]
	case arch.SignalActIgnore:
		return SignalActionIgnore
	default:
		return SignalActionHandler
	}
}

// UnblockableSignals contains the set of signals which cannot be blocked.
var UnblockableSignals = linux.MakeSignalSet(linux.SIGKILL, linux.SIGSTOP)

// StopSignals is the set of signals whose default action is SignalActionStop.
var StopSignals = linux.MakeSignalSet(linux.SIGSTOP, linux.SIGTSTP, linux.SIGTTIN, linux.SIGTTOU)

// dequeueSignalLocked returns a pending signal that is *not* included in mask.
// If there are no pending unmasked signals, dequeueSignalLocked returns nil.
//
// Preconditions: t.tg.signalHandlers.mu must be locked.
func (t *Task) dequeueSignalLocked(mask linux.SignalSet) *arch.SignalInfo {
	if info := t.pendingSignals.dequeue(mask); info != nil {
		return info
	}
	return t.tg.pendingSignals.dequeue(mask)
}

// discardSpecificLocked removes all instances of the given signal from all
// signal queues in tg.
//
// Preconditions: The signal mutex must be locked.
func (tg *ThreadGroup) discardSpecificLocked(sig linux.Signal) {
	tg.pendingSignals.discardSpecific(sig)
	for t := tg.tasks.Front(); t != nil; t = t.Next() {
		t.pendingSignals.discardSpecific(sig)
	}
}

// PendingSignals returns the set of pending signals.
func (t *Task) PendingSignals() linux.SignalSet {
	t.tg.pidns.owner.mu.RLock()
	defer t.tg.pidns.owner.mu.RUnlock()
	t.tg.signalHandlers.mu.Lock()
	defer t.tg.signalHandlers.mu.Unlock()
	return t.pendingSignals.pendingSet | t.tg.pendingSignals.pendingSet
}

// deliverSignal delivers the given signal and returns the following run state.
func (t *Task) deliverSignal(info *arch.SignalInfo, act arch.SignalAct) taskRunState {
	sigact := computeAction(linux.Signal(info.Signo), act)

	if t.haveSyscallReturn {
		if sre, ok := SyscallRestartErrnoFromReturn(t.Arch().Return()); ok {
			// Signals that are ignored, cause a thread group stop, or
			// terminate the thread group do not interact with interrupted
			// syscalls; in Linux terms, they are never returned to the signal
			// handling path from get_signal => get_signal_to_deliver. The
			// behavior of an interrupted syscall is determined by the first
			// signal that is actually handled (by userspace).
			if sigact == SignalActionHandler {
				switch {
				case sre == ERESTARTNOHAND:
					fallthrough
				case sre == ERESTART_RESTARTBLOCK:
					fallthrough
				case (sre == ERESTARTSYS && !act.IsRestart()):
					t.Debugf("Not restarting syscall %d after errno %d: interrupted by signal %d", t.Arch().SyscallNo(), sre, info.Signo)
					t.Arch().SetReturn(uintptr(-t.ExtractErrno(syserror.EINTR, -1)))
				default:
					t.Debugf("Restarting syscall %d after errno %d: interrupted by signal %d", t.Arch().SyscallNo(), sre, info.Signo)
					t.Arch().RestartSyscall()
				}
			}
		}
	}

	switch sigact {
	case SignalActionTerm, SignalActionCore:
		// "Default action is to terminate the process." - signal(7)
		t.Debugf("Signal %d: terminating thread group", info.Signo)

		// Emit an event channel messages related to this uncaught signal.
		ucs := &ucspb.UncaughtSignal{
			Tid:          int32(t.Kernel().TaskSet().Root.IDOfTask(t)),
			Pid:          int32(t.Kernel().TaskSet().Root.IDOfThreadGroup(t.ThreadGroup())),
			Registers:    t.Arch().StateData().Proto(),
			SignalNumber: info.Signo,
		}

		// Attach an fault address if appropriate.
		switch linux.Signal(info.Signo) {
		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)})
		return (*runExit)(nil)

	case SignalActionStop:
		// "Default action is to stop the process."
		t.initiateGroupStop(info)

	case SignalActionIgnore:
		// "Default action is to ignore the signal."
		t.Debugf("Signal %d: ignored", info.Signo)

	case SignalActionHandler:
		// Try to deliver the signal to the user-configured handler.
		t.Debugf("Signal %d: delivering to handler", info.Signo)
		if err := t.deliverSignalToHandler(info, act); err != nil {
			// This is not a warning, it can occur during normal operation.
			t.Debugf("Failed to deliver signal %+v to user handler: %v", info, err)

			// 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.SendSignal(SignalInfoPriv(linux.SIGSEGV))
		}

	default:
		panic(fmt.Sprintf("Unknown signal action %+v, %d?", info, computeAction(linux.Signal(info.Signo), act)))
	}
	return (*runInterrupt)(nil)
}

// deliverSignalToHandler changes the task's userspace state to enter the given
// user-configured handler for the given signal.
func (t *Task) deliverSignalToHandler(info *arch.SignalInfo, act arch.SignalAct) error {
	// Signal delivery to an application handler interrupts restartable
	// sequences.
	t.rseqInterrupt()

	// Are executing on the main stack,
	// or the provided alternate stack?
	sp := usermem.Addr(t.Arch().Stack())

	// N.B. This is a *copy* of the alternate stack that the user's signal
	// handler expects to see in its ucontext (even if it's not in use).
	alt := t.signalStack
	if act.IsOnStack() && alt.IsEnabled() {
		alt.SetOnStack()
		if !alt.Contains(sp) {
			sp = usermem.Addr(alt.Top())
		}
	}

	// Set up the signal handler. If we have a saved signal mask, the signal
	// handler should run with the current mask, but sigreturn should restore
	// the saved one.
	st := &arch.Stack{t.Arch(), t.MemoryManager(), sp}
	mask := t.signalMask
	if t.haveSavedSignalMask {
		mask = t.savedSignalMask
	}
	if err := t.Arch().SignalSetup(st, &act, info, &alt, mask); err != nil {
		return err
	}
	t.haveSavedSignalMask = false

	// Add our signal mask.
	newMask := t.signalMask | act.Mask
	if !act.IsNoDefer() {
		newMask |= linux.SignalSetOf(linux.Signal(info.Signo))
	}
	t.SetSignalMask(newMask)

	return nil
}

var ctrlResume = &SyscallControl{ignoreReturn: true}

// SignalReturn implements sigreturn(2) (if rt is false) or rt_sigreturn(2) (if
// rt is true).
func (t *Task) SignalReturn(rt bool) (*SyscallControl, error) {
	st := t.Stack()
	sigset, alt, err := t.Arch().SignalRestore(st, rt)
	if err != nil {
		return nil, err
	}

	// Attempt to record the given signal stack. Note that we silently
	// ignore failures here, as does Linux. Only an EFAULT may be
	// generated, but SignalRestore has already deserialized the entire
	// frame successfully.
	t.SetSignalStack(alt)

	// Restore our signal mask. SIGKILL and SIGSTOP should not be blocked.
	t.SetSignalMask(sigset &^ UnblockableSignals)

	return ctrlResume, nil
}

// Sigtimedwait implements the semantics of sigtimedwait(2).
//
// Preconditions: The caller must be running on the task goroutine. t.exitState
// < TaskExitZombie.
func (t *Task) Sigtimedwait(set linux.SignalSet, timeout time.Duration) (*arch.SignalInfo, error) {
	// set is the set of signals we're interested in; invert it to get the set
	// of signals to block.
	mask := ^(set &^ UnblockableSignals)

	t.tg.signalHandlers.mu.Lock()
	defer t.tg.signalHandlers.mu.Unlock()
	if info := t.dequeueSignalLocked(mask); info != nil {
		return info, nil
	}

	if timeout == 0 {
		return nil, syserror.EAGAIN
	}

	// Unblock signals we're waiting for. Remember the original signal mask so
	// that Task.sendSignalTimerLocked doesn't discard ignored signals that
	// we're temporarily unblocking.
	t.realSignalMask = t.signalMask
	t.setSignalMaskLocked(t.signalMask & mask)

	// Wait for a timeout or new signal.
	t.tg.signalHandlers.mu.Unlock()
	_, err := t.BlockWithTimeout(nil, true, timeout)
	t.tg.signalHandlers.mu.Lock()

	// Restore the original signal mask.
	t.setSignalMaskLocked(t.realSignalMask)
	t.realSignalMask = 0

	if info := t.dequeueSignalLocked(mask); info != nil {
		return info, nil
	}
	if err == syserror.ETIMEDOUT {
		return nil, syserror.EAGAIN
	}
	return nil, err
}

// SendSignal sends the given signal to t.
//
// The following errors may be returned:
//
//	syserror.ESRCH - The task has exited.
//	syserror.EINVAL - The signal is not valid.
//	syserror.EAGAIN - THe signal is realtime, and cannot be queued.
//
func (t *Task) SendSignal(info *arch.SignalInfo) error {
	t.tg.pidns.owner.mu.RLock()
	defer t.tg.pidns.owner.mu.RUnlock()
	t.tg.signalHandlers.mu.Lock()
	defer t.tg.signalHandlers.mu.Unlock()
	return t.sendSignalLocked(info, false /* group */)
}

// SendGroupSignal sends the given signal to t's thread group.
func (t *Task) SendGroupSignal(info *arch.SignalInfo) error {
	t.tg.pidns.owner.mu.RLock()
	defer t.tg.pidns.owner.mu.RUnlock()
	t.tg.signalHandlers.mu.Lock()
	defer t.tg.signalHandlers.mu.Unlock()
	return t.sendSignalLocked(info, true /* group */)
}

// SendSignal sends the given signal to tg, using tg's leader to determine if
// the signal is blocked.
func (tg *ThreadGroup) SendSignal(info *arch.SignalInfo) error {
	tg.pidns.owner.mu.RLock()
	defer tg.pidns.owner.mu.RUnlock()
	tg.signalHandlers.mu.Lock()
	defer tg.signalHandlers.mu.Unlock()
	return tg.leader.sendSignalLocked(info, true /* group */)
}

func (t *Task) sendSignalLocked(info *arch.SignalInfo, group bool) error {
	return t.sendSignalTimerLocked(info, group, nil)
}

func (t *Task) sendSignalTimerLocked(info *arch.SignalInfo, group bool, timer *IntervalTimer) error {
	if t.exitState == TaskExitDead {
		return syserror.ESRCH
	}
	sig := linux.Signal(info.Signo)
	if sig == 0 {
		return nil
	}
	if !sig.IsValid() {
		return syserror.EINVAL
	}

	// Signal side effects apply even if the signal is ultimately discarded.
	t.tg.applySignalSideEffectsLocked(sig)

	// TODO: "Only signals for which the "init" process has established a
	// signal handler can be sent to the "init" process by other members of the
	// PID namespace. This restriction applies even to privileged processes,
	// and prevents other members of the PID namespace from accidentally
	// killing the "init" process." - pid_namespaces(7). We don't currently do
	// this for child namespaces, though we should; we also don't do this for
	// the root namespace (the same restriction applies to global init on
	// Linux), where whether or not we should is much murkier. In practice,
	// most sandboxed applications are not prepared to function as an init
	// process.

	// Unmasked, ignored signals are discarded without being queued, unless
	// they will be visible to a tracer. Even for group signals, it's the
	// originally-targeted task's signal mask and tracer that matter; compare
	// Linux's kernel/signal.c:__send_signal() => prepare_signal() =>
	// sig_ignored().
	ignored := computeAction(sig, t.tg.signalHandlers.actions[sig]) == SignalActionIgnore
	if sigset := linux.SignalSetOf(sig); sigset&t.signalMask == 0 && sigset&t.realSignalMask == 0 && ignored && !t.hasTracer() {
		t.Debugf("Discarding ignored signal %d", sig)
		if timer != nil {
			timer.signalRejectedLocked()
		}
		return nil
	}

	q := &t.pendingSignals
	if group {
		q = &t.tg.pendingSignals
	}
	if !q.enqueue(info, timer) {
		if sig.IsRealtime() {
			return syserror.EAGAIN
		}
		t.Debugf("Discarding duplicate signal %d", sig)
		if timer != nil {
			timer.signalRejectedLocked()
		}
		return nil
	}

	// Find a receiver to notify. Note that the task we choose to notify, if
	// any, may not be the task that actually dequeues and handles the signal;
	// e.g. a racing signal mask change may cause the notified task to become
	// ineligible, or a racing sibling task may dequeue the signal first.
	if t.canReceiveSignalLocked(sig) {
		t.Debugf("Notified of signal %d", sig)
		t.interrupt()
		return nil
	}
	if group {
		if nt := t.tg.findSignalReceiverLocked(sig); nt != nil {
			nt.Debugf("Notified of group signal %d", sig)
			nt.interrupt()
			return nil
		}
	}
	t.Debugf("No task notified of signal %d", sig)
	return nil
}

func (tg *ThreadGroup) applySignalSideEffectsLocked(sig linux.Signal) {
	switch {
	case linux.SignalSetOf(sig)&StopSignals != 0:
		// Stop signals cause all prior SIGCONT to be discarded. (This is
		// despite the fact this has little effect since SIGCONT's most
		// important effect is applied when the signal is sent in the branch
		// below, not when the signal is delivered.)
		tg.discardSpecificLocked(linux.SIGCONT)
	case sig == linux.SIGCONT:
		// "The SIGCONT signal has a side effect of waking up (all threads of)
		// a group-stopped process. This side effect happens before
		// signal-delivery-stop. The tracer can't suppress this side effect (it
		// can only suppress signal injection, which only causes the SIGCONT
		// handler to not be executed in the tracee, if such a handler is
		// installed." - ptrace(2)
		tg.endGroupStopLocked(true)
	case sig == linux.SIGKILL:
		// "SIGKILL does not generate signal-delivery-stop and therefore the
		// tracer can't suppress it. SIGKILL kills even within system calls
		// (syscall-exit-stop is not generated prior to death by SIGKILL)." -
		// ptrace(2)
		//
		// Note that this differs from ThreadGroup.requestExit in that it
		// ignores tg.execing.
		if !tg.exiting {
			tg.exiting = true
			tg.exitStatus = ExitStatus{Signo: int(linux.SIGKILL)}
		}
		for t := tg.tasks.Front(); t != nil; t = t.Next() {
			t.killLocked()
		}
	}
}

// canReceiveSignalLocked returns true if t should be interrupted to receive
// the given signal. canReceiveSignalLocked is analogous to Linux's
// kernel/signal.c:wants_signal(), but see below for divergences.
//
// Preconditions: The signal mutex must be locked.
func (t *Task) canReceiveSignalLocked(sig linux.Signal) bool {
	// Notify that the signal is queued.
	t.signalQueue.Notify(waiter.EventMask(linux.MakeSignalSet(sig)))

	// - Do not choose tasks that are blocking the signal.
	if linux.SignalSetOf(sig)&t.signalMask != 0 {
		return false
	}
	// - No need to check Task.exitState, as the exit path sets every bit in the
	// signal mask when it transitions from TaskExitNone to TaskExitInitiated.
	// - No special case for SIGKILL: SIGKILL already interrupted all tasks in the
	// task group via applySignalSideEffects => killLocked.
	// - Do not choose stopped tasks, which cannot handle signals.
	if t.stop != nil {
		return false
	}
	// - TODO(b/38173783): No special case for when t is also the sending task,
	// because the identity of the sender is unknown.
	// - Do not choose tasks that have already been interrupted, as they may be
	// busy handling another signal.
	if len(t.interruptChan) != 0 {
		return false
	}
	return true
}

// findSignalReceiverLocked returns a task in tg that should be interrupted to
// receive the given signal. If no such task exists, findSignalReceiverLocked
// returns nil.
//
// Linux actually records curr_target to balance the group signal targets.
//
// Preconditions: The signal mutex must be locked.
func (tg *ThreadGroup) findSignalReceiverLocked(sig linux.Signal) *Task {
	for t := tg.tasks.Front(); t != nil; t = t.Next() {
		if t.canReceiveSignalLocked(sig) {
			return t
		}
	}
	return nil
}

// forceSignal ensures that the task is not ignoring or blocking the given
// signal. If unconditional is true, forceSignal takes action even if the
// signal isn't being ignored or blocked.
func (t *Task) forceSignal(sig linux.Signal, unconditional bool) {
	t.tg.pidns.owner.mu.RLock()
	defer t.tg.pidns.owner.mu.RUnlock()
	t.tg.signalHandlers.mu.Lock()
	defer t.tg.signalHandlers.mu.Unlock()
	t.forceSignalLocked(sig, unconditional)
}

func (t *Task) forceSignalLocked(sig linux.Signal, unconditional bool) {
	blocked := linux.SignalSetOf(sig)&t.signalMask != 0
	act := t.tg.signalHandlers.actions[sig]
	ignored := act.Handler == arch.SignalActIgnore
	if blocked || ignored || unconditional {
		act.Handler = arch.SignalActDefault
		t.tg.signalHandlers.actions[sig] = act
		if blocked {
			t.setSignalMaskLocked(t.signalMask &^ linux.SignalSetOf(sig))
		}
	}
}

// SignalMask returns a copy of t's signal mask.
func (t *Task) SignalMask() linux.SignalSet {
	return linux.SignalSet(atomic.LoadUint64((*uint64)(&t.signalMask)))
}

// SetSignalMask sets t's signal mask.
//
// Preconditions: SetSignalMask can only be called by the task goroutine.
// t.exitState < TaskExitZombie.
func (t *Task) SetSignalMask(mask linux.SignalSet) {
	// By precondition, t prevents t.tg from completing an execve and mutating
	// t.tg.signalHandlers, so we can skip the TaskSet mutex.
	t.tg.signalHandlers.mu.Lock()
	t.setSignalMaskLocked(mask)
	t.tg.signalHandlers.mu.Unlock()
}

// Preconditions: The signal mutex must be locked.
func (t *Task) setSignalMaskLocked(mask linux.SignalSet) {
	oldMask := t.signalMask
	atomic.StoreUint64((*uint64)(&t.signalMask), uint64(mask))

	// If the new mask blocks any signals that were not blocked by the old
	// mask, and at least one such signal is pending in tg.pendingSignals, and
	// t has been woken, it could be the case that t was woken to handle that
	// signal, but will no longer do so as a result of its new signal mask, so
	// we have to pick a replacement.
	blocked := mask &^ oldMask
	blockedGroupPending := blocked & t.tg.pendingSignals.pendingSet
	if blockedGroupPending != 0 && t.interrupted() {
		linux.ForEachSignal(blockedGroupPending, func(sig linux.Signal) {
			if nt := t.tg.findSignalReceiverLocked(sig); nt != nil {
				nt.interrupt()
				return
			}
		})
		// We have to re-issue the interrupt consumed by t.interrupted() since
		// it might have been for a different reason.
		t.interruptSelf()
	}

	// Conversely, if the new mask unblocks any signals that were blocked by
	// the old mask, and at least one such signal is pending, we may now need
	// to handle that signal.
	unblocked := oldMask &^ mask
	unblockedPending := unblocked & (t.pendingSignals.pendingSet | t.tg.pendingSignals.pendingSet)
	if unblockedPending != 0 {
		t.interruptSelf()
	}
}

// SetSavedSignalMask sets the saved signal mask (see Task.savedSignalMask's
// comment).
//
// Preconditions: SetSavedSignalMask can only be called by the task goroutine.
func (t *Task) SetSavedSignalMask(mask linux.SignalSet) {
	t.savedSignalMask = mask
	t.haveSavedSignalMask = true
}

// SignalStack returns the task-private signal stack.
func (t *Task) SignalStack() arch.SignalStack {
	alt := t.signalStack
	if t.onSignalStack(alt) {
		alt.Flags |= arch.SignalStackFlagOnStack
	}
	return alt
}

// onSignalStack returns true if the task is executing on the given signal stack.
func (t *Task) onSignalStack(alt arch.SignalStack) bool {
	sp := usermem.Addr(t.Arch().Stack())
	return alt.Contains(sp)
}

// SetSignalStack sets the task-private signal stack.
//
// This value may not be changed if the task is currently executing on the
// signal stack, i.e. if t.onSignalStack returns true. In this case, this
// function will return false. Otherwise, true is returned.
func (t *Task) SetSignalStack(alt arch.SignalStack) bool {
	// Check that we're not executing on the stack.
	if t.onSignalStack(t.signalStack) {
		return false
	}

	if alt.Flags&arch.SignalStackFlagDisable != 0 {
		// Don't record anything beyond the flags.
		t.signalStack = arch.SignalStack{
			Flags: arch.SignalStackFlagDisable,
		}
	} else {
		// Mask out irrelevant parts: only disable matters.
		alt.Flags &= arch.SignalStackFlagDisable
		t.signalStack = alt
	}
	return true
}

// SetSignalAct atomically sets the thread group's signal action for signal sig
// to *actptr (if actptr is not nil) and returns the old signal action.
func (tg *ThreadGroup) SetSignalAct(sig linux.Signal, actptr *arch.SignalAct) (arch.SignalAct, error) {
	if !sig.IsValid() {
		return arch.SignalAct{}, syserror.EINVAL
	}

	tg.pidns.owner.mu.RLock()
	defer tg.pidns.owner.mu.RUnlock()
	sh := tg.signalHandlers
	sh.mu.Lock()
	defer sh.mu.Unlock()
	oldact := sh.actions[sig]
	if actptr != nil {
		if sig == linux.SIGKILL || sig == linux.SIGSTOP {
			return oldact, syserror.EINVAL
		}

		act := *actptr
		act.Mask &^= UnblockableSignals
		sh.actions[sig] = act
		// From POSIX, by way of Linux:
		//
		// "Setting a signal action to SIG_IGN for a signal that is pending
		// shall cause the pending signal to be discarded, whether or not it is
		// blocked."
		//
		// "Setting a signal action to SIG_DFL for a signal that is pending and
		// whose default action is to ignore the signal (for example, SIGCHLD),
		// shall cause the pending signal to be discarded, whether or not it is
		// blocked."
		if computeAction(sig, act) == SignalActionIgnore {
			tg.discardSpecificLocked(sig)
		}
	}
	return oldact, nil
}

// CopyOutSignalAct converts the given SignalAct into an architecture-specific
// type and then copies it out to task memory.
func (t *Task) CopyOutSignalAct(addr usermem.Addr, s *arch.SignalAct) error {
	n := t.Arch().NewSignalAct()
	n.SerializeFrom(s)
	_, err := t.CopyOut(addr, n)
	return err
}

// CopyInSignalAct copies an architecture-specific sigaction type from task
// memory and then converts it into a SignalAct.
func (t *Task) CopyInSignalAct(addr usermem.Addr) (arch.SignalAct, error) {
	n := t.Arch().NewSignalAct()
	var s arch.SignalAct
	if _, err := t.CopyIn(addr, n); err != nil {
		return s, err
	}
	n.DeserializeTo(&s)
	return s, nil
}

// CopyOutSignalStack converts the given SignalStack into an
// architecture-specific type and then copies it out to task memory.
func (t *Task) CopyOutSignalStack(addr usermem.Addr, s *arch.SignalStack) error {
	n := t.Arch().NewSignalStack()
	n.SerializeFrom(s)
	_, err := t.CopyOut(addr, n)
	return err
}

// CopyInSignalStack copies an architecture-specific stack_t from task memory
// and then converts it into a SignalStack.
func (t *Task) CopyInSignalStack(addr usermem.Addr) (arch.SignalStack, error) {
	n := t.Arch().NewSignalStack()
	var s arch.SignalStack
	if _, err := t.CopyIn(addr, n); err != nil {
		return s, err
	}
	n.DeserializeTo(&s)
	return s, nil
}

// groupStop is a TaskStop placed on tasks that have received a stop signal
// (SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU). (The term "group-stop" originates from
// the ptrace man page.)
//
// +stateify savable
type groupStop struct{}

// Killable implements TaskStop.Killable.
func (*groupStop) Killable() bool { return true }

// initiateGroupStop attempts to initiate a group stop based on a
// previously-dequeued stop signal.
//
// Preconditions: The caller must be running on the task goroutine.
func (t *Task) initiateGroupStop(info *arch.SignalInfo) {
	t.tg.pidns.owner.mu.RLock()
	defer t.tg.pidns.owner.mu.RUnlock()
	t.tg.signalHandlers.mu.Lock()
	defer t.tg.signalHandlers.mu.Unlock()
	if t.groupStopPending {
		t.Debugf("Signal %d: not stopping thread group: lost to racing stop signal", info.Signo)
		return
	}
	if !t.tg.groupStopDequeued {
		t.Debugf("Signal %d: not stopping thread group: lost to racing SIGCONT", info.Signo)
		return
	}
	if t.tg.exiting {
		t.Debugf("Signal %d: not stopping thread group: lost to racing group exit", info.Signo)
		return
	}
	if t.tg.execing != nil {
		t.Debugf("Signal %d: not stopping thread group: lost to racing execve", info.Signo)
		return
	}
	if !t.tg.groupStopComplete {
		t.tg.groupStopSignal = linux.Signal(info.Signo)
	}
	t.tg.groupStopPendingCount = 0
	for t2 := t.tg.tasks.Front(); t2 != nil; t2 = t2.Next() {
		if t2.killedLocked() || t2.exitState >= TaskExitInitiated {
			t2.groupStopPending = false
			continue
		}
		t2.groupStopPending = true
		t2.groupStopAcknowledged = false
		if t2.ptraceSeized {
			t2.trapNotifyPending = true
			if s, ok := t2.stop.(*ptraceStop); ok && s.listen {
				t2.endInternalStopLocked()
			}
		}
		t2.interrupt()
		t.tg.groupStopPendingCount++
	}
	t.Debugf("Signal %d: stopping %d threads in thread group", info.Signo, t.tg.groupStopPendingCount)
}

// endGroupStopLocked ensures that all prior stop signals received by tg are
// not stopping tg and will not stop tg in the future. If broadcast is true,
// parent and tracer notification will be scheduled if appropriate.
//
// Preconditions: The signal mutex must be locked.
func (tg *ThreadGroup) endGroupStopLocked(broadcast bool) {
	// Discard all previously-queued stop signals.
	linux.ForEachSignal(StopSignals, tg.discardSpecificLocked)

	if tg.groupStopPendingCount == 0 && !tg.groupStopComplete {
		return
	}

	completeStr := "incomplete"
	if tg.groupStopComplete {
		completeStr = "complete"
	}
	tg.leader.Debugf("Ending %s group stop with %d threads pending", completeStr, tg.groupStopPendingCount)
	for t := tg.tasks.Front(); t != nil; t = t.Next() {
		t.groupStopPending = false
		if t.ptraceSeized {
			t.trapNotifyPending = true
			if s, ok := t.stop.(*ptraceStop); ok && s.listen {
				t.endInternalStopLocked()
			}
		} else {
			if _, ok := t.stop.(*groupStop); ok {
				t.endInternalStopLocked()
			}
		}
	}
	if broadcast {
		// Instead of notifying the parent here, set groupContNotify so that
		// one of the continuing tasks does so. (Linux does something similar.)
		// The reason we do this is to keep locking sane. In order to send a
		// signal to the parent, we need to lock its signal mutex, but we're
		// already holding tg's signal mutex, and the TaskSet mutex must be
		// locked for writing for us to hold two signal mutexes. Since we don't
		// want to require this for endGroupStopLocked (which is called from
		// signal-sending paths), nor do we want to lose atomicity by releasing
		// the mutexes we're already holding, just let the continuing thread
		// group deal with it.
		tg.groupContNotify = true
		tg.groupContInterrupted = !tg.groupStopComplete
		tg.groupContWaitable = true
	}
	// Unsetting groupStopDequeued will cause racing calls to initiateGroupStop
	// to recognize that the group stop has been cancelled.
	tg.groupStopDequeued = false
	tg.groupStopSignal = 0
	tg.groupStopPendingCount = 0
	tg.groupStopComplete = false
	tg.groupStopWaitable = false
}

// participateGroupStopLocked is called to handle thread group side effects
// after t unsets t.groupStopPending. The caller must handle task side effects
// (e.g. placing the task goroutine into the group stop). It returns true if
// the caller must notify t.tg.leader's parent of a completed group stop (which
// participateGroupStopLocked cannot do due to holding the wrong locks).
//
// Preconditions: The signal mutex must be locked.
func (t *Task) participateGroupStopLocked() bool {
	if t.groupStopAcknowledged {
		return false
	}
	t.groupStopAcknowledged = true
	t.tg.groupStopPendingCount--
	if t.tg.groupStopPendingCount != 0 {
		return false
	}
	if t.tg.groupStopComplete {
		return false
	}
	t.Debugf("Completing group stop")
	t.tg.groupStopComplete = true
	t.tg.groupStopWaitable = true
	t.tg.groupContNotify = false
	t.tg.groupContWaitable = false
	return true
}

// signalStop sends a signal to t's thread group of a new group stop, group
// continue, or ptrace stop, if appropriate. code and status are set in the
// signal sent to tg, if any.
//
// Preconditions: The TaskSet mutex must be locked (for reading or writing).
func (t *Task) signalStop(target *Task, code int32, status int32) {
	t.tg.signalHandlers.mu.Lock()
	defer t.tg.signalHandlers.mu.Unlock()
	act, ok := t.tg.signalHandlers.actions[linux.SIGCHLD]
	if !ok || (act.Handler != arch.SignalActIgnore && act.Flags&arch.SignalFlagNoCldStop == 0) {
		sigchld := &arch.SignalInfo{
			Signo: int32(linux.SIGCHLD),
			Code:  code,
		}
		sigchld.SetPid(int32(t.tg.pidns.tids[target]))
		sigchld.SetUid(int32(target.Credentials().RealKUID.In(t.UserNamespace()).OrOverflow()))
		sigchld.SetStatus(status)
		// TODO(b/72102453): Set utime, stime.
		t.sendSignalLocked(sigchld, true /* group */)
	}
}

// The runInterrupt state handles conditions indicated by interrupts.
//
// +stateify savable
type runInterrupt struct{}

func (*runInterrupt) execute(t *Task) taskRunState {
	// Interrupts are de-duplicated (if t is interrupted twice before
	// t.interrupted() is called, t.interrupted() will only return true once),
	// so early exits from this function must re-enter the runInterrupt state
	// to check for more interrupt-signaled conditions.

	t.tg.signalHandlers.mu.Lock()

	// Did we just leave a group stop?
	if t.tg.groupContNotify {
		t.tg.groupContNotify = false
		sig := t.tg.groupStopSignal
		intr := t.tg.groupContInterrupted
		t.tg.signalHandlers.mu.Unlock()
		t.tg.pidns.owner.mu.RLock()
		// For consistency with Linux, if the parent and (thread group
		// leader's) tracer are in the same thread group, deduplicate
		// notifications.
		notifyParent := t.tg.leader.parent != nil
		if tracer := t.tg.leader.Tracer(); tracer != nil {
			if notifyParent && tracer.tg == t.tg.leader.parent.tg {
				notifyParent = false
			}
			// Sending CLD_STOPPED to the tracer doesn't really make any sense;
			// the thread group leader may have already entered the stop and
			// notified its tracer accordingly. But it's consistent with
			// Linux...
			if intr {
				tracer.signalStop(t.tg.leader, arch.CLD_STOPPED, int32(sig))
				if !notifyParent {
					tracer.tg.eventQueue.Notify(EventGroupContinue | EventTraceeStop | EventChildGroupStop)
				} else {
					tracer.tg.eventQueue.Notify(EventGroupContinue | EventTraceeStop)
				}
			} else {
				tracer.signalStop(t.tg.leader, arch.CLD_CONTINUED, int32(sig))
				tracer.tg.eventQueue.Notify(EventGroupContinue)
			}
		}
		if notifyParent {
			// If groupContInterrupted, do as Linux does and pretend the group
			// stop completed just before it ended. The theoretical behavior in
			// this case would be to send a SIGCHLD indicating the completed
			// stop, followed by a SIGCHLD indicating the continue. However,
			// SIGCHLD is a standard signal, so the latter would always be
			// dropped. Hence sending only the former is equivalent.
			if intr {
				t.tg.leader.parent.signalStop(t.tg.leader, arch.CLD_STOPPED, int32(sig))
				t.tg.leader.parent.tg.eventQueue.Notify(EventGroupContinue | EventChildGroupStop)
			} else {
				t.tg.leader.parent.signalStop(t.tg.leader, arch.CLD_CONTINUED, int32(sig))
				t.tg.leader.parent.tg.eventQueue.Notify(EventGroupContinue)
			}
		}
		t.tg.pidns.owner.mu.RUnlock()
		return (*runInterrupt)(nil)
	}

	// Do we need to enter a group stop or related ptrace stop? This path is
	// analogous to Linux's kernel/signal.c:get_signal() => do_signal_stop()
	// (with ptrace enabled) and do_jobctl_trap().
	if t.groupStopPending || t.trapStopPending || t.trapNotifyPending {
		sig := t.tg.groupStopSignal
		notifyParent := false
		if t.groupStopPending {
			t.groupStopPending = false
			// We care about t.tg.groupStopSignal (for tracer notification)
			// even if this doesn't complete a group stop, so keep the
			// value of sig we've already read.
			notifyParent = t.participateGroupStopLocked()
		}
		t.trapStopPending = false
		t.trapNotifyPending = false
		// Drop the signal mutex so we can take the TaskSet mutex.
		t.tg.signalHandlers.mu.Unlock()

		t.tg.pidns.owner.mu.RLock()
		if t.tg.leader.parent == nil {
			notifyParent = false
		}
		if tracer := t.Tracer(); tracer != nil {
			if t.ptraceSeized {
				if sig == 0 {
					sig = linux.SIGTRAP
				}
				// "If tracee was attached using PTRACE_SEIZE, group-stop is
				// indicated by PTRACE_EVENT_STOP: status>>16 ==
				// PTRACE_EVENT_STOP. This allows detection of group-stops
				// without requiring an extra PTRACE_GETSIGINFO call." -
				// "Group-stop", ptrace(2)
				t.ptraceCode = int32(sig) | linux.PTRACE_EVENT_STOP<<8
				t.ptraceSiginfo = &arch.SignalInfo{
					Signo: int32(sig),
					Code:  t.ptraceCode,
				}
				t.ptraceSiginfo.SetPid(int32(t.tg.pidns.tids[t]))
				t.ptraceSiginfo.SetUid(int32(t.Credentials().RealKUID.In(t.UserNamespace()).OrOverflow()))
			} else {
				t.ptraceCode = int32(sig)
				t.ptraceSiginfo = nil
			}
			if t.beginPtraceStopLocked() {
				tracer.signalStop(t, arch.CLD_STOPPED, int32(sig))
				// For consistency with Linux, if the parent and tracer are in the
				// same thread group, deduplicate notification signals.
				if notifyParent && tracer.tg == t.tg.leader.parent.tg {
					notifyParent = false
					tracer.tg.eventQueue.Notify(EventChildGroupStop | EventTraceeStop)
				} else {
					tracer.tg.eventQueue.Notify(EventTraceeStop)
				}
			}
		} else {
			t.tg.signalHandlers.mu.Lock()
			if !t.killedLocked() {
				t.beginInternalStopLocked((*groupStop)(nil))
			}
			t.tg.signalHandlers.mu.Unlock()
		}
		if notifyParent {
			t.tg.leader.parent.signalStop(t.tg.leader, arch.CLD_STOPPED, int32(sig))
			t.tg.leader.parent.tg.eventQueue.Notify(EventChildGroupStop)
		}
		t.tg.pidns.owner.mu.RUnlock()

		return (*runInterrupt)(nil)
	}

	// Are there signals pending?
	if info := t.dequeueSignalLocked(t.signalMask); info != nil {
		if linux.SignalSetOf(linux.Signal(info.Signo))&StopSignals != 0 {
			// Indicate that we've dequeued a stop signal before unlocking the
			// signal mutex; initiateGroupStop will check for races with
			// endGroupStopLocked after relocking it.
			t.tg.groupStopDequeued = true
		}
		if t.ptraceSignalLocked(info) {
			// Dequeueing the signal action must wait until after the
			// signal-delivery-stop ends since the tracer can change or
			// suppress the signal.
			t.tg.signalHandlers.mu.Unlock()
			return (*runInterruptAfterSignalDeliveryStop)(nil)
		}
		act := t.tg.signalHandlers.dequeueAction(linux.Signal(info.Signo))
		t.tg.signalHandlers.mu.Unlock()
		return t.deliverSignal(info, act)
	}

	t.tg.signalHandlers.mu.Unlock()
	return (*runApp)(nil)
}

// +stateify savable
type runInterruptAfterSignalDeliveryStop struct{}

func (*runInterruptAfterSignalDeliveryStop) execute(t *Task) taskRunState {
	t.tg.pidns.owner.mu.Lock()
	// Can't defer unlock: deliverSignal must be called without holding TaskSet
	// mutex.
	sig := linux.Signal(t.ptraceCode)
	defer func() {
		t.ptraceSiginfo = nil
	}()
	if !sig.IsValid() {
		t.tg.pidns.owner.mu.Unlock()
		return (*runInterrupt)(nil)
	}
	info := t.ptraceSiginfo
	if sig != linux.Signal(info.Signo) {
		info.Signo = int32(sig)
		info.Errno = 0
		info.Code = arch.SignalInfoUser
		// pid isn't a valid field for all signal numbers, but Linux
		// doesn't care (kernel/signal.c:ptrace_signal()).
		//
		// Linux uses t->parent for the tid and uid here, which is the tracer
		// if it hasn't detached or the real parent otherwise.
		parent := t.parent
		if tracer := t.Tracer(); tracer != nil {
			parent = tracer
		}
		if parent == nil {
			// Tracer has detached and t was created by Kernel.CreateProcess().
			// Pretend the parent is in an ancestor PID + user namespace.
			info.SetPid(0)
			info.SetUid(int32(auth.OverflowUID))
		} else {
			info.SetPid(int32(t.tg.pidns.tids[parent]))
			info.SetUid(int32(parent.Credentials().RealKUID.In(t.UserNamespace()).OrOverflow()))
		}
	}
	t.tg.signalHandlers.mu.Lock()
	t.tg.pidns.owner.mu.Unlock()
	// If the signal is masked, re-queue it.
	if linux.SignalSetOf(sig)&t.signalMask != 0 {
		t.sendSignalLocked(info, false /* group */)
		t.tg.signalHandlers.mu.Unlock()
		return (*runInterrupt)(nil)
	}
	act := t.tg.signalHandlers.dequeueAction(linux.Signal(info.Signo))
	t.tg.signalHandlers.mu.Unlock()
	return t.deliverSignal(info, act)
}

// SignalRegister registers a waiter for pending signals.
func (t *Task) SignalRegister(e *waiter.Entry, mask waiter.EventMask) {
	t.tg.signalHandlers.mu.Lock()
	t.signalQueue.EventRegister(e, mask)
	t.tg.signalHandlers.mu.Unlock()
}

// SignalUnregister unregisters a waiter for pending signals.
func (t *Task) SignalUnregister(e *waiter.Entry) {
	t.tg.signalHandlers.mu.Lock()
	t.signalQueue.EventUnregister(e)
	t.tg.signalHandlers.mu.Unlock()
}