Black Lives Matter. Support the Equal Justice Initiative.

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

View as plain text