github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/safecopy/safecopy.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package safecopy provides an efficient implementation of functions to access
    16  // memory that may result in SIGSEGV or SIGBUS being sent to the accessor.
    17  package safecopy
    18  
    19  import (
    20  	"fmt"
    21  	"runtime"
    22  
    23  	"golang.org/x/sys/unix"
    24  	"github.com/SagerNet/gvisor/pkg/syserror"
    25  )
    26  
    27  // SegvError is returned when a safecopy function receives SIGSEGV.
    28  type SegvError struct {
    29  	// Addr is the address at which the SIGSEGV occurred.
    30  	Addr uintptr
    31  }
    32  
    33  // Error implements error.Error.
    34  func (e SegvError) Error() string {
    35  	return fmt.Sprintf("SIGSEGV at %#x", e.Addr)
    36  }
    37  
    38  // BusError is returned when a safecopy function receives SIGBUS.
    39  type BusError struct {
    40  	// Addr is the address at which the SIGBUS occurred.
    41  	Addr uintptr
    42  }
    43  
    44  // Error implements error.Error.
    45  func (e BusError) Error() string {
    46  	return fmt.Sprintf("SIGBUS at %#x", e.Addr)
    47  }
    48  
    49  // AlignmentError is returned when a safecopy function is passed an address
    50  // that does not meet alignment requirements.
    51  type AlignmentError struct {
    52  	// Addr is the invalid address.
    53  	Addr uintptr
    54  
    55  	// Alignment is the required alignment.
    56  	Alignment uintptr
    57  }
    58  
    59  // Error implements error.Error.
    60  func (e AlignmentError) Error() string {
    61  	return fmt.Sprintf("address %#x is not aligned to a %d-byte boundary", e.Addr, e.Alignment)
    62  }
    63  
    64  var (
    65  	// The begin and end addresses below are for the functions that are
    66  	// checked by the signal handler.
    67  	memcpyBegin               uintptr
    68  	memcpyEnd                 uintptr
    69  	memclrBegin               uintptr
    70  	memclrEnd                 uintptr
    71  	swapUint32Begin           uintptr
    72  	swapUint32End             uintptr
    73  	swapUint64Begin           uintptr
    74  	swapUint64End             uintptr
    75  	compareAndSwapUint32Begin uintptr
    76  	compareAndSwapUint32End   uintptr
    77  	loadUint32Begin           uintptr
    78  	loadUint32End             uintptr
    79  
    80  	// savedSigSegVHandler is a pointer to the SIGSEGV handler that was
    81  	// configured before we replaced it with our own. We still call into it
    82  	// when we get a SIGSEGV that is not interesting to us.
    83  	savedSigSegVHandler uintptr
    84  
    85  	// same a above, but for SIGBUS signals.
    86  	savedSigBusHandler uintptr
    87  )
    88  
    89  // signalHandler is our replacement signal handler for SIGSEGV and SIGBUS
    90  // signals.
    91  func signalHandler()
    92  
    93  // addrOfSignalHandler returns the start address of signalHandler.
    94  //
    95  // See comment on addrOfMemcpy for more details.
    96  func addrOfSignalHandler() uintptr
    97  
    98  // FindEndAddress returns the end address (one byte beyond the last) of the
    99  // function that contains the specified address (begin).
   100  func FindEndAddress(begin uintptr) uintptr {
   101  	f := runtime.FuncForPC(begin)
   102  	if f != nil {
   103  		for p := begin; ; p++ {
   104  			g := runtime.FuncForPC(p)
   105  			if f != g {
   106  				return p
   107  			}
   108  		}
   109  	}
   110  	return begin
   111  }
   112  
   113  // initializeAddresses initializes the addresses used by the signal handler.
   114  func initializeAddresses() {
   115  	// The following functions are written in assembly language, so they won't
   116  	// be inlined by the existing compiler/linker. Tests will fail if this
   117  	// assumption is violated.
   118  	memcpyBegin = addrOfMemcpy()
   119  	memcpyEnd = FindEndAddress(memcpyBegin)
   120  	memclrBegin = addrOfMemclr()
   121  	memclrEnd = FindEndAddress(memclrBegin)
   122  	swapUint32Begin = addrOfSwapUint32()
   123  	swapUint32End = FindEndAddress(swapUint32Begin)
   124  	swapUint64Begin = addrOfSwapUint64()
   125  	swapUint64End = FindEndAddress(swapUint64Begin)
   126  	compareAndSwapUint32Begin = addrOfCompareAndSwapUint32()
   127  	compareAndSwapUint32End = FindEndAddress(compareAndSwapUint32Begin)
   128  	loadUint32Begin = addrOfLoadUint32()
   129  	loadUint32End = FindEndAddress(loadUint32Begin)
   130  }
   131  
   132  func init() {
   133  	initializeAddresses()
   134  	if err := ReplaceSignalHandler(unix.SIGSEGV, addrOfSignalHandler(), &savedSigSegVHandler); err != nil {
   135  		panic(fmt.Sprintf("Unable to set handler for SIGSEGV: %v", err))
   136  	}
   137  	if err := ReplaceSignalHandler(unix.SIGBUS, addrOfSignalHandler(), &savedSigBusHandler); err != nil {
   138  		panic(fmt.Sprintf("Unable to set handler for SIGBUS: %v", err))
   139  	}
   140  	syserror.AddErrorUnwrapper(func(e error) (unix.Errno, bool) {
   141  		switch e.(type) {
   142  		case SegvError, BusError, AlignmentError:
   143  			return unix.EFAULT, true
   144  		default:
   145  			return 0, false
   146  		}
   147  	})
   148  }