github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/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/metacubex/gvisor/pkg/errors"
    25  	"github.com/metacubex/gvisor/pkg/errors/linuxerr"
    26  	"github.com/metacubex/gvisor/pkg/sighandling"
    27  )
    28  
    29  // SegvError is returned when a safecopy function receives SIGSEGV.
    30  type SegvError struct {
    31  	// Addr is the address at which the SIGSEGV occurred.
    32  	Addr uintptr
    33  }
    34  
    35  // Error implements error.Error.
    36  func (e SegvError) Error() string {
    37  	return fmt.Sprintf("SIGSEGV at %#x", e.Addr)
    38  }
    39  
    40  // BusError is returned when a safecopy function receives SIGBUS.
    41  type BusError struct {
    42  	// Addr is the address at which the SIGBUS occurred.
    43  	Addr uintptr
    44  }
    45  
    46  // Error implements error.Error.
    47  func (e BusError) Error() string {
    48  	return fmt.Sprintf("SIGBUS at %#x", e.Addr)
    49  }
    50  
    51  // AlignmentError is returned when a safecopy function is passed an address
    52  // that does not meet alignment requirements.
    53  type AlignmentError struct {
    54  	// Addr is the invalid address.
    55  	Addr uintptr
    56  
    57  	// Alignment is the required alignment.
    58  	Alignment uintptr
    59  }
    60  
    61  // Error implements error.Error.
    62  func (e AlignmentError) Error() string {
    63  	return fmt.Sprintf("address %#x is not aligned to a %d-byte boundary", e.Addr, e.Alignment)
    64  }
    65  
    66  var (
    67  	// The begin and end addresses below are for the functions that are
    68  	// checked by the signal handler.
    69  	memcpyBegin               uintptr
    70  	memcpyEnd                 uintptr
    71  	memclrBegin               uintptr
    72  	memclrEnd                 uintptr
    73  	swapUint32Begin           uintptr
    74  	swapUint32End             uintptr
    75  	swapUint64Begin           uintptr
    76  	swapUint64End             uintptr
    77  	compareAndSwapUint32Begin uintptr
    78  	compareAndSwapUint32End   uintptr
    79  	loadUint32Begin           uintptr
    80  	loadUint32End             uintptr
    81  
    82  	// savedSigSegVHandler is a pointer to the SIGSEGV handler that was
    83  	// configured before we replaced it with our own. We still call into it
    84  	// when we get a SIGSEGV that is not interesting to us.
    85  	savedSigSegVHandler uintptr
    86  
    87  	// Same as above, but for SIGBUS signals.
    88  	savedSigBusHandler uintptr
    89  )
    90  
    91  // signalHandler is our replacement signal handler for SIGSEGV and SIGBUS
    92  // signals.
    93  func signalHandler()
    94  
    95  // addrOfSignalHandler returns the start address of signalHandler.
    96  //
    97  // See comment on addrOfMemcpy for more details.
    98  func addrOfSignalHandler() uintptr
    99  
   100  // FindEndAddress returns the end address (one byte beyond the last) of the
   101  // function that contains the specified address (begin).
   102  func FindEndAddress(begin uintptr) uintptr {
   103  	f := runtime.FuncForPC(begin)
   104  	if f != nil {
   105  		for p := begin; ; p++ {
   106  			g := runtime.FuncForPC(p)
   107  			if f != g {
   108  				return p
   109  			}
   110  		}
   111  	}
   112  	return begin
   113  }
   114  
   115  // initializeAddresses initializes the addresses used by the signal handler.
   116  func initializeAddresses() {
   117  	// The following functions are written in assembly language, so they won't
   118  	// be inlined by the existing compiler/linker. Tests will fail if this
   119  	// assumption is violated.
   120  	memcpyBegin = addrOfMemcpy()
   121  	memcpyEnd = FindEndAddress(memcpyBegin)
   122  	memclrBegin = addrOfMemclr()
   123  	memclrEnd = FindEndAddress(memclrBegin)
   124  	swapUint32Begin = addrOfSwapUint32()
   125  	swapUint32End = FindEndAddress(swapUint32Begin)
   126  	swapUint64Begin = addrOfSwapUint64()
   127  	swapUint64End = FindEndAddress(swapUint64Begin)
   128  	compareAndSwapUint32Begin = addrOfCompareAndSwapUint32()
   129  	compareAndSwapUint32End = FindEndAddress(compareAndSwapUint32Begin)
   130  	loadUint32Begin = addrOfLoadUint32()
   131  	loadUint32End = FindEndAddress(loadUint32Begin)
   132  	initializeArchAddresses()
   133  }
   134  
   135  func init() {
   136  	initializeAddresses()
   137  	if err := sighandling.ReplaceSignalHandler(unix.SIGSEGV, addrOfSignalHandler(), &savedSigSegVHandler); err != nil {
   138  		panic(fmt.Sprintf("Unable to set handler for SIGSEGV: %v", err))
   139  	}
   140  	if err := sighandling.ReplaceSignalHandler(unix.SIGBUS, addrOfSignalHandler(), &savedSigBusHandler); err != nil {
   141  		panic(fmt.Sprintf("Unable to set handler for SIGBUS: %v", err))
   142  	}
   143  	linuxerr.AddErrorUnwrapper(func(e error) (*errors.Error, bool) {
   144  		switch e.(type) {
   145  		case SegvError, BusError, AlignmentError:
   146  			return linuxerr.EFAULT, true
   147  		default:
   148  			return nil, false
   149  		}
   150  	})
   151  }