mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
os: ignore SIGSYS in checkPidfd
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: aad6b3b32c
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>
This commit is contained in:
parent
607975cfa1
commit
a3a05ed04c
4 changed files with 51 additions and 2 deletions
|
|
@ -18,6 +18,7 @@ package os
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"internal/syscall/unix"
|
"internal/syscall/unix"
|
||||||
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
@ -151,6 +152,13 @@ var checkPidfdOnce = sync.OnceValue(checkPidfd)
|
||||||
// execution environment in which the above system calls are restricted by
|
// execution environment in which the above system calls are restricted by
|
||||||
// seccomp or a similar technology.
|
// seccomp or a similar technology.
|
||||||
func checkPidfd() error {
|
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
|
// Get a pidfd of the current process (opening of "/proc/self" won't
|
||||||
// work for waitid).
|
// work for waitid).
|
||||||
fd, err := unix.PidFDOpen(syscall.Getpid(), 0)
|
fd, err := unix.PidFDOpen(syscall.Getpid(), 0)
|
||||||
|
|
@ -192,3 +200,11 @@ func checkPidfd() error {
|
||||||
//
|
//
|
||||||
//go:linkname checkClonePidfd
|
//go:linkname checkClonePidfd
|
||||||
func checkClonePidfd() error
|
func checkClonePidfd() error
|
||||||
|
|
||||||
|
// Provided by runtime.
|
||||||
|
//
|
||||||
|
//go:linkname ignoreSIGSYS
|
||||||
|
func ignoreSIGSYS()
|
||||||
|
|
||||||
|
//go:linkname restoreSIGSYS
|
||||||
|
func restoreSIGSYS()
|
||||||
|
|
|
||||||
|
|
@ -879,8 +879,9 @@ func runPerThreadSyscall() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_SI_USER = 0
|
_SI_USER = 0
|
||||||
_SI_TKILL = -6
|
_SI_TKILL = -6
|
||||||
|
_SYS_SECCOMP = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
// sigFromUser reports whether the signal was sent because of a call
|
// sigFromUser reports whether the signal was sent because of a call
|
||||||
|
|
@ -892,6 +893,14 @@ func (c *sigctxt) sigFromUser() bool {
|
||||||
return code == _SI_USER || code == _SI_TKILL
|
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
|
//go:nosplit
|
||||||
func mprotect(addr unsafe.Pointer, n uintptr, prot int32) (ret int32, errno int32) {
|
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)
|
r, _, err := syscall.Syscall6(syscall.SYS_MPROTECT, uintptr(addr), n, uintptr(prot), 0, 0, 0)
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,10 @@ package runtime
|
||||||
func (c *sigctxt) sigFromUser() bool {
|
func (c *sigctxt) sigFromUser() bool {
|
||||||
return c.sigcode() == _SI_USER
|
return c.sigcode() == _SI_USER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sigFromSeccomp reports whether the signal was sent from seccomp.
|
||||||
|
//
|
||||||
|
//go:nosplit
|
||||||
|
func (c *sigctxt) sigFromSeccomp() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -605,6 +605,19 @@ var crashing atomic.Int32
|
||||||
var testSigtrap func(info *siginfo, ctxt *sigctxt, gp *g) bool
|
var testSigtrap func(info *siginfo, ctxt *sigctxt, gp *g) bool
|
||||||
var testSigusr1 func(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
|
// 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
|
// 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
|
// signal stack. The parameter gp will be the value of the global g
|
||||||
|
|
@ -715,6 +728,10 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if sig == _SIGSYS && c.sigFromSeccomp() && atomic.Load(&sigsysIgnored) != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if flags&_SigKill != 0 {
|
if flags&_SigKill != 0 {
|
||||||
dieFromSignal(sig)
|
dieFromSignal(sig)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue