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 }