github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/kernel/pending_signals.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package kernel
    16  
    17  import (
    18  	"github.com/nicocha30/gvisor-ligolo/pkg/abi/linux"
    19  	"github.com/nicocha30/gvisor-ligolo/pkg/bits"
    20  )
    21  
    22  const (
    23  	// stdSignalCap is the maximum number of instances of a given standard
    24  	// signal that may be pending. ("[If] multiple instances of a standard
    25  	// signal are delivered while that signal is currently blocked, then only
    26  	// one instance is queued.") - signal(7)
    27  	stdSignalCap = 1
    28  
    29  	// rtSignalCap is the maximum number of instances of a given realtime
    30  	// signal that may be pending.
    31  	//
    32  	// TODO(igudger): In Linux, the minimum signal queue size is
    33  	// RLIMIT_SIGPENDING, which is by default max_threads/2.
    34  	rtSignalCap = 32
    35  )
    36  
    37  // pendingSignals holds a collection of pending signals. The zero value of
    38  // pendingSignals is a valid empty collection. pendingSignals is thread-unsafe;
    39  // users must provide synchronization.
    40  //
    41  // +stateify savable
    42  type pendingSignals struct {
    43  	// signals contains all pending signals.
    44  	//
    45  	// Note that signals is zero-indexed, but signal 1 is the first valid
    46  	// signal, so signals[0] contains signals with signo 1 etc. This offset is
    47  	// usually handled by using Signal.index().
    48  	signals [linux.SignalMaximum]pendingSignalQueue `state:".([]savedPendingSignal)"`
    49  
    50  	// Bit i of pendingSet is set iff there is at least one signal with signo
    51  	// i+1 pending.
    52  	pendingSet linux.SignalSet `state:"manual"`
    53  }
    54  
    55  // pendingSignalQueue holds a pendingSignalList for a single signal number.
    56  //
    57  // +stateify savable
    58  type pendingSignalQueue struct {
    59  	pendingSignalList
    60  	length int
    61  }
    62  
    63  // +stateify savable
    64  type pendingSignal struct {
    65  	// pendingSignalEntry links into a pendingSignalList.
    66  	pendingSignalEntry
    67  	*linux.SignalInfo
    68  
    69  	// If timer is not nil, it is the IntervalTimer which sent this signal.
    70  	timer *IntervalTimer
    71  }
    72  
    73  // enqueue enqueues the given signal. enqueue returns true on success and false
    74  // on failure (if the given signal's queue is full).
    75  //
    76  // Preconditions: info represents a valid signal.
    77  func (p *pendingSignals) enqueue(info *linux.SignalInfo, timer *IntervalTimer) bool {
    78  	sig := linux.Signal(info.Signo)
    79  	q := &p.signals[sig.Index()]
    80  	if sig.IsStandard() {
    81  		if q.length >= stdSignalCap {
    82  			return false
    83  		}
    84  	} else if q.length >= rtSignalCap {
    85  		return false
    86  	}
    87  	q.pendingSignalList.PushBack(&pendingSignal{SignalInfo: info, timer: timer})
    88  	q.length++
    89  	p.pendingSet |= linux.SignalSetOf(sig)
    90  	return true
    91  }
    92  
    93  // dequeue dequeues and returns any pending signal not masked by mask. If no
    94  // unmasked signals are pending, dequeue returns nil.
    95  func (p *pendingSignals) dequeue(mask linux.SignalSet) *linux.SignalInfo {
    96  	// "Real-time signals are delivered in a guaranteed order. Multiple
    97  	// real-time signals of the same type are delivered in the order they were
    98  	// sent. If different real-time signals are sent to a process, they are
    99  	// delivered starting with the lowest-numbered signal. (I.e., low-numbered
   100  	// signals have highest priority.) By contrast, if multiple standard
   101  	// signals are pending for a process, the order in which they are delivered
   102  	// is unspecified. If both standard and real-time signals are pending for a
   103  	// process, POSIX leaves it unspecified which is delivered first. Linux,
   104  	// like many other implementations, gives priority to standard signals in
   105  	// this case." - signal(7)
   106  	lowestPendingUnblockedBit := bits.TrailingZeros64(uint64(p.pendingSet &^ mask))
   107  	if lowestPendingUnblockedBit >= linux.SignalMaximum {
   108  		return nil
   109  	}
   110  	return p.dequeueSpecific(linux.Signal(lowestPendingUnblockedBit + 1))
   111  }
   112  
   113  func (p *pendingSignals) dequeueSpecific(sig linux.Signal) *linux.SignalInfo {
   114  	q := &p.signals[sig.Index()]
   115  	ps := q.pendingSignalList.Front()
   116  	if ps == nil {
   117  		return nil
   118  	}
   119  	q.pendingSignalList.Remove(ps)
   120  	q.length--
   121  	if q.length == 0 {
   122  		p.pendingSet &^= linux.SignalSetOf(sig)
   123  	}
   124  	if ps.timer != nil {
   125  		ps.timer.updateDequeuedSignalLocked(ps.SignalInfo)
   126  	}
   127  	return ps.SignalInfo
   128  }
   129  
   130  // discardSpecific causes all pending signals with number sig to be discarded.
   131  func (p *pendingSignals) discardSpecific(sig linux.Signal) {
   132  	q := &p.signals[sig.Index()]
   133  	for ps := q.pendingSignalList.Front(); ps != nil; ps = ps.Next() {
   134  		if ps.timer != nil {
   135  			ps.timer.signalRejectedLocked()
   136  		}
   137  	}
   138  	q.pendingSignalList.Reset()
   139  	q.length = 0
   140  	p.pendingSet &^= linux.SignalSetOf(sig)
   141  }