diff options
author | Nicolas Lacasse <nlacasse@google.com> | 2018-10-17 12:27:58 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-10-17 12:29:05 -0700 |
commit | 4e6f0892c96c374b1abcf5c39b75ba52d98c97f8 (patch) | |
tree | cb21538ad26a50ff61086d55c1bef36d5026e4c0 /pkg | |
parent | 578fe5a50dcf8e104b6bce3802987b0f8c069ade (diff) |
runsc: Support job control signals for the root container.
Now containers run with "docker run -it" support control characters like ^C and
^Z.
This required refactoring our signal handling a bit. Signals delivered to the
"runsc boot" process are turned into loader.Signal calls with the appropriate
delivery mode. Previously they were always sent directly to PID 1.
PiperOrigin-RevId: 217566770
Change-Id: I5b7220d9a0f2b591a56335479454a200c6de8732
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/sentry/kernel/kernel.go | 27 | ||||
-rw-r--r-- | pkg/sentry/sighandling/BUILD | 6 | ||||
-rw-r--r-- | pkg/sentry/sighandling/sighandling.go | 25 |
3 files changed, 36 insertions, 22 deletions
diff --git a/pkg/sentry/kernel/kernel.go b/pkg/sentry/kernel/kernel.go index cc664deec..84afdb530 100644 --- a/pkg/sentry/kernel/kernel.go +++ b/pkg/sentry/kernel/kernel.go @@ -839,17 +839,40 @@ func (k *Kernel) SendContainerSignal(cid string, info *arch.SignalInfo) error { k.tasks.mu.RLock() defer k.tasks.mu.RUnlock() + var lastErr error for t := range k.tasks.Root.tids { if t == t.tg.leader && t.ContainerID() == cid { t.tg.signalHandlers.mu.Lock() defer t.tg.signalHandlers.mu.Unlock() infoCopy := *info if err := t.sendSignalLocked(&infoCopy, true /*group*/); err != nil { - return err + lastErr = err } } } - return nil + return lastErr +} + +// SendProcessGroupSignal sends a signal to all processes inside the process +// group. It is analagous to kernel/signal.c:kill_pgrp. +func (k *Kernel) SendProcessGroupSignal(pg *ProcessGroup, info *arch.SignalInfo) error { + k.extMu.Lock() + defer k.extMu.Unlock() + k.tasks.mu.RLock() + defer k.tasks.mu.RUnlock() + + var lastErr error + for t := range k.tasks.Root.tids { + if t == t.tg.leader && t.tg.ProcessGroup() == pg { + t.tg.signalHandlers.mu.Lock() + defer t.tg.signalHandlers.mu.Unlock() + infoCopy := *info + if err := t.sendSignalLocked(&infoCopy, true /*group*/); err != nil { + lastErr = err + } + } + } + return lastErr } // FeatureSet returns the FeatureSet. diff --git a/pkg/sentry/sighandling/BUILD b/pkg/sentry/sighandling/BUILD index f480f0735..751176747 100644 --- a/pkg/sentry/sighandling/BUILD +++ b/pkg/sentry/sighandling/BUILD @@ -10,9 +10,5 @@ go_library( ], importpath = "gvisor.googlesource.com/gvisor/pkg/sentry/sighandling", visibility = ["//pkg/sentry:internal"], - deps = [ - "//pkg/abi/linux", - "//pkg/sentry/arch", - "//pkg/sentry/kernel", - ], + deps = ["//pkg/abi/linux"], ) diff --git a/pkg/sentry/sighandling/sighandling.go b/pkg/sentry/sighandling/sighandling.go index 0946ab075..29bcf55ab 100644 --- a/pkg/sentry/sighandling/sighandling.go +++ b/pkg/sentry/sighandling/sighandling.go @@ -23,18 +23,17 @@ import ( "syscall" "gvisor.googlesource.com/gvisor/pkg/abi/linux" - "gvisor.googlesource.com/gvisor/pkg/sentry/arch" - "gvisor.googlesource.com/gvisor/pkg/sentry/kernel" ) // numSignals is the number of normal (non-realtime) signals on Linux. const numSignals = 32 -// forwardSignals listens for incoming signals and delivers them to k. +// handleSignals listens for incoming signals and calls the given handler +// function. // // 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{}) { +func handleSignals(sigchans []chan os.Signal, handler func(linux.Signal), start, stop, done chan struct{}) { // Build a select case. sc := []reflect.SelectCase{{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(start)}} for _, sigchan := range sigchans { @@ -98,18 +97,19 @@ func forwardSignals(k *kernel.Kernel, sigchans []chan os.Signal, start, stop, do } } - k.SendExternalSignal(&arch.SignalInfo{Signo: int32(signal)}, "sentry") + // Pass the signal to the handler. + handler(signal) } } -// 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. +// PrepareHandler ensures that synchronous signals are passed to the given +// handler function and returns a callback that starts signal delivery, which +// itself returns a callback that stops signal handling. // // 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() { +func PrepareHandler(handler func(linux.Signal)) func() func() { start := make(chan struct{}) stop := make(chan struct{}) done := make(chan struct{}) @@ -125,15 +125,10 @@ func PrepareForwarding(k *kernel.Kernel, skipSignal syscall.Signal) func() func( for sig := 1; sig <= numSignals+1; sig++ { sigchan := make(chan os.Signal, 1) sigchans = append(sigchans, sigchan) - - if syscall.Signal(sig) == skipSignal { - continue - } - signal.Notify(sigchan, syscall.Signal(sig)) } // Start up our listener. - go forwardSignals(k, sigchans, start, stop, done) // S/R-SAFE: synchronized by Kernel.extMu. + go handleSignals(sigchans, handler, start, stop, done) // S/R-SAFE: synchronized by Kernel.extMu. return func() func() { close(start) |