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  }