github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/pkg/sentry/platform/ptrace/ptrace_unsafe.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 ptrace 16 17 import ( 18 "unsafe" 19 20 "github.com/ttpreport/gvisor-ligolo/pkg/abi/linux" 21 "github.com/ttpreport/gvisor-ligolo/pkg/hostarch" 22 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/arch" 23 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/arch/fpu" 24 "golang.org/x/sys/unix" 25 ) 26 27 // getRegs gets the general purpose register set. 28 func (t *thread) getRegs(regs *arch.Registers) error { 29 iovec := unix.Iovec{ 30 Base: (*byte)(unsafe.Pointer(regs)), 31 Len: uint64(unsafe.Sizeof(*regs)), 32 } 33 _, _, errno := unix.RawSyscall6( 34 unix.SYS_PTRACE, 35 unix.PTRACE_GETREGSET, 36 uintptr(t.tid), 37 linux.NT_PRSTATUS, 38 uintptr(unsafe.Pointer(&iovec)), 39 0, 0) 40 if errno != 0 { 41 return errno 42 } 43 return nil 44 } 45 46 // setRegs sets the general purpose register set. 47 func (t *thread) setRegs(regs *arch.Registers) error { 48 iovec := unix.Iovec{ 49 Base: (*byte)(unsafe.Pointer(regs)), 50 Len: uint64(unsafe.Sizeof(*regs)), 51 } 52 _, _, errno := unix.RawSyscall6( 53 unix.SYS_PTRACE, 54 unix.PTRACE_SETREGSET, 55 uintptr(t.tid), 56 linux.NT_PRSTATUS, 57 uintptr(unsafe.Pointer(&iovec)), 58 0, 0) 59 if errno != 0 { 60 return errno 61 } 62 return nil 63 } 64 65 // getFPRegs gets the floating-point data via the GETREGSET ptrace unix. 66 func (t *thread) getFPRegs(fpState *fpu.State, ac *archContext) error { 67 iovec := unix.Iovec{ 68 Base: fpState.BytePointer(), 69 Len: ac.floatingPointLength(), 70 } 71 _, _, errno := unix.RawSyscall6( 72 unix.SYS_PTRACE, 73 unix.PTRACE_GETREGSET, 74 uintptr(t.tid), 75 ac.floatingPointRegSet(), 76 uintptr(unsafe.Pointer(&iovec)), 77 0, 0) 78 if errno != 0 { 79 return errno 80 } 81 return nil 82 } 83 84 // setFPRegs sets the floating-point data via the SETREGSET ptrace unix. 85 func (t *thread) setFPRegs(fpState *fpu.State, ac *archContext) error { 86 iovec := unix.Iovec{ 87 Base: fpState.BytePointer(), 88 Len: ac.floatingPointLength(), 89 } 90 _, _, errno := unix.RawSyscall6( 91 unix.SYS_PTRACE, 92 unix.PTRACE_SETREGSET, 93 uintptr(t.tid), 94 ac.floatingPointRegSet(), 95 uintptr(unsafe.Pointer(&iovec)), 96 0, 0) 97 if errno != 0 { 98 return errno 99 } 100 return nil 101 } 102 103 // getSignalInfo retrieves information about the signal that caused the stop. 104 func (t *thread) getSignalInfo(si *linux.SignalInfo) error { 105 _, _, errno := unix.RawSyscall6( 106 unix.SYS_PTRACE, 107 unix.PTRACE_GETSIGINFO, 108 uintptr(t.tid), 109 0, 110 uintptr(unsafe.Pointer(si)), 111 0, 0) 112 if errno != 0 { 113 return errno 114 } 115 return nil 116 } 117 118 // clone creates a new thread from this one. 119 // 120 // The returned thread will be stopped and available for any system thread to 121 // call attach on it. 122 // 123 // Precondition: the OS thread must be locked and own t. 124 func (t *thread) clone() (*thread, error) { 125 r, ok := hostarch.Addr(stackPointer(&t.initRegs)).RoundUp() 126 if !ok { 127 return nil, unix.EINVAL 128 } 129 rval, err := t.syscallIgnoreInterrupt( 130 &t.initRegs, 131 unix.SYS_CLONE, 132 arch.SyscallArgument{Value: uintptr( 133 unix.CLONE_FILES | 134 unix.CLONE_FS | 135 unix.CLONE_SIGHAND | 136 unix.CLONE_THREAD | 137 unix.CLONE_PTRACE | 138 unix.CLONE_VM)}, 139 // The stack pointer is just made up, but we have it be 140 // something sensible so the kernel doesn't think we're 141 // up to no good. Which we are. 142 arch.SyscallArgument{Value: uintptr(r)}, 143 arch.SyscallArgument{}, 144 arch.SyscallArgument{}, 145 // We use these registers initially, but really they 146 // could be anything. We're going to stop immediately. 147 arch.SyscallArgument{Value: uintptr(unsafe.Pointer(&t.initRegs))}) 148 if err != nil { 149 return nil, err 150 } 151 152 return &thread{ 153 tgid: t.tgid, 154 tid: int32(rval), 155 cpu: ^uint32(0), 156 }, nil 157 } 158 159 // getEventMessage retrieves a message about the ptrace event that just happened. 160 func (t *thread) getEventMessage() (uintptr, error) { 161 var msg uintptr 162 _, _, errno := unix.RawSyscall6( 163 unix.SYS_PTRACE, 164 unix.PTRACE_GETEVENTMSG, 165 uintptr(t.tid), 166 0, 167 uintptr(unsafe.Pointer(&msg)), 168 0, 0) 169 if errno != 0 { 170 return msg, errno 171 } 172 return msg, nil 173 }