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_