aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/app/shim_linux.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/app/shim_linux.go')
-rw-r--r--internal/app/shim_linux.go62
1 files changed, 54 insertions, 8 deletions
diff --git a/internal/app/shim_linux.go b/internal/app/shim_linux.go
index 67e5fdbe..066f51da 100644
--- a/internal/app/shim_linux.go
+++ b/internal/app/shim_linux.go
@@ -3,10 +3,12 @@ package app
import (
"context"
"errors"
+ "io"
"log"
"os"
"os/exec"
"os/signal"
+ "runtime"
"syscall"
"time"
@@ -34,6 +36,13 @@ type shimParams struct {
Verbose bool
}
+const (
+ // ShimExitRequest is returned when the monitor process requests shim exit.
+ ShimExitRequest = 254
+ // ShimExitOrphan is returned when the shim is orphaned before monitor delivers a signal.
+ ShimExitOrphan = 3
+)
+
// ShimMain is the main function of the shim process and runs as the unconstrained target user.
func ShimMain() {
hlog.Prepare("shim")
@@ -58,18 +67,55 @@ func ShimMain() {
} else {
internal.InstallOutput(params.Verbose)
closeSetup = f
+ }
- // the Go runtime does not expose siginfo_t so SIGCONT is handled in C to check si_pid
- if _, err = C.hakurei_shim_setup_cont_signal(C.pid_t(params.Monitor)); err != nil {
- log.Fatalf("cannot install SIGCONT handler: %v", err)
- }
+ var signalPipe io.ReadCloser
+ // the Go runtime does not expose siginfo_t so SIGCONT is handled in C to check si_pid
+ if r, w, err := os.Pipe(); err != nil {
+ log.Fatalf("cannot pipe: %v", err)
+ } else if _, err = C.hakurei_shim_setup_cont_signal(C.pid_t(params.Monitor), C.int(w.Fd())); err != nil {
+ log.Fatalf("cannot install SIGCONT handler: %v", err)
+ } else {
+ defer runtime.KeepAlive(w)
+ signalPipe = r
+ }
- // pdeath_signal delivery is checked as if the dying process called kill(2), see kernel/exit.c
- if _, _, errno := syscall.Syscall(syscall.SYS_PRCTL, syscall.PR_SET_PDEATHSIG, uintptr(syscall.SIGCONT), 0); errno != 0 {
- log.Fatalf("cannot set parent-death signal: %v", errno)
- }
+ // pdeath_signal delivery is checked as if the dying process called kill(2), see kernel/exit.c
+ if _, _, errno := syscall.Syscall(syscall.SYS_PRCTL, syscall.PR_SET_PDEATHSIG, uintptr(syscall.SIGCONT), 0); errno != 0 {
+ log.Fatalf("cannot set parent-death signal: %v", errno)
}
+ // signal handler outcome
+ go func() {
+ buf := make([]byte, 1)
+ for {
+ if _, err := signalPipe.Read(buf); err != nil {
+ log.Fatalf("cannot read from signal pipe: %v", err)
+ }
+
+ switch buf[0] {
+ case 0:
+ hlog.Resume()
+ os.Exit(ShimExitRequest)
+ return
+
+ case 1:
+ hlog.BeforeExit()
+ os.Exit(ShimExitOrphan)
+ return
+
+ case 2:
+ log.Println("sa_sigaction got invalid siginfo")
+
+ case 3:
+ log.Println("got SIGCONT from unexpected process")
+
+ default:
+ log.Fatalf("got invalid message %d from signal handler", buf[0])
+ }
+ }
+ }()
+
if params.Container == nil || params.Container.Ops == nil {
log.Fatal("invalid container params")
}