gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/platform/systrap/sysmsg/sysmsg.h (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  #ifndef THIRD_PARTY_GVISOR_PKG_SENTRY_PLATFORM_SYSTRAP_SYSMSG_SYSMSG_H_
    16  #define THIRD_PARTY_GVISOR_PKG_SENTRY_PLATFORM_SYSTRAP_SYSMSG_SYSMSG_H_
    17  
    18  #include <stdint.h>
    19  #include <sys/types.h>
    20  #include <sys/user.h>
    21  
    22  #include "sysmsg_offsets.h"  // NOLINT
    23  
    24  #if defined(__x86_64__)
    25  // LINT.IfChange
    26  struct arch_state {
    27    uint32_t xsave_mode;
    28    uint32_t fp_len;
    29    uint32_t fsgsbase;
    30  };
    31  // LINT.ThenChange(sysmsg_amd64.go)
    32  #else
    33  // LINT.IfChange
    34  struct arch_state {
    35    uint32_t fp_len;
    36  };
    37  // LINT.ThenChange(sysmsg_arm64.go)
    38  #endif
    39  
    40  // LINT.IfChange
    41  enum thread_state {
    42    THREAD_STATE_NONE,
    43    THREAD_STATE_DONE,
    44    THREAD_STATE_PREP,
    45    THREAD_STATE_ASLEEP,
    46    THREAD_STATE_INITIALIZING,
    47  };
    48  
    49  struct thread_context;
    50  
    51  // sysmsg contains the current state of the sysmsg thread. See: sysmsg.go:Msg
    52  struct sysmsg {
    53    struct sysmsg *self;
    54    uint64_t ret_addr;
    55    uint64_t syshandler;
    56    uint64_t syshandler_stack;
    57    uint64_t app_stack;
    58    uint32_t interrupt;
    59    uint32_t state;
    60    struct thread_context *context;
    61  
    62    // The fields above have offsets defined in sysmsg_offsets*.h
    63  
    64    int32_t fault_jump;
    65    int32_t err;
    66    int32_t err_additional;
    67    int32_t err_line;
    68    uint64_t debug;
    69    uint32_t thread_id;
    70  };
    71  
    72  enum context_state {
    73    CONTEXT_STATE_NONE,
    74    CONTEXT_STATE_SYSCALL,
    75    CONTEXT_STATE_FAULT,
    76    CONTEXT_STATE_SYSCALL_TRAP,
    77    CONTEXT_STATE_SYSCALL_NEED_TRAP,
    78    CONTEXT_STATE_INVALID,
    79  };
    80  
    81  // thread_context contains the current context of the sysmsg thread.
    82  // See sysmsg.go:SysThreadContext
    83  struct thread_context {
    84    uint8_t fpstate[MAX_FPSTATE_LEN];
    85    uint64_t fpstate_changed;
    86    struct user_regs_struct ptregs;
    87  
    88    // The fields above have offsets defined in sysmsg_offsets*.h
    89  
    90    siginfo_t siginfo;
    91    int64_t signo;
    92    uint32_t state;
    93    uint32_t interrupt;
    94    uint32_t thread_id;
    95    uint32_t last_thread_id;
    96    uint32_t sentry_fast_path;
    97    uint64_t acked_time;
    98    uint64_t state_changed_time;
    99    uint64_t tls;
   100    uint64_t debug;
   101  };
   102  
   103  enum stub_error {
   104    STUB_ERROR_BAD_SYSMSG = 0x0bad0000,
   105    STUB_ERROR_BAD_THREAD_STATE,
   106    STUB_ERROR_SPINNING_QUEUE_DECREF,
   107    STUB_ERROR_ARCH_PRCTL,
   108    STUB_ERROR_FUTEX,
   109    STUB_ERROR_BAD_CONTEXT_ID,
   110    STUB_ERROR_FPSTATE_BAD_HEADER,
   111  };
   112  
   113  #ifndef PAGE_SIZE
   114  #define PAGE_SIZE 4096
   115  #endif
   116  #define PER_THREAD_MEM_SIZE (8 * PAGE_SIZE)
   117  #define GUARD_SIZE (PAGE_SIZE)
   118  #define MSG_OFFSET_FROM_START (PER_THREAD_MEM_SIZE - PAGE_SIZE)
   119  
   120  #define SPINNING_QUEUE_MEM_SIZE PAGE_SIZE
   121  // LINT.ThenChange(sysmsg.go)
   122  
   123  #define FAULT_OPCODE 0x06  // "push %es" on x32 and invalid opcode on x64.
   124  
   125  #define __stringify_1(x...) #x
   126  #define __stringify(x...) __stringify_1(x)
   127  #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2 * !!(condition)]))
   128  
   129  extern uint64_t __export_pr_sched_core;
   130  extern uint64_t __export_deep_sleep_timeout;
   131  extern struct arch_state __export_arch_state;
   132  struct context_queue;
   133  extern struct context_queue *__export_context_queue_addr;
   134  
   135  // NOLINTBEGIN(runtime/int)
   136  static void *sysmsg_sp() {
   137    volatile int p;
   138    void *sp =
   139        (struct sysmsg *)(((long)&p) / PER_THREAD_MEM_SIZE * PER_THREAD_MEM_SIZE);
   140  
   141    _Static_assert(
   142        sizeof(struct sysmsg) < (PER_THREAD_MEM_SIZE - MSG_OFFSET_FROM_START),
   143        "The sysmsg structure is too big.");
   144    return sp;
   145  }
   146  
   147  static struct sysmsg *sysmsg_addr(void *sp) {
   148    return (struct sysmsg *)(sp + MSG_OFFSET_FROM_START);
   149  }
   150  
   151  long __syscall(long n, long a1, long a2, long a3, long a4, long a5, long a6);
   152  
   153  struct __kernel_timespec;
   154  long sys_futex(uint32_t *addr, int op, int val, struct __kernel_timespec *tv,
   155                 uint32_t *addr2, int val3);
   156  
   157  static void __panic(int err, int err_additional, long line) {
   158    void *sp = sysmsg_sp();
   159    struct sysmsg *sysmsg = sysmsg_addr(sp);
   160    struct thread_context *ctx = sysmsg->context;
   161    sysmsg->err = err;
   162    sysmsg->err_additional = err_additional;
   163    sysmsg->err_line = line;
   164    // Wake up the goroutine waiting on the current context.
   165    __atomic_store_n(&ctx->state, CONTEXT_STATE_FAULT, __ATOMIC_RELEASE);
   166    sys_futex(&ctx->state, FUTEX_WAKE, 1, NULL, NULL, 666);
   167    // crash the stub process.
   168    //
   169    // Normal user processes cannot map addresses lower than vm.mmap_min_addr
   170    // which is usually > 4K. So writing to an address <4K should crash the
   171    // process with a segfault.
   172  #pragma GCC diagnostic push
   173  #pragma GCC diagnostic ignored "-Warray-bounds"
   174    *(int *)(line % 4096) = err;
   175  #pragma GCC diagnostic pop
   176  }
   177  
   178  void memcpy(uint8_t *dest, uint8_t *src, size_t n);
   179  
   180  void __export_start(struct sysmsg *sysmsg, void *_ucontext);
   181  
   182  void restore_state(struct sysmsg *sysmsg, struct thread_context *ctx,
   183                     void *_ucontext);
   184  
   185  struct thread_context *switch_context(struct sysmsg *sysmsg,
   186                                        struct thread_context *ctx,
   187                                        enum context_state new_context_state);
   188  
   189  int wait_state(struct sysmsg *sysmsg, enum thread_state new_thread_state);
   190  void init_new_thread(void);
   191  
   192  #define panic(err, err_additional) __panic(err, err_additional, __LINE__)
   193  // NOLINTEND(runtime/int)
   194  
   195  #endif  // THIRD_PARTY_GVISOR_PKG_SENTRY_PLATFORM_SYSTRAP_SYSMSG_SYSMSG_H_