diff options
| author | Ophestra <cat@gensokyo.uk> | 2025-07-29 02:21:12 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2025-07-29 02:23:06 +0900 |
| commit | b43d10468039a07ada412dcab83e8e074ab9ef46 (patch) | |
| tree | 3eca94296dea7e9c364be9e3b29e18c6d33971a2 /internal | |
| parent | ddf48a6c22d4387ff2ca2e45afbcc86fa7d81968 (diff) | |
app: integrate interrupt forwarding
This significantly increases usability of command line tools running through hakurei.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/app/app_nixos_linux_test.go | 1 | ||||
| -rw-r--r-- | internal/app/app_pd_linux_test.go | 2 | ||||
| -rw-r--r-- | internal/app/container_linux.go | 4 | ||||
| -rw-r--r-- | internal/app/shim_linux.go | 28 |
4 files changed, 27 insertions, 8 deletions
diff --git a/internal/app/app_nixos_linux_test.go b/internal/app/app_nixos_linux_test.go index ba56bfaa..c1bda924 100644 --- a/internal/app/app_nixos_linux_test.go +++ b/internal/app/app_nixos_linux_test.go @@ -144,6 +144,7 @@ var testCasesNixos = []sealTestCase{ Tmpfs("/var/run/nscd", 8192, 0755), SeccompPresets: seccomp.PresetExt | seccomp.PresetDenyTTY | seccomp.PresetDenyDevel, HostNet: true, + ForwardCancel: true, }, }, } diff --git a/internal/app/app_pd_linux_test.go b/internal/app/app_pd_linux_test.go index a2f9f246..5712a42a 100644 --- a/internal/app/app_pd_linux_test.go +++ b/internal/app/app_pd_linux_test.go @@ -71,6 +71,7 @@ var testCasesPd = []sealTestCase{ SeccompPresets: seccomp.PresetExt | seccomp.PresetDenyDevel, HostNet: true, RetainSession: true, + ForwardCancel: true, }, }, { @@ -220,6 +221,7 @@ var testCasesPd = []sealTestCase{ SeccompPresets: seccomp.PresetExt | seccomp.PresetDenyDevel, HostNet: true, RetainSession: true, + ForwardCancel: true, }, }, } diff --git a/internal/app/container_linux.go b/internal/app/container_linux.go index 98cddc7a..baea57d9 100644 --- a/internal/app/container_linux.go +++ b/internal/app/container_linux.go @@ -32,6 +32,10 @@ func newContainer(s *hst.ContainerConfig, os sys.State, uid, gid *int) (*contain SeccompPresets: s.SeccompPresets, RetainSession: s.Tty, HostNet: s.Net, + + // the container is canceled when shim is requested to exit or receives an interrupt or termination signal; + // this behaviour is implemented in the shim + ForwardCancel: !s.ImmediateTermination, } { diff --git a/internal/app/shim_linux.go b/internal/app/shim_linux.go index 066f51da..c88c8672 100644 --- a/internal/app/shim_linux.go +++ b/internal/app/shim_linux.go @@ -9,6 +9,7 @@ import ( "os/exec" "os/signal" "runtime" + "sync/atomic" "syscall" "time" @@ -41,6 +42,10 @@ const ( ShimExitRequest = 254 // ShimExitOrphan is returned when the shim is orphaned before monitor delivers a signal. ShimExitOrphan = 3 + + // ShimWaitDelay is the duration to wait after interrupting a container's initial process + // before the container is fully killed off. + ShimWaitDelay = 5 * time.Second ) // ShimMain is the main function of the shim process and runs as the unconstrained target user. @@ -86,6 +91,7 @@ func ShimMain() { } // signal handler outcome + var cancelContainer atomic.Pointer[context.CancelFunc] go func() { buf := make([]byte, 1) for { @@ -94,23 +100,30 @@ func ShimMain() { } switch buf[0] { - case 0: + case 0: // got SIGCONT from monitor: shim exit requested + if fp := cancelContainer.Load(); params.Container.ForwardCancel && fp != nil && *fp != nil { + (*fp)() + // shim now bound by ShimWaitDelay, implemented below + continue + } + + // setup has not completed, terminate immediately hlog.Resume() os.Exit(ShimExitRequest) return - case 1: + case 1: // got SIGCONT after adoption: monitor died before delivering signal hlog.BeforeExit() os.Exit(ShimExitOrphan) return - case 2: + case 2: // unreachable log.Println("sa_sigaction got invalid siginfo") - case 3: + case 3: // got SIGCONT from unexpected process: hopefully the terminal driver log.Println("got SIGCONT from unexpected process") - default: + default: // unreachable log.Fatalf("got invalid message %d from signal handler", buf[0]) } } @@ -146,12 +159,11 @@ func ShimMain() { name = params.Container.Args[0] } ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) - defer stop() // unreachable + cancelContainer.Store(&stop) z := container.New(ctx, name) z.Params = *params.Container z.Stdin, z.Stdout, z.Stderr = os.Stdin, os.Stdout, os.Stderr - z.Cancel = func(cmd *exec.Cmd) error { return cmd.Process.Signal(os.Interrupt) } - z.WaitDelay = 2 * time.Second + z.WaitDelay = ShimWaitDelay if err := z.Start(); err != nil { hlog.PrintBaseError(err, "cannot start container:") |
