1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Note: any code in this file MUST be async-signal safe. 6 7 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" 8 9 #include <stddef.h> 10 #include <stdint.h> 11 #include <sys/syscall.h> 12 #include <unistd.h> 13 14 #include "base/logging.h" 15 #include "base/posix/eintr_wrapper.h" 16 #include "build/build_config.h" 17 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" 18 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 19 #include "sandbox/linux/seccomp-bpf/syscall.h" 20 #include "sandbox/linux/services/syscall_wrappers.h" 21 #include "sandbox/linux/system_headers/linux_syscalls.h" 22 23 #if defined(__mips__) 24 // __NR_Linux, is defined in <asm/unistd.h>. 25 #include <asm/unistd.h> 26 #endif 27 28 #define SECCOMP_MESSAGE_COMMON_CONTENT "seccomp-bpf failure" 29 #define SECCOMP_MESSAGE_CLONE_CONTENT "clone() failure" 30 #define SECCOMP_MESSAGE_PRCTL_CONTENT "prctl() failure" 31 #define SECCOMP_MESSAGE_IOCTL_CONTENT "ioctl() failure" 32 #define SECCOMP_MESSAGE_KILL_CONTENT "(tg)kill() failure" 33 #define SECCOMP_MESSAGE_FUTEX_CONTENT "futex() failure" 34 35 namespace { 36 37 inline bool IsArchitectureX86_64() { 38 #if defined(__x86_64__) 39 return true; 40 #else 41 return false; 42 #endif 43 } 44 45 // Write |error_message| to stderr. Similar to RawLog(), but a bit more careful 46 // about async-signal safety. |size| is the size to write and should typically 47 // not include a terminating \0. 48 void WriteToStdErr(const char* error_message, size_t size) { 49 while (size > 0) { 50 // TODO(jln): query the current policy to check if send() is available and 51 // use it to perform a non-blocking write. 52 const int ret = HANDLE_EINTR(write(STDERR_FILENO, error_message, size)); 53 // We can't handle any type of error here. 54 if (ret <= 0 || static_cast<size_t>(ret) > size) break; 55 size -= ret; 56 error_message += ret; 57 } 58 } 59 60 // Invalid syscall values are truncated to zero. 61 // On architectures where base value is zero (Intel and Arm), 62 // syscall number is the same as offset from base. 63 // This function returns values between 0 and 1023 on all architectures. 64 // On architectures where base value is different than zero (currently only 65 // Mips), we are truncating valid syscall values to offset from base. 66 uint32_t SyscallNumberToOffsetFromBase(uint32_t sysno) { 67 #if defined(__mips__) 68 // On MIPS syscall numbers are in different range than on x86 and ARM. 69 // Valid MIPS O32 ABI syscall __NR_syscall will be truncated to zero for 70 // simplicity. 71 sysno = sysno - __NR_Linux; 72 #endif 73 74 if (sysno >= 1024) 75 sysno = 0; 76 77 return sysno; 78 } 79 80 // Print a seccomp-bpf failure to handle |sysno| to stderr in an 81 // async-signal safe way. 82 void PrintSyscallError(uint32_t sysno) { 83 if (sysno >= 1024) 84 sysno = 0; 85 // TODO(markus): replace with async-signal safe snprintf when available. 86 const size_t kNumDigits = 4; 87 char sysno_base10[kNumDigits]; 88 uint32_t rem = sysno; 89 uint32_t mod = 0; 90 for (int i = kNumDigits - 1; i >= 0; i--) { 91 mod = rem % 10; 92 rem /= 10; 93 sysno_base10[i] = '0' + mod; 94 } 95 #if defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32) 96 static const char kSeccompErrorPrefix[] = __FILE__ 97 ":**CRASHING**:" SECCOMP_MESSAGE_COMMON_CONTENT " in syscall 4000 + "; 98 #else 99 static const char kSeccompErrorPrefix[] = 100 __FILE__":**CRASHING**:" SECCOMP_MESSAGE_COMMON_CONTENT " in syscall "; 101 #endif 102 static const char kSeccompErrorPostfix[] = "\n"; 103 WriteToStdErr(kSeccompErrorPrefix, sizeof(kSeccompErrorPrefix) - 1); 104 WriteToStdErr(sysno_base10, sizeof(sysno_base10)); 105 WriteToStdErr(kSeccompErrorPostfix, sizeof(kSeccompErrorPostfix) - 1); 106 } 107 108 } // namespace. 109 110 namespace sandbox { 111 112 intptr_t CrashSIGSYS_Handler(const struct arch_seccomp_data& args, void* aux) { 113 uint32_t syscall = SyscallNumberToOffsetFromBase(args.nr); 114 115 PrintSyscallError(syscall); 116 117 // Encode 8-bits of the 1st two arguments too, so we can discern which socket 118 // type, which fcntl, ... etc., without being likely to hit a mapped 119 // address. 120 // Do not encode more bits here without thinking about increasing the 121 // likelihood of collision with mapped pages. 122 syscall |= ((args.args[0] & 0xffUL) << 12); 123 syscall |= ((args.args[1] & 0xffUL) << 20); 124 // Purposefully dereference the syscall as an address so it'll show up very 125 // clearly and easily in crash dumps. 126 volatile char* addr = reinterpret_cast<volatile char*>(syscall); 127 *addr = '\0'; 128 // In case we hit a mapped address, hit the null page with just the syscall, 129 // for paranoia. 130 syscall &= 0xfffUL; 131 addr = reinterpret_cast<volatile char*>(syscall); 132 *addr = '\0'; 133 for (;;) 134 _exit(1); 135 } 136 137 // TODO(jln): refactor the reporting functions. 138 139 intptr_t SIGSYSCloneFailure(const struct arch_seccomp_data& args, void* aux) { 140 static const char kSeccompCloneError[] = 141 __FILE__":**CRASHING**:" SECCOMP_MESSAGE_CLONE_CONTENT "\n"; 142 WriteToStdErr(kSeccompCloneError, sizeof(kSeccompCloneError) - 1); 143 // "flags" is the first argument in the kernel's clone(). 144 // Mark as volatile to be able to find the value on the stack in a minidump. 145 volatile uint64_t clone_flags = args.args[0]; 146 volatile char* addr; 147 if (IsArchitectureX86_64()) { 148 addr = reinterpret_cast<volatile char*>(clone_flags & 0xFFFFFF); 149 *addr = '\0'; 150 } 151 // Hit the NULL page if this fails to fault. 152 addr = reinterpret_cast<volatile char*>(clone_flags & 0xFFF); 153 *addr = '\0'; 154 for (;;) 155 _exit(1); 156 } 157 158 intptr_t SIGSYSPrctlFailure(const struct arch_seccomp_data& args, 159 void* /* aux */) { 160 static const char kSeccompPrctlError[] = 161 __FILE__":**CRASHING**:" SECCOMP_MESSAGE_PRCTL_CONTENT "\n"; 162 WriteToStdErr(kSeccompPrctlError, sizeof(kSeccompPrctlError) - 1); 163 // Mark as volatile to be able to find the value on the stack in a minidump. 164 volatile uint64_t option = args.args[0]; 165 volatile char* addr = 166 reinterpret_cast<volatile char*>(option & 0xFFF); 167 *addr = '\0'; 168 for (;;) 169 _exit(1); 170 } 171 172 intptr_t SIGSYSIoctlFailure(const struct arch_seccomp_data& args, 173 void* /* aux */) { 174 static const char kSeccompIoctlError[] = 175 __FILE__":**CRASHING**:" SECCOMP_MESSAGE_IOCTL_CONTENT "\n"; 176 WriteToStdErr(kSeccompIoctlError, sizeof(kSeccompIoctlError) - 1); 177 // Make "request" volatile so that we can see it on the stack in a minidump. 178 volatile uint64_t request = args.args[1]; 179 volatile char* addr = reinterpret_cast<volatile char*>(request & 0xFFFF); 180 *addr = '\0'; 181 // Hit the NULL page if this fails. 182 addr = reinterpret_cast<volatile char*>(request & 0xFFF); 183 *addr = '\0'; 184 for (;;) 185 _exit(1); 186 } 187 188 intptr_t SIGSYSKillFailure(const struct arch_seccomp_data& args, 189 void* /* aux */) { 190 static const char kSeccompKillError[] = 191 __FILE__":**CRASHING**:" SECCOMP_MESSAGE_KILL_CONTENT "\n"; 192 WriteToStdErr(kSeccompKillError, sizeof(kSeccompKillError) - 1); 193 // Make "pid" volatile so that we can see it on the stack in a minidump. 194 volatile uint64_t my_pid = sys_getpid(); 195 volatile char* addr = reinterpret_cast<volatile char*>(my_pid & 0xFFF); 196 *addr = '\0'; 197 for (;;) 198 _exit(1); 199 } 200 201 intptr_t SIGSYSFutexFailure(const struct arch_seccomp_data& args, 202 void* /* aux */) { 203 static const char kSeccompFutexError[] = 204 __FILE__ ":**CRASHING**:" SECCOMP_MESSAGE_FUTEX_CONTENT "\n"; 205 WriteToStdErr(kSeccompFutexError, sizeof(kSeccompFutexError) - 1); 206 volatile int futex_op = args.args[1]; 207 volatile char* addr = reinterpret_cast<volatile char*>(futex_op & 0xFFF); 208 *addr = '\0'; 209 for (;;) 210 _exit(1); 211 } 212 213 intptr_t SIGSYSSchedHandler(const struct arch_seccomp_data& args, 214 void* aux) { 215 switch (args.nr) { 216 case __NR_sched_getaffinity: 217 case __NR_sched_getattr: 218 case __NR_sched_getparam: 219 case __NR_sched_getscheduler: 220 case __NR_sched_rr_get_interval: 221 case __NR_sched_setaffinity: 222 case __NR_sched_setattr: 223 case __NR_sched_setparam: 224 case __NR_sched_setscheduler: 225 const pid_t tid = sys_gettid(); 226 // The first argument is the pid. If is our thread id, then replace it 227 // with 0, which is equivalent and allowed by the policy. 228 if (args.args[0] == static_cast<uint64_t>(tid)) { 229 return Syscall::Call(args.nr, 230 0, 231 static_cast<intptr_t>(args.args[1]), 232 static_cast<intptr_t>(args.args[2]), 233 static_cast<intptr_t>(args.args[3]), 234 static_cast<intptr_t>(args.args[4]), 235 static_cast<intptr_t>(args.args[5])); 236 } 237 break; 238 } 239 240 CrashSIGSYS_Handler(args, aux); 241 242 // Should never be reached. 243 RAW_CHECK(false); 244 return -ENOSYS; 245 } 246 247 bpf_dsl::ResultExpr CrashSIGSYS() { 248 return bpf_dsl::Trap(CrashSIGSYS_Handler, NULL); 249 } 250 251 bpf_dsl::ResultExpr CrashSIGSYSClone() { 252 return bpf_dsl::Trap(SIGSYSCloneFailure, NULL); 253 } 254 255 bpf_dsl::ResultExpr CrashSIGSYSPrctl() { 256 return bpf_dsl::Trap(SIGSYSPrctlFailure, NULL); 257 } 258 259 bpf_dsl::ResultExpr CrashSIGSYSIoctl() { 260 return bpf_dsl::Trap(SIGSYSIoctlFailure, NULL); 261 } 262 263 bpf_dsl::ResultExpr CrashSIGSYSKill() { 264 return bpf_dsl::Trap(SIGSYSKillFailure, NULL); 265 } 266 267 bpf_dsl::ResultExpr CrashSIGSYSFutex() { 268 return bpf_dsl::Trap(SIGSYSFutexFailure, NULL); 269 } 270 271 bpf_dsl::ResultExpr RewriteSchedSIGSYS() { 272 return bpf_dsl::Trap(SIGSYSSchedHandler, NULL); 273 } 274 275 const char* GetErrorMessageContentForTests() { 276 return SECCOMP_MESSAGE_COMMON_CONTENT; 277 } 278 279 const char* GetCloneErrorMessageContentForTests() { 280 return SECCOMP_MESSAGE_CLONE_CONTENT; 281 } 282 283 const char* GetPrctlErrorMessageContentForTests() { 284 return SECCOMP_MESSAGE_PRCTL_CONTENT; 285 } 286 287 const char* GetIoctlErrorMessageContentForTests() { 288 return SECCOMP_MESSAGE_IOCTL_CONTENT; 289 } 290 291 const char* GetKillErrorMessageContentForTests() { 292 return SECCOMP_MESSAGE_KILL_CONTENT; 293 } 294 295 const char* GetFutexErrorMessageContentForTests() { 296 return SECCOMP_MESSAGE_FUTEX_CONTENT; 297 } 298 299 } // namespace sandbox. 300