aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2017-07-19 23:42:27 -0700
committerIan Lance Taylor <iant@golang.org>2017-07-20 18:02:47 +0000
commit28f650a2f7718b4fa7f55e06a0f75a85df90c517 (patch)
tree360183af955c160ae6b94af195f54aff1ece793a
parent5125a967100643cebc4501e3d626b44b5ab15747 (diff)
downloadgo-28f650a2f7718b4fa7f55e06a0f75a85df90c517.tar.gz
go-28f650a2f7718b4fa7f55e06a0f75a85df90c517.zip
runtime: don't call libc sigaction function in forked child
If we are using vfork, and if something (such as TSAN) is intercepting the sigaction function, then we must call the system call, not the libc function. Otherwise the intercepted sigaction call in the child may trash the data structures in the parent. Change-Id: Id9588bfeaa934f32c920bf829c5839be5cacf243 Reviewed-on: https://go-review.googlesource.com/50251 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com> Reviewed-by: Austin Clements <austin@google.com>
-rw-r--r--src/runtime/cgo_sigaction.go2
-rw-r--r--src/runtime/proc.go17
2 files changed, 18 insertions, 1 deletions
diff --git a/src/runtime/cgo_sigaction.go b/src/runtime/cgo_sigaction.go
index 4da2f401b5..713490d353 100644
--- a/src/runtime/cgo_sigaction.go
+++ b/src/runtime/cgo_sigaction.go
@@ -30,7 +30,7 @@ func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32 {
var ret int32
- if _cgo_sigaction == nil {
+ if _cgo_sigaction == nil || inForkedChild {
ret = sysSigaction(sig, new, old, size)
} else {
// We need to call _cgo_sigaction, which means we need a big enough stack
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 4f61f6164b..a5ada4f6db 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -2851,18 +2851,35 @@ func syscall_runtime_AfterFork() {
systemstack(afterfork)
}
+// inForkedChild is true while manipulating signals in the child process.
+// This is used to avoid calling libc functions in case we are using vfork.
+var inForkedChild bool
+
// Called from syscall package after fork in child.
// It resets non-sigignored signals to the default handler, and
// restores the signal mask in preparation for the exec.
+//
+// Because this might be called during a vfork, and therefore may be
+// temporarily sharing address space with the parent process, this must
+// not change any global variables or calling into C code that may do so.
+//
//go:linkname syscall_runtime_AfterForkInChild syscall.runtime_AfterForkInChild
//go:nosplit
//go:nowritebarrierrec
func syscall_runtime_AfterForkInChild() {
+ // It's OK to change the global variable inForkedChild here
+ // because we are going to change it back. There is no race here,
+ // because if we are sharing address space with the parent process,
+ // then the parent process can not be running concurrently.
+ inForkedChild = true
+
clearSignalHandlers()
// When we are the child we are the only thread running,
// so we know that nothing else has changed gp.m.sigmask.
msigrestore(getg().m.sigmask)
+
+ inForkedChild = false
}
// Called from syscall package before Exec.