diff options
Diffstat (limited to 'pkg/sentry/sighandling/sighandling.go')
-rw-r--r-- | pkg/sentry/sighandling/sighandling.go | 41 |
1 files changed, 25 insertions, 16 deletions
diff --git a/pkg/sentry/sighandling/sighandling.go b/pkg/sentry/sighandling/sighandling.go index 5bac3a4e1..b08588c11 100644 --- a/pkg/sentry/sighandling/sighandling.go +++ b/pkg/sentry/sighandling/sighandling.go @@ -30,9 +30,11 @@ import ( // numSignals is the number of normal (non-realtime) signals on Linux. const numSignals = 32 -// forwardSignals listens for incoming signals and delivers them to k. It starts -// when the start channel is closed and stops when the stop channel is closed. -func forwardSignals(k *kernel.Kernel, sigchans []chan os.Signal, start, stop chan struct{}) { +// forwardSignals listens for incoming signals and delivers them to k. +// +// It starts when the start channel is closed, stops when the stop channel +// is closed, and closes done once it will no longer deliver signals to k. +func forwardSignals(k *kernel.Kernel, sigchans []chan os.Signal, start, stop, done chan struct{}) { // Build a select case. sc := []reflect.SelectCase{{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(start)}} for _, sigchan := range sigchans { @@ -47,13 +49,19 @@ func forwardSignals(k *kernel.Kernel, sigchans []chan os.Signal, start, stop cha // Was it the start / stop channel? if index == 0 { if !ok { - if started { - // stop channel - break - } else { - // start channel + if !started { + // start channel; start forwarding and + // swap this case for the stop channel + // to select stop requests. started = true sc[0] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(stop)} + } else { + // stop channel; stop forwarding and + // clear this case so it is never + // selected again. + started = false + close(done) + sc[0].Chan = reflect.Value{} } } continue @@ -69,7 +77,8 @@ func forwardSignals(k *kernel.Kernel, sigchans []chan os.Signal, start, stop cha signal := linux.Signal(index) if !started { - // Kernel is not ready to receive signals. + // Kernel cannot receive signals, either because it is + // not ready yet or is shutting down. // // Kill ourselves if this signal would have killed the // process before PrepareForwarding was called. i.e., all @@ -92,20 +101,19 @@ func forwardSignals(k *kernel.Kernel, sigchans []chan os.Signal, start, stop cha k.SendExternalSignal(&arch.SignalInfo{Signo: int32(signal)}, "sentry") } - - // Close all individual channels. - for _, sigchan := range sigchans { - signal.Stop(sigchan) - close(sigchan) - } } // PrepareForwarding ensures that synchronous signals are forwarded to k and // returns a callback that starts signal delivery, which itself returns a // callback that stops signal forwarding. +// +// Note that this function permanently takes over signal handling. After the +// stop callback, signals revert to the default Go runtime behavior, which +// cannot be overridden with external calls to signal.Notify. func PrepareForwarding(k *kernel.Kernel, skipSignal syscall.Signal) func() func() { start := make(chan struct{}) stop := make(chan struct{}) + done := make(chan struct{}) // Register individual channels. One channel per standard signal is // required as os.Notify() is non-blocking and may drop signals. To avoid @@ -126,12 +134,13 @@ func PrepareForwarding(k *kernel.Kernel, skipSignal syscall.Signal) func() func( signal.Notify(sigchan, syscall.Signal(sig)) } // Start up our listener. - go forwardSignals(k, sigchans, start, stop) // S/R-SAFE: synchronized by Kernel.extMu + go forwardSignals(k, sigchans, start, stop, done) // S/R-SAFE: synchronized by Kernel.extMu. return func() func() { close(start) return func() { close(stop) + <-done } } } |