Skip to content

runtime: exit 2 from PID 1 upon SIGTERM/INT/HUP #78442

@kolyshkin

Description

@kolyshkin

Go version

go version go1.26.1 linux/amd64

Output of go env in your module/workspace:

AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/kir/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/kir/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build737629206=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE='/home/kir/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/kir/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/kir/sdk/go1.26.1'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/kir/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/kir/sdk/go1.26.1/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.26.1'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

Run a simple Go program as PID 1 (in a new Linux PID namespace).
The program has no signal handlers installed.
Send SIGTERM to it.

What did you see happen?

The program exits with exit code 2.

What did you expect to see?

Either the signal being ignored (as this is PID 1 aka init), or at least a
saner exit code.


A curious bug was reported to kubernetes 1 and runc2 recently:
sometimes runc init reports exit status of 2.

Turns out, Go runtime assumes that on any UNIX system signals such as
SIGTERM (or any other that has _sigKill flag set in sigtable) with no
signal handler set up, will result in kernel terminating the program.
This is true, except for PID 1 which gets a custom treatment from the
kernel.

As a result, when a Go program that runs as PID 1 (which is easy to
achieve in Linux by using a new PID namespace) receives such a signal,
Go runtime calls dieFromSignal which falls through all the way to
exit(2), which is very confusing to a user.

This issue can be worked around by the program by adding custom handlers
for SIGTERM/SIGINT/SIGHUP, but that requires a goroutine to handle those
signals, which, in case of runc, unnecessarily raises its NPROC/pid.max
requirement (see discussion at 2).

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugReportIssues describing a possible bug in the Go implementation.FixPendingIssues that have a fix which has not yet been reviewed or submitted.compiler/runtimeIssues related to the Go compiler and/or runtime.

    Type

    No type

    Projects

    Status

    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions