Source file src/runtime/os_linux_x86.go

Documentation: runtime

     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  
     8  package runtime
     9  
    10  import "runtime/internal/atomic"
    11  
    12  //go:noescape
    13  func uname(utsname *new_utsname) int
    14  
    15  func mlock(addr, len uintptr) int
    16  
    17  func osArchInit() {
    18  	// Linux 5.2 introduced a bug that can corrupt vector
    19  	// registers on return from a signal if the signal stack isn't
    20  	// faulted in:
    21  	// https://bugzilla.kernel.org/show_bug.cgi?id=205663
    22  	//
    23  	// It was fixed in 5.3.15, 5.4.2, and all 5.5 and later
    24  	// kernels.
    25  	//
    26  	// If we're on an affected kernel, work around this issue by
    27  	// mlocking the top page of every signal stack. This doesn't
    28  	// help for signal stacks created in C, but there's not much
    29  	// we can do about that.
    30  	//
    31  	// TODO(austin): Remove this in Go 1.15, at which point it
    32  	// will be unlikely to encounter any of the affected kernels
    33  	// in the wild.
    34  
    35  	var uts new_utsname
    36  	if uname(&uts) < 0 {
    37  		throw("uname failed")
    38  	}
    39  	// Check for null terminator to ensure gostringnocopy doesn't
    40  	// walk off the end of the release string.
    41  	found := false
    42  	for _, b := range uts.release {
    43  		if b == 0 {
    44  			found = true
    45  			break
    46  		}
    47  	}
    48  	if !found {
    49  		return
    50  	}
    51  	rel := gostringnocopy(&uts.release[0])
    52  
    53  	major, minor, patch, ok := parseRelease(rel)
    54  	if !ok {
    55  		return
    56  	}
    57  
    58  	if major == 5 && (minor == 2 || minor == 3 && patch < 15 || minor == 4 && patch < 2) {
    59  		gsignalInitQuirk = mlockGsignal
    60  		if m0.gsignal != nil {
    61  			throw("gsignal quirk too late")
    62  		}
    63  		throwReportQuirk = throwBadKernel
    64  	}
    65  }
    66  
    67  func mlockGsignal(gsignal *g) {
    68  	if atomic.Load(&touchStackBeforeSignal) != 0 {
    69  		// mlock has already failed, don't try again.
    70  		return
    71  	}
    72  
    73  	// This mlock call may fail, but we don't report the failure.
    74  	// Instead, if something goes badly wrong, we rely on prepareSignalM
    75  	// and throwBadKernel to do further mitigation and to report a problem
    76  	// to the user if mitigation fails. This is because many
    77  	// systems have a limit on the total mlock size, and many kernels
    78  	// that appear to have bad versions are actually patched to avoid the
    79  	// bug described above. We want Go 1.14 to run on those systems.
    80  	// See #37436.
    81  	if errno := mlock(gsignal.stack.hi-physPageSize, physPageSize); errno < 0 {
    82  		atomic.Store(&touchStackBeforeSignal, uint32(-errno))
    83  	}
    84  }
    85  
    86  // throwBadKernel is called, via throwReportQuirk, by throw.
    87  func throwBadKernel() {
    88  	if errno := atomic.Load(&touchStackBeforeSignal); errno != 0 {
    89  		println("runtime: note: your Linux kernel may be buggy")
    90  		println("runtime: note: see https://golang.org/wiki/LinuxKernelSignalVectorBug")
    91  		println("runtime: note: mlock workaround for kernel bug failed with errno", errno)
    92  	}
    93  }
    94  

View as plain text