1// Copyright 2019 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// +build linux 6// +build 386 amd64 7 8package runtime 9 10//go:noescape 11func uname(utsname *new_utsname) int 12 13func mlock(addr, len uintptr) int 14 15func osArchInit() { 16 // Linux 5.2 introduced a bug that can corrupt vector 17 // registers on return from a signal if the signal stack isn't 18 // faulted in: 19 // https://bugzilla.kernel.org/show_bug.cgi?id=205663 20 // 21 // It was fixed in 5.3.15, 5.4.2, and all 5.5 and later 22 // kernels. 23 // 24 // If we're on an affected kernel, work around this issue by 25 // mlocking the top page of every signal stack. This doesn't 26 // help for signal stacks created in C, but there's not much 27 // we can do about that. 28 // 29 // TODO(austin): Remove this in Go 1.15, at which point it 30 // will be unlikely to encounter any of the affected kernels 31 // in the wild. 32 33 var uts new_utsname 34 if uname(&uts) < 0 { 35 throw("uname failed") 36 } 37 // Check for null terminator to ensure gostringnocopy doesn't 38 // walk off the end of the release string. 39 found := false 40 for _, b := range uts.release { 41 if b == 0 { 42 found = true 43 break 44 } 45 } 46 if !found { 47 return 48 } 49 rel := gostringnocopy(&uts.release[0]) 50 51 major, minor, patch, ok := parseRelease(rel) 52 if !ok { 53 return 54 } 55 56 if major == 5 && (minor == 2 || minor == 3 && patch < 15 || minor == 4 && patch < 2) { 57 gsignalInitQuirk = mlockGsignal 58 if m0.gsignal != nil { 59 throw("gsignal quirk too late") 60 } 61 } 62} 63 64func mlockGsignal(gsignal *g) { 65 if err := mlock(gsignal.stack.hi-physPageSize, physPageSize); err < 0 { 66 printlock() 67 println("runtime: mlock of signal stack failed:", -err) 68 if err == -_ENOMEM { 69 println("runtime: increase the mlock limit (ulimit -l) or") 70 } 71 println("runtime: update your kernel to 5.3.15+, 5.4.2+, or 5.5+") 72 throw("mlock failed") 73 } 74} 75