In Android version 11 and earlier, pidfd-related system calls
are not allowed by the seccomp policy, which causes crashes due
to SIGSYS signals.
Fixes #69065
Change-Id: Ib29631639a5cf221ac11b4d82390cb79436b8657
GitHub-Last-Rev:
aad6b3b32c81795f86bc4a9e81aad94899daf520
GitHub-Pull-Request: golang/go#69543
Reviewed-on: https://go-review.googlesource.com/c/go/+/614277
Auto-Submit: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
import (
"errors"
"internal/syscall/unix"
+ "runtime"
"sync"
"syscall"
"unsafe"
// execution environment in which the above system calls are restricted by
// seccomp or a similar technology.
func checkPidfd() error {
+ // In Android version < 12, pidfd-related system calls are not allowed
+ // by seccomp and trigger the SIGSYS signal. See issue #69065.
+ if runtime.GOOS == "android" {
+ ignoreSIGSYS()
+ defer restoreSIGSYS()
+ }
+
// Get a pidfd of the current process (opening of "/proc/self" won't
// work for waitid).
fd, err := unix.PidFDOpen(syscall.Getpid(), 0)
//
//go:linkname checkClonePidfd
func checkClonePidfd() error
+
+// Provided by runtime.
+//
+//go:linkname ignoreSIGSYS
+func ignoreSIGSYS()
+
+//go:linkname restoreSIGSYS
+func restoreSIGSYS()
}
const (
- _SI_USER = 0
- _SI_TKILL = -6
+ _SI_USER = 0
+ _SI_TKILL = -6
+ _SYS_SECCOMP = 1
)
// sigFromUser reports whether the signal was sent because of a call
return code == _SI_USER || code == _SI_TKILL
}
+// sigFromSeccomp reports whether the signal was sent from seccomp.
+//
+//go:nosplit
+func (c *sigctxt) sigFromSeccomp() bool {
+ code := int32(c.sigcode())
+ return code == _SYS_SECCOMP
+}
+
//go:nosplit
func mprotect(addr unsafe.Pointer, n uintptr, prot int32) (ret int32, errno int32) {
r, _, err := syscall.Syscall6(syscall.SYS_MPROTECT, uintptr(addr), n, uintptr(prot), 0, 0, 0)
func (c *sigctxt) sigFromUser() bool {
return c.sigcode() == _SI_USER
}
+
+// sigFromSeccomp reports whether the signal was sent from seccomp.
+//
+//go:nosplit
+func (c *sigctxt) sigFromSeccomp() bool {
+ return false
+}
var testSigtrap func(info *siginfo, ctxt *sigctxt, gp *g) bool
var testSigusr1 func(gp *g) bool
+// sigsysIgnored is non-zero if we are currently ignoring SIGSYS. See issue #69065.
+var sigsysIgnored uint32
+
+//go:linkname ignoreSIGSYS os.ignoreSIGSYS
+func ignoreSIGSYS() {
+ atomic.Store(&sigsysIgnored, 1)
+}
+
+//go:linkname restoreSIGSYS os.restoreSIGSYS
+func restoreSIGSYS() {
+ atomic.Store(&sigsysIgnored, 0)
+}
+
// sighandler is invoked when a signal occurs. The global g will be
// set to a gsignal goroutine and we will be running on the alternate
// signal stack. The parameter gp will be the value of the global g
return
}
+ if sig == _SIGSYS && c.sigFromSeccomp() && atomic.Load(&sigsysIgnored) != 0 {
+ return
+ }
+
if flags&_SigKill != 0 {
dieFromSignal(sig)
}