github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/platform/systrap/subprocess_arm64.go (about) 1 // Copyright 2019 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 //go:build arm64 16 // +build arm64 17 18 package systrap 19 20 import ( 21 "fmt" 22 "strings" 23 24 "golang.org/x/sys/unix" 25 "github.com/nicocha30/gvisor-ligolo/pkg/abi/linux" 26 "github.com/nicocha30/gvisor-ligolo/pkg/seccomp" 27 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/arch" 28 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/platform/systrap/sysmsg" 29 ) 30 31 const ( 32 // initRegsRipAdjustment is the size of the svc instruction. 33 initRegsRipAdjustment = 4 34 ) 35 36 // resetSysemuRegs sets up emulation registers. 37 // 38 // This should be called prior to calling sysemu. 39 func (s *subprocess) resetSysemuRegs(regs *arch.Registers) { 40 } 41 42 // createSyscallRegs sets up syscall registers. 43 // 44 // This should be called to generate registers for a system call. 45 func createSyscallRegs(initRegs *arch.Registers, sysno uintptr, args ...arch.SyscallArgument) arch.Registers { 46 // Copy initial registers (Pc, Sp, etc.). 47 regs := *initRegs 48 49 // Set our syscall number. 50 // r8 for the syscall number. 51 // r0-r6 is used to store the parameters. 52 regs.Regs[8] = uint64(sysno) 53 if len(args) >= 1 { 54 regs.Regs[0] = args[0].Uint64() 55 } 56 if len(args) >= 2 { 57 regs.Regs[1] = args[1].Uint64() 58 } 59 if len(args) >= 3 { 60 regs.Regs[2] = args[2].Uint64() 61 } 62 if len(args) >= 4 { 63 regs.Regs[3] = args[3].Uint64() 64 } 65 if len(args) >= 5 { 66 regs.Regs[4] = args[4].Uint64() 67 } 68 if len(args) >= 6 { 69 regs.Regs[5] = args[5].Uint64() 70 } 71 72 return regs 73 } 74 75 // updateSyscallRegs updates registers after finishing sysemu. 76 func updateSyscallRegs(regs *arch.Registers) { 77 // No special work is necessary. 78 return 79 } 80 81 // syscallReturnValue extracts a sensible return from registers. 82 func syscallReturnValue(regs *arch.Registers) (uintptr, error) { 83 rval := int64(regs.Regs[0]) 84 if rval < 0 { 85 return 0, unix.Errno(-rval) 86 } 87 return uintptr(rval), nil 88 } 89 90 func dumpRegs(regs *arch.Registers) string { 91 var m strings.Builder 92 93 fmt.Fprintf(&m, "Registers:\n") 94 95 for i := 0; i < 31; i++ { 96 fmt.Fprintf(&m, "\tRegs[%d]\t = %016x\n", i, regs.Regs[i]) 97 } 98 fmt.Fprintf(&m, "\tSp\t = %016x\n", regs.Sp) 99 fmt.Fprintf(&m, "\tPc\t = %016x\n", regs.Pc) 100 fmt.Fprintf(&m, "\tPstate\t = %016x\n", regs.Pstate) 101 102 return m.String() 103 } 104 105 // adjustInitregsRip adjust the current register RIP value to 106 // be just before the system call instruction execution. 107 func (t *thread) adjustInitRegsRip() { 108 t.initRegs.Pc -= initRegsRipAdjustment 109 } 110 111 // Pass the expected PPID to the child via X7 when creating stub process 112 func initChildProcessPPID(initregs *arch.Registers, ppid int32) { 113 initregs.Regs[7] = uint64(ppid) 114 // R9 has to be set to 1 when creating stub process. 115 initregs.Regs[9] = _NEW_STUB 116 } 117 118 func maybePatchSignalInfo(regs *arch.Registers, signalInfo *linux.SignalInfo) (patched bool) { 119 // vsyscall emulation is not supported on ARM64. No need to patch anything. 120 return false 121 } 122 123 // Noop on arm64. 124 // 125 //go:nosplit 126 func enableCpuidFault() { 127 } 128 129 // appendArchSeccompRules append architecture specific seccomp rules when creating BPF program. 130 // Ref attachedThread() for more detail. 131 func appendArchSeccompRules(rules []seccomp.RuleSet) []seccomp.RuleSet { 132 return rules 133 } 134 135 // probeSeccomp returns true if seccomp is run after ptrace notifications, 136 // which is generally the case for kernel version >= 4.8. 137 // 138 // On arm64, the support of PTRACE_SYSEMU was added in the 5.3 kernel, so 139 // probeSeccomp can always return true. 140 func probeSeccomp() bool { 141 return true 142 } 143 144 func (s *subprocess) arm64SyscallWorkaround(t *thread, regs *arch.Registers) { 145 // On ARM64, when ptrace stops on a system call, it uses the x7 146 // register to indicate whether the stop has been signalled from 147 // syscall entry or syscall exit. This means that we can't get a value 148 // of this register and we can't change it. More details are in the 149 // comment for tracehook_report_syscall in arch/arm64/kernel/ptrace.c. 150 // 151 // This happens only if we stop on a system call, so let's queue a 152 // signal, resume a stub thread and catch it on a signal handling. 153 t.NotifyInterrupt() 154 for { 155 if _, _, errno := unix.RawSyscall6( 156 unix.SYS_PTRACE, 157 unix.PTRACE_SYSEMU, 158 uintptr(t.tid), 0, 0, 0, 0); errno != 0 { 159 panic(fmt.Sprintf("ptrace sysemu failed: %v", errno)) 160 } 161 162 // Wait for the syscall-enter stop. 163 sig := t.wait(stopped) 164 if sig == unix.SIGSTOP { 165 // SIGSTOP was delivered to another thread in the same thread 166 // group, which initiated another group stop. Just ignore it. 167 continue 168 } 169 if sig == (syscallEvent | unix.SIGTRAP) { 170 t.dumpAndPanic(fmt.Sprintf("unexpected syscall event")) 171 } 172 break 173 } 174 if err := t.getRegs(regs); err != nil { 175 panic(fmt.Sprintf("ptrace get regs failed: %v", err)) 176 } 177 } 178 179 func restoreArchSpecificState(ctx *sysmsg.ThreadContext, ac *arch.Context64) { 180 ctx.TLS = uint64(ac.TLS()) 181 } 182 183 func setArchSpecificRegs(sysThread *sysmsgThread, regs *arch.Registers) { 184 } 185 186 func retrieveArchSpecificState(ctx *sysmsg.ThreadContext, ac *arch.Context64) { 187 if !ac.SetTLS(uintptr(ctx.TLS)) { 188 panic(fmt.Sprintf("ac.SetTLS(%+v) failed", ctx.TLS)) 189 } 190 } 191 192 func archSpecificSysmsgThreadInit(sysThread *sysmsgThread) { 193 // Send a fake event to stop the BPF process so that it enters the sighandler. 194 if _, _, e := unix.RawSyscall(unix.SYS_TGKILL, uintptr(sysThread.thread.tgid), uintptr(sysThread.thread.tid), uintptr(unix.SIGSEGV)); e != 0 { 195 panic(fmt.Sprintf("tkill failed: %v", e)) 196 } 197 }