1// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Support for sanitizers. See runtime/cgo/sigaction.go.
6
7//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) || (linux && ppc64le)
8
9package runtime
10
11import "unsafe"
12
13// _cgo_sigaction is filled in by runtime/cgo when it is linked into the
14// program, so it is only non-nil when using cgo.
15//
16//go:linkname _cgo_sigaction _cgo_sigaction
17var _cgo_sigaction unsafe.Pointer
18
19//go:nosplit
20//go:nowritebarrierrec
21func sigaction(sig uint32, new, old *sigactiont) {
22	// racewalk.go avoids adding sanitizing instrumentation to package runtime,
23	// but we might be calling into instrumented C functions here,
24	// so we need the pointer parameters to be properly marked.
25	//
26	// Mark the input as having been written before the call
27	// and the output as read after.
28	if msanenabled && new != nil {
29		msanwrite(unsafe.Pointer(new), unsafe.Sizeof(*new))
30	}
31	if asanenabled && new != nil {
32		asanwrite(unsafe.Pointer(new), unsafe.Sizeof(*new))
33	}
34	if _cgo_sigaction == nil || inForkedChild {
35		sysSigaction(sig, new, old)
36	} else {
37		// We need to call _cgo_sigaction, which means we need a big enough stack
38		// for C.  To complicate matters, we may be in libpreinit (before the
39		// runtime has been initialized) or in an asynchronous signal handler (with
40		// the current thread in transition between goroutines, or with the g0
41		// system stack already in use).
42
43		var ret int32
44
45		var g *g
46		if mainStarted {
47			g = getg()
48		}
49		sp := uintptr(unsafe.Pointer(&sig))
50		switch {
51		case g == nil:
52			// No g: we're on a C stack or a signal stack.
53			ret = callCgoSigaction(uintptr(sig), new, old)
54		case sp < g.stack.lo || sp >= g.stack.hi:
55			// We're no longer on g's stack, so we must be handling a signal.  It's
56			// possible that we interrupted the thread during a transition between g
57			// and g0, so we should stay on the current stack to avoid corrupting g0.
58			ret = callCgoSigaction(uintptr(sig), new, old)
59		default:
60			// We're running on g's stack, so either we're not in a signal handler or
61			// the signal handler has set the correct g.  If we're on gsignal or g0,
62			// systemstack will make the call directly; otherwise, it will switch to
63			// g0 to ensure we have enough room to call a libc function.
64			//
65			// The function literal that we pass to systemstack is not nosplit, but
66			// that's ok: we'll be running on a fresh, clean system stack so the stack
67			// check will always succeed anyway.
68			systemstack(func() {
69				ret = callCgoSigaction(uintptr(sig), new, old)
70			})
71		}
72
73		const EINVAL = 22
74		if ret == EINVAL {
75			// libc reserves certain signals — normally 32-33 — for pthreads, and
76			// returns EINVAL for sigaction calls on those signals.  If we get EINVAL,
77			// fall back to making the syscall directly.
78			sysSigaction(sig, new, old)
79		}
80	}
81
82	if msanenabled && old != nil {
83		msanread(unsafe.Pointer(old), unsafe.Sizeof(*old))
84	}
85	if asanenabled && old != nil {
86		asanread(unsafe.Pointer(old), unsafe.Sizeof(*old))
87	}
88}
89
90// callCgoSigaction calls the sigaction function in the runtime/cgo package
91// using the GCC calling convention. It is implemented in assembly.
92//
93//go:noescape
94func callCgoSigaction(sig uintptr, new, old *sigactiont) int32
95