github.com/sagernet/gvisor@v0.0.0-20240428053021-e691de28565f/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/errors" 25 "github.com/sagernet/gvisor/pkg/errors/linuxerr" 26 "github.com/sagernet/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 }