The old calculation just looked whether PC was within a page of a vDSO
symbol. This doesn't work because the vDSO .text might span two whole
pages, with trampolines and such redirecting PC around between them.
This manifests itself with the new vDSO getrandom() function, where on
PowerPC, the trampoline is quite far away from the actual C function it
jumps into. The effect is that the signal handler doesn't know it's
interrupting a vDSO call and forgets to restore g to R30, resulting in a
crash.
Fix this by storing the start and end of the LOAD section from the
program headers. We could be more specific and parse out the .text
section, but PT_LOAD is good enough and appears to work well.
Change-Id: I3cf16955177eedb51e28b3b1a0191b32c3327a42
Reviewed-on: https://go-review.googlesource.com/c/go/+/616015
Auto-Submit: Jason Donenfeld <Jason@zx2c4.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
verdef *elfVerdef
}
+var vdsoLoadStart, vdsoLoadEnd uintptr
+
// see vdso_linux_*.go for vdsoSymbolKeys[] and vdso*Sym vars
func vdsoInitFromSysinfoEhdr(info *vdsoInfo, hdr *elfEhdr) {
if !foundVaddr {
foundVaddr = true
info.loadOffset = info.loadAddr + uintptr(pt.p_offset-pt.p_vaddr)
+ vdsoLoadStart = info.loadOffset
+ vdsoLoadEnd = info.loadOffset + uintptr(pt.p_memsz)
}
case _PT_DYNAMIC:
//
//go:nosplit
func inVDSOPage(pc uintptr) bool {
- for _, k := range vdsoSymbolKeys {
- if *k.ptr != 0 {
- page := *k.ptr &^ (physPageSize - 1)
- return pc >= page && pc < page+physPageSize
- }
- }
- return false
+ return pc >= vdsoLoadStart && pc < vdsoLoadEnd
}