From: Jason A. Donenfeld Date: Wed, 25 Sep 2024 23:14:18 +0000 (+0200) Subject: runtime: properly compute whether PC is inside vDSO pages X-Git-Tag: go1.24rc1~826 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=ba42120723a8bb4161c4f54c93f7ab3234923473;p=gostls13.git runtime: properly compute whether PC is inside vDSO pages 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 Reviewed-by: Michael Pratt LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- diff --git a/src/runtime/vdso_linux.go b/src/runtime/vdso_linux.go index 4523615711..72b17ce4ac 100644 --- a/src/runtime/vdso_linux.go +++ b/src/runtime/vdso_linux.go @@ -97,6 +97,8 @@ type vdsoInfo struct { verdef *elfVerdef } +var vdsoLoadStart, vdsoLoadEnd uintptr + // see vdso_linux_*.go for vdsoSymbolKeys[] and vdso*Sym vars func vdsoInitFromSysinfoEhdr(info *vdsoInfo, hdr *elfEhdr) { @@ -116,6 +118,8 @@ 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: @@ -285,11 +289,5 @@ func vdsoauxv(tag, val uintptr) { // //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 }