mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime, syscall: reset signal handlers to default in child
Block all signals during a fork. In the parent process, after the fork, restore the signal mask. In the child process, reset all currently handled signals to the default handler, and then restore the signal mask. The effect of this is that the child will be operating using the same signal regime as the program it is about to exec, as exec resets all non-ignored signals to the default, and preserves the signal mask. We do this so that in the case of a signal sent to the process group, the child process will not try to run a signal handler while in the precarious state after a fork. Fixes #18600. Change-Id: I9f39aaa3884035908d687ee323c975f349d5faaa Reviewed-on: https://go-review.googlesource.com/45471 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
This commit is contained in:
parent
17ba830f46
commit
df0892cbf8
10 changed files with 158 additions and 10 deletions
|
|
@ -204,6 +204,20 @@ func sigignore(sig uint32) {
|
|||
}
|
||||
}
|
||||
|
||||
// clearSignalHandlers clears all signal handlers that are not ignored
|
||||
// back to the default. This is called by the child after a fork, so that
|
||||
// we can enable the signal mask for the exec without worrying about
|
||||
// running a signal handler in the child.
|
||||
//go:nosplit
|
||||
//go:nowritebarrierrec
|
||||
func clearSignalHandlers() {
|
||||
for i := uint32(0); i < _NSIG; i++ {
|
||||
if atomic.Load(&handlingSig[i]) != 0 {
|
||||
setsig(i, _SIG_DFL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setProcessCPUProfiler is called when the profiling timer changes.
|
||||
// It is called with prof.lock held. hz is the new timer, and is 0 if
|
||||
// profiling is being disabled. Enable or disable the signal as
|
||||
|
|
@ -310,6 +324,11 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
|
|||
}
|
||||
|
||||
setg(g.m.gsignal)
|
||||
|
||||
if g.stackguard0 == stackFork {
|
||||
signalDuringFork(sig)
|
||||
}
|
||||
|
||||
c := &sigctxt{info, ctx}
|
||||
c.fixsigcode(sig)
|
||||
sighandler(sig, info, ctx, g)
|
||||
|
|
@ -521,6 +540,16 @@ func sigNotOnStack(sig uint32) {
|
|||
throw("non-Go code set up signal handler without SA_ONSTACK flag")
|
||||
}
|
||||
|
||||
// signalDuringFork is called if we receive a signal while doing a fork.
|
||||
// We do not want signals at that time, as a signal sent to the process
|
||||
// group may be delivered to the child process, causing confusion.
|
||||
// This should never be called, because we block signals across the fork;
|
||||
// this function is just a safety check. See issue 18600 for background.
|
||||
func signalDuringFork(sig uint32) {
|
||||
println("signal", sig, "received during fork")
|
||||
throw("signal received during fork")
|
||||
}
|
||||
|
||||
// This runs on a foreign stack, without an m or a g. No stack split.
|
||||
//go:nosplit
|
||||
//go:norace
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue