github.com/undefinedlabs/go-mpatch@v1.0.8-0.20230904093002-fbac8a0d7853/patcher_unix.go (about) 1 //go:build !windows 2 // +build !windows 3 4 package mpatch 5 6 import ( 7 "reflect" 8 "syscall" 9 "time" 10 "unsafe" 11 ) 12 13 var writeAccess = syscall.PROT_READ | syscall.PROT_WRITE | syscall.PROT_EXEC 14 var readAccess = syscall.PROT_READ | syscall.PROT_EXEC 15 16 //go:nosplit 17 func getMemorySliceFromUintptr(p uintptr, length int) []byte { 18 return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ 19 Data: p, 20 Len: length, 21 Cap: length, 22 })) 23 } 24 25 //go:nosplit 26 func callMProtect(addr unsafe.Pointer, length int, prot int) error { 27 for p := uintptr(addr) & ^(uintptr(pageSize - 1)); p < uintptr(addr)+uintptr(length); p += uintptr(pageSize) { 28 page := getMemorySliceFromUintptr(p, pageSize) 29 if err := syscall.Mprotect(page, prot); err != nil { 30 return err 31 } 32 } 33 return nil 34 } 35 36 func writeDataToPointer(ptr unsafe.Pointer, data []byte) error { 37 dataLength := len(data) 38 ptrByteSlice := getMemorySliceFromPointer(ptr, len(data)) 39 if err := callMProtect(ptr, dataLength, writeAccess); err != nil { 40 return err 41 } 42 copy(ptrByteSlice, data[:]) 43 if err := callMProtect(ptr, dataLength, readAccess); err != nil { 44 return err 45 } 46 <-time.After(100 * time.Microsecond) // If we remove this line then it fails to unpatch on ARM64 47 return nil 48 }