gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/platform/systrap/sysmsg/sighandler_arm64.c (about) 1 // Copyright 2020 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 #define _GNU_SOURCE 16 #include <asm/sigcontext.h> 17 #include <asm/unistd.h> 18 #include <errno.h> 19 #include <linux/audit.h> 20 #include <linux/futex.h> 21 #include <linux/unistd.h> 22 #include <signal.h> 23 #include <stddef.h> 24 #include <stdint.h> 25 #include <stdlib.h> 26 #include <sys/prctl.h> 27 #include <sys/ucontext.h> 28 29 #include "atomic.h" 30 #include "sysmsg.h" 31 #include "sysmsg_offsets.h" 32 33 // TODO(b/271631387): These globals are shared between AMD64 and ARM64; move to 34 // sysmsg_lib.c. 35 struct arch_state __export_arch_state; 36 uint64_t __export_stub_start; 37 38 long __syscall(long n, long a1, long a2, long a3, long a4, long a5, long a6) { 39 // ARM64 syscall interface passes the syscall number in x8 and the 6 arguments 40 // in x0-x5. The return value is in x0. 41 // 42 // See: https://man7.org/linux/man-pages/man2/syscall.2.html 43 register long x8 __asm__("x8") = n; 44 register long x0 __asm__("x0") = a1; 45 register long x1 __asm__("x1") = a2; 46 register long x2 __asm__("x2") = a3; 47 register long x3 __asm__("x3") = a4; 48 register long x4 __asm__("x4") = a5; 49 register long x5 __asm__("x5") = a6; 50 __asm__ __volatile__("svc #0" 51 : "=r"(x0) 52 : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5) 53 : "memory", "cc"); 54 return x0; 55 } 56 57 static __inline void set_tls(uint64_t tls) { 58 __asm__("msr tpidr_el0,%0" : : "r"(tls)); 59 } 60 61 static __inline uint64_t get_tls() { 62 uint64_t tls; 63 __asm__("mrs %0,tpidr_el0" : "=r"(tls)); 64 return tls; 65 } 66 67 long sys_futex(uint32_t *addr, int op, int val, struct __kernel_timespec *tv, 68 uint32_t *addr2, int val3) { 69 return __syscall(__NR_futex, (long)addr, (long)op, (long)val, (long)tv, 70 (long)addr2, (long)val3); 71 } 72 73 static void gregs_to_ptregs(ucontext_t *ucontext, 74 struct user_regs_struct *ptregs) { 75 // Set all registers. 76 for (int i = 0; i < 31; i++ ) { 77 ptregs->regs[i] = ucontext->uc_mcontext.regs[i]; 78 } 79 ptregs->sp = ucontext->uc_mcontext.sp; 80 ptregs->pc = ucontext->uc_mcontext.pc; 81 ptregs->pstate = ucontext->uc_mcontext.pstate; 82 } 83 84 static void ptregs_to_gregs(ucontext_t *ucontext, 85 struct user_regs_struct *ptregs) { 86 for (int i = 0; i < 31; i++ ) { 87 ucontext->uc_mcontext.regs[i] = ptregs->regs[i]; 88 } 89 ucontext->uc_mcontext.sp = ptregs->sp; 90 ucontext->uc_mcontext.pc = ptregs->pc; 91 ucontext->uc_mcontext.pstate = ptregs->pstate; 92 } 93 94 void __export_start(struct sysmsg *sysmsg, void *_ucontext) { 95 panic(0x11111111, 0); 96 } 97 98 void __export_sighandler(int signo, siginfo_t *siginfo, void *_ucontext) { 99 ucontext_t *ucontext = _ucontext; 100 void *sp = sysmsg_sp(); 101 struct sysmsg *sysmsg = sysmsg_addr(sp); 102 103 if (sysmsg != sysmsg->self) panic(STUB_ERROR_BAD_SYSMSG, 0); 104 int32_t thread_state = atomic_load(&sysmsg->state); 105 106 uint32_t ctx_state = CONTEXT_STATE_INVALID; 107 struct thread_context *ctx = NULL, *old_ctx = NULL; 108 if (thread_state == THREAD_STATE_INITIALIZING) { 109 // Find a new context and exit to restore it. 110 init_new_thread(); 111 goto init; 112 } 113 114 ctx = sysmsg->context; 115 old_ctx = sysmsg->context; 116 117 ctx->signo = signo; 118 119 gregs_to_ptregs(ucontext, &ctx->ptregs); 120 121 // Signal frames for ARM64 include 8 byte magic header before the floating 122 // point context. 123 // 124 // See: arch/arm64/include/uapi/asm/sigcontext.h 125 const uint64_t kSigframeMagicHeaderLen = sizeof(struct _aarch64_ctx); 126 // Verify the header. 127 if (((uint32_t *)&ucontext->uc_mcontext.__reserved)[0] != FPSIMD_MAGIC) { 128 panic(STUB_ERROR_FPSTATE_BAD_HEADER, 129 ((uint32_t *)&ucontext->uc_mcontext.__reserved)[0]); 130 } 131 uint8_t *fpStatePointer = 132 (uint8_t *)&ucontext->uc_mcontext.__reserved + kSigframeMagicHeaderLen; 133 134 memcpy(ctx->fpstate, fpStatePointer, __export_arch_state.fp_len); 135 ctx->tls = get_tls(); 136 ctx->siginfo = *siginfo; 137 switch (signo) { 138 case SIGSYS: { 139 ctx_state = CONTEXT_STATE_SYSCALL; 140 if (siginfo->si_arch != AUDIT_ARCH_AARCH64) { 141 // gVisor doesn't support x32 system calls, so let's change the syscall 142 // number so that it returns ENOSYS. The value added here is just a 143 // random large number which is large enough to not match any existing 144 // syscall number in linux. 145 ctx->ptregs.regs[8] += 0x86000000; 146 } 147 break; 148 } 149 case SIGCHLD: 150 case SIGSEGV: 151 case SIGBUS: 152 case SIGFPE: 153 case SIGTRAP: 154 case SIGILL: 155 ctx_state = CONTEXT_STATE_FAULT; 156 break; 157 default: 158 return; 159 } 160 161 init: 162 for (;;) { 163 ctx = switch_context(sysmsg, ctx, ctx_state); 164 165 if (atomic_load(&ctx->interrupt) != 0) { 166 // This context got interrupted while it was waiting in the queue. 167 // Setup all the necessary bits to let the sentry know this context has 168 // switched back because of it. 169 atomic_store(&ctx->interrupt, 0); 170 ctx_state = CONTEXT_STATE_FAULT; 171 ctx->signo = SIGCHLD; 172 ctx->siginfo.si_signo = SIGCHLD; 173 } else { 174 break; 175 } 176 } 177 178 if (old_ctx != ctx || ctx->last_thread_id != sysmsg->thread_id) { 179 ctx->fpstate_changed = 1; 180 } 181 restore_state(sysmsg, ctx, _ucontext); 182 } 183 184 // On ARM restore_state sets up a correct restore from the sighandler by 185 // populating _ucontext. 186 void restore_state(struct sysmsg *sysmsg, struct thread_context *ctx, 187 void *_ucontext) { 188 ucontext_t *ucontext = _ucontext; 189 struct fpsimd_context *fpctx = 190 (struct fpsimd_context *)&ucontext->uc_mcontext.__reserved; 191 uint8_t *fpStatePointer = (uint8_t *)&fpctx->fpsr; 192 193 if (atomic_load(&ctx->fpstate_changed)) { 194 memcpy(fpStatePointer, ctx->fpstate, __export_arch_state.fp_len); 195 } 196 ptregs_to_gregs(ucontext, &ctx->ptregs); 197 set_tls(ctx->tls); 198 atomic_store(&sysmsg->state, THREAD_STATE_NONE); 199 }