From d844c7bbb71929877a5407e23af515274c3def6f Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 4 Mar 2025 11:19:38 -0800 Subject: [PATCH] Allow Sentry to kill itself even when it is the init process PiperOrigin-RevId: 733399678 --- pkg/sentry/platform/ptrace/BUILD | 1 + pkg/sentry/platform/ptrace/filters.go | 7 ++++++ pkg/sentry/platform/ptrace/subprocess.go | 4 +-- pkg/sentry/platform/systrap/BUILD | 1 + pkg/sentry/platform/systrap/filters.go | 9 ++++++- pkg/sentry/platform/systrap/subprocess.go | 5 ++-- pkg/sighandling/sighandling_linux_unsafe.go | 27 +++++++++++++++++++++ 7 files changed, 48 insertions(+), 6 deletions(-) diff --git a/pkg/sentry/platform/ptrace/BUILD b/pkg/sentry/platform/ptrace/BUILD index 200782d16..38606790e 100644 --- a/pkg/sentry/platform/ptrace/BUILD +++ b/pkg/sentry/platform/ptrace/BUILD @@ -41,6 +41,7 @@ go_library( "//pkg/sentry/memmap", "//pkg/sentry/platform", "//pkg/sentry/platform/interrupt", + "//pkg/sighandling", "//pkg/sync", "@org_golang_x_sys//unix:go_default_library", ], diff --git a/pkg/sentry/platform/ptrace/filters.go b/pkg/sentry/platform/ptrace/filters.go index a93732fc8..a6773ee79 100644 --- a/pkg/sentry/platform/ptrace/filters.go +++ b/pkg/sentry/platform/ptrace/filters.go @@ -15,6 +15,8 @@ package ptrace import ( + "os" + "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/seccomp" "gvisor.dev/gvisor/pkg/sentry/platform" @@ -26,6 +28,11 @@ func (*PTrace) SeccompInfo() platform.SeccompInfo { PlatformName: "ptrace", Filters: seccomp.MakeSyscallRules(map[uintptr]seccomp.SyscallRule{ unix.SYS_PTRACE: seccomp.MatchAll{}, + unix.SYS_RT_TGSIGQUEUEINFO: seccomp.PerArg{ + seccomp.EqualTo(os.Getpid()), + seccomp.AnyValue{}, // tid + seccomp.EqualTo(unix.SIGKILL), + }, unix.SYS_TGKILL: seccomp.MatchAll{}, unix.SYS_WAIT4: seccomp.MatchAll{}, }), diff --git a/pkg/sentry/platform/ptrace/subprocess.go b/pkg/sentry/platform/ptrace/subprocess.go index d0f1df2c6..4e6bcdcb2 100644 --- a/pkg/sentry/platform/ptrace/subprocess.go +++ b/pkg/sentry/platform/ptrace/subprocess.go @@ -27,6 +27,7 @@ import ( "gvisor.dev/gvisor/pkg/sentry/arch" "gvisor.dev/gvisor/pkg/sentry/memmap" "gvisor.dev/gvisor/pkg/sentry/platform" + "gvisor.dev/gvisor/pkg/sighandling" "gvisor.dev/gvisor/pkg/sync" ) @@ -357,8 +358,7 @@ func (t *thread) unexpectedStubExit() { // these cases, we don't need to panic. There is no reasons to // think that something wrong in gVisor. log.Warningf("The ptrace stub process %v has been killed by SIGKILL.", t.tgid) - pid := os.Getpid() - unix.Tgkill(pid, pid, unix.Signal(unix.SIGKILL)) + sighandling.KillItself() } t.dumpAndPanic(fmt.Sprintf("wait failed: the process %d:%d exited: %x (err %v)", t.tgid, t.tid, msg, err)) } diff --git a/pkg/sentry/platform/systrap/BUILD b/pkg/sentry/platform/systrap/BUILD index e39e44ac7..17c8f1cd2 100644 --- a/pkg/sentry/platform/systrap/BUILD +++ b/pkg/sentry/platform/systrap/BUILD @@ -99,6 +99,7 @@ go_library( "//pkg/sentry/platform/systrap/sysmsg", "//pkg/sentry/platform/systrap/usertrap", "//pkg/sentry/usage", + "//pkg/sighandling", "//pkg/sync", "//pkg/syncevent", "@org_golang_x_sys//unix:go_default_library", diff --git a/pkg/sentry/platform/systrap/filters.go b/pkg/sentry/platform/systrap/filters.go index 932969a17..0958e6ccc 100644 --- a/pkg/sentry/platform/systrap/filters.go +++ b/pkg/sentry/platform/systrap/filters.go @@ -15,6 +15,8 @@ package systrap import ( + "os" + "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/seccomp" @@ -93,7 +95,12 @@ func (systrapSeccomp) SyscallFilters(vars precompiledseccomp.Values) seccomp.Sys }, }, unix.SYS_TGKILL: seccomp.MatchAll{}, - unix.SYS_WAIT4: seccomp.MatchAll{}, + unix.SYS_RT_TGSIGQUEUEINFO: seccomp.PerArg{ + seccomp.EqualTo(os.Getpid()), + seccomp.AnyValue{}, // tid + seccomp.EqualTo(unix.SIGKILL), + }, + unix.SYS_WAIT4: seccomp.MatchAll{}, unix.SYS_IOCTL: seccomp.Or{ seccomp.PerArg{ seccomp.NonNegativeFD{}, diff --git a/pkg/sentry/platform/systrap/subprocess.go b/pkg/sentry/platform/systrap/subprocess.go index 09491f8bb..0de9fb592 100644 --- a/pkg/sentry/platform/systrap/subprocess.go +++ b/pkg/sentry/platform/systrap/subprocess.go @@ -16,7 +16,6 @@ package systrap import ( "fmt" - "os" "runtime" "sync" "sync/atomic" @@ -36,6 +35,7 @@ import ( "gvisor.dev/gvisor/pkg/sentry/platform/systrap/sysmsg" "gvisor.dev/gvisor/pkg/sentry/platform/systrap/usertrap" "gvisor.dev/gvisor/pkg/sentry/usage" + "gvisor.dev/gvisor/pkg/sighandling" ) var ( @@ -609,8 +609,7 @@ func (t *thread) unexpectedStubExit() { // these cases, we don't need to panic. There is no reasons to // think that something wrong in gVisor. log.Warningf("The ptrace stub process %v has been killed by SIGKILL.", t.tgid) - pid := os.Getpid() - unix.Tgkill(pid, pid, unix.Signal(unix.SIGKILL)) + sighandling.KillItself() } t.dumpAndPanic(fmt.Sprintf("wait failed: the process %d:%d exited: %x (err %v)", t.tgid, t.tid, msg, err)) } diff --git a/pkg/sighandling/sighandling_linux_unsafe.go b/pkg/sighandling/sighandling_linux_unsafe.go index 68bdfac16..a42feaaef 100644 --- a/pkg/sighandling/sighandling_linux_unsafe.go +++ b/pkg/sighandling/sighandling_linux_unsafe.go @@ -19,6 +19,7 @@ package sighandling import ( "fmt" + "os" "unsafe" "golang.org/x/sys/unix" @@ -74,3 +75,29 @@ func ReplaceSignalHandler(sig unix.Signal, handler uintptr, previous *uintptr) e return nil } + +// KillItself sends SIGKILL to the current process, bypassing the init process +// restriction. +// +// The standard `kill(getpid(), SIGKILL)` syscall doesn't work when the current +// process is the init process within its PID namespace. This is a "known" +// Linux feature. +// +// This function uses the rt_tgqueueinfo syscall to send a "kernel-generated" +// SIGKILL. +func KillItself() error { + pid := os.Getpid() + tid, _, _ := unix.RawSyscall(unix.SYS_GETTID, 0, 0, 0) + info := linux.SignalInfo{Code: linux.SI_KERNEL} + // The current thread can send a fake kernel siginfo to itself. + if _, _, e := unix.RawSyscall6( + unix.SYS_RT_TGSIGQUEUEINFO, + uintptr(pid), uintptr(tid), + uintptr(linux.SIGKILL), + uintptr(unsafe.Pointer(&info)), + 0, 0, + ); e != 0 { + return e + } + panic("unreachable") +}