diff options
-rw-r--r-- | pkg/sentry/sighandling/sighandling.go | 5 | ||||
-rw-r--r-- | runsc/boot/config.go | 6 | ||||
-rw-r--r-- | runsc/boot/loader.go | 14 | ||||
-rw-r--r-- | runsc/cmd/debug.go | 10 | ||||
-rw-r--r-- | runsc/main.go | 2 |
5 files changed, 33 insertions, 4 deletions
diff --git a/pkg/sentry/sighandling/sighandling.go b/pkg/sentry/sighandling/sighandling.go index 25295440c..5bac3a4e1 100644 --- a/pkg/sentry/sighandling/sighandling.go +++ b/pkg/sentry/sighandling/sighandling.go @@ -103,7 +103,7 @@ func forwardSignals(k *kernel.Kernel, sigchans []chan os.Signal, start, stop cha // 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. -func PrepareForwarding(k *kernel.Kernel, enablePanicSignal bool) func() func() { +func PrepareForwarding(k *kernel.Kernel, skipSignal syscall.Signal) func() func() { start := make(chan struct{}) stop := make(chan struct{}) @@ -119,8 +119,7 @@ func PrepareForwarding(k *kernel.Kernel, enablePanicSignal bool) func() func() { sigchan := make(chan os.Signal, 1) sigchans = append(sigchans, sigchan) - // SignalPanic is handled by Run. - if enablePanicSignal && linux.Signal(sig) == kernel.SignalPanic { + if syscall.Signal(sig) == skipSignal { continue } diff --git a/runsc/boot/config.go b/runsc/boot/config.go index bc392deb3..efb8563ea 100644 --- a/runsc/boot/config.go +++ b/runsc/boot/config.go @@ -204,7 +204,12 @@ type Config struct { // TODO: Remove this when multiple container is fully supported. MultiContainer bool + // WatchdogAction sets what action the watchdog takes when triggered. WatchdogAction watchdog.Action + + // PanicSignal register signal handling that panics. Usually set to + // SIGUSR2(12) to troubleshoot hangs. -1 disables it. + PanicSignal int } // ToFlags returns a slice of flags that correspond to the given Config. @@ -225,5 +230,6 @@ func (c *Config) ToFlags() []string { "--strace-syscalls=" + strings.Join(c.StraceSyscalls, ","), "--strace-log-size=" + strconv.Itoa(int(c.StraceLogSize)), "--watchdog-action=" + c.WatchdogAction.String(), + "--panic-signal=" + strconv.Itoa(c.PanicSignal), } } diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go index 3963ed55d..0ad830a6b 100644 --- a/runsc/boot/loader.go +++ b/runsc/boot/loader.go @@ -20,6 +20,7 @@ import ( "fmt" "math/rand" "os" + "os/signal" "runtime" "sync" "sync/atomic" @@ -229,7 +230,18 @@ func New(spec *specs.Spec, conf *Config, controllerFD int, ioFDs []int, console return nil, fmt.Errorf("failed to ignore child stop signals: %v", err) } // Ensure that signals received are forwarded to the emulated kernel. - stopSignalForwarding := sighandling.PrepareForwarding(k, false)() + ps := syscall.Signal(conf.PanicSignal) + stopSignalForwarding := sighandling.PrepareForwarding(k, ps)() + if conf.PanicSignal != -1 { + // Panics if the sentry receives 'conf.PanicSignal'. + panicChan := make(chan os.Signal, 1) + signal.Notify(panicChan, ps) + go func() { // S/R-SAFE: causes sentry panic. + <-panicChan + panic("Signal-induced panic") + }() + log.Infof("Panic signal set to %v(%d)", ps, conf.PanicSignal) + } procArgs, err := newProcess(spec, creds, utsns, ipcns, k) if err != nil { diff --git a/runsc/cmd/debug.go b/runsc/cmd/debug.go index 7952489de..b20987b2c 100644 --- a/runsc/cmd/debug.go +++ b/runsc/cmd/debug.go @@ -15,6 +15,8 @@ package cmd import ( + "syscall" + "context" "flag" "github.com/google/subcommands" @@ -27,6 +29,7 @@ import ( type Debug struct { pid int stacks bool + signal int } // Name implements subcommands.Command. @@ -48,6 +51,7 @@ func (*Debug) Usage() string { func (d *Debug) SetFlags(f *flag.FlagSet) { f.IntVar(&d.pid, "pid", 0, "sandbox process ID. Container ID is not necessary if this is set") f.BoolVar(&d.stacks, "stacks", false, "if true, dumps all sandbox stacks to the log") + f.IntVar(&d.signal, "signal", -1, "sends signal to the sandbox") } // Execute implements subcommands.Command.Execute. @@ -96,6 +100,12 @@ func (d *Debug) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) Fatalf("sandbox %q is not running", c.Sandbox.ID) } + if d.signal > 0 { + log.Infof("Sending signal %d to process: %d", d.signal, c.Sandbox.Pid) + if err := syscall.Kill(c.Sandbox.Pid, syscall.Signal(d.signal)); err != nil { + Fatalf("failed to send signal %d to processs %d", d.signal, c.Sandbox.Pid) + } + } if d.stacks { log.Infof("Retrieving sandbox stacks") stacks, err := c.Sandbox.Stacks() diff --git a/runsc/main.go b/runsc/main.go index 0a2cbca6c..773ec6486 100644 --- a/runsc/main.go +++ b/runsc/main.go @@ -61,6 +61,7 @@ var ( overlay = flag.Bool("overlay", false, "wrap filesystem mounts with writable overlay. All modifications are stored in memory inside the sandbox.") multiContainer = flag.Bool("multi-container", false, "enable *experimental* multi-container support.") watchdogAction = flag.String("watchdog-action", "log", "sets what action the watchdog takes when triggered: log (default), panic.") + panicSignal = flag.Int("panic-signal", -1, "register signal handling that panics. Usually set to SIGUSR2(12) to troubleshoot hangs. -1 disables it.") ) var gitRevision = "" @@ -139,6 +140,7 @@ func main() { StraceLogSize: *straceLogSize, MultiContainer: *multiContainer, WatchdogAction: wa, + PanicSignal: *panicSignal, } if len(*straceSyscalls) != 0 { conf.StraceSyscalls = strings.Split(*straceSyscalls, ",") |