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 <sys/syscall.h> 10 #include <unistd.h> 11 12 #include "base/basictypes.h" 13 #include "base/logging.h" 14 #include "base/posix/eintr_wrapper.h" 15 #include "build/build_config.h" 16 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 17 #include "sandbox/linux/seccomp-bpf/syscall.h" 18 #include "sandbox/linux/services/linux_syscalls.h" 19 20 #if defined(__mips__) 21 // __NR_Linux, is defined in <asm/unistd.h>. 22 #include <asm/unistd.h> 23 #endif 24 25 #define SECCOMP_MESSAGE_COMMON_CONTENT "seccomp-bpf failure" 26 #define SECCOMP_MESSAGE_CLONE_CONTENT "clone() failure" 27 #define SECCOMP_MESSAGE_PRCTL_CONTENT "prctl() failure" 28 #define SECCOMP_MESSAGE_IOCTL_CONTENT "ioctl() failure" 29 #define SECCOMP_MESSAGE_KILL_CONTENT "(tg)kill() failure" 30 #define SECCOMP_MESSAGE_FUTEX_CONTENT "futex() failure" 31 32 namespace { 33 34 inline bool IsArchitectureX86_64() { 35 #if defined(__x86_64__) 36 return true; 37 #else 38 return false; 39 #endif 40 } 41 42 // Write |error_message| to stderr. Similar to RawLog(), but a bit more careful 43 // about async-signal safety. |size| is the size to write and should typically 44 // not include a terminating \0. 45 void WriteToStdErr(const char* error_message, size_t size) { 46 while (size > 0) { 47 // TODO(jln): query the current policy to check if send() is available and 48 // use it to perform a non-blocking write. 49 const int ret = HANDLE_EINTR(write(STDERR_FILENO, error_message, size)); 50 // We can't handle any type of error here. 51 if (ret <= 0 || static_cast<size_t>(ret) > size) break; 52 size -= ret; 53 error_message += ret; 54 } 55 } 56 57 // Invalid syscall values are truncated to zero. 58 // On architectures where base value is zero (Intel and Arm), 59 // syscall number is the same as offset from base. 60 // This function returns values between 0 and 1023 on all architectures. 61 // On architectures where base value is different than zero (currently only 62 // Mips), we are truncating valid syscall values to offset from base. 63 uint32_t SyscallNumberToOffsetFromBase(uint32_t sysno) { 64 #if defined(__mips__) 65 // On MIPS syscall numbers are in different range than on x86 and ARM. 66 // Valid MIPS O32 ABI syscall __NR_syscall will be truncated to zero for 67 // simplicity. 68 sysno = sysno - __NR_Linux; 69 #endif 70 71 if (sysno >= 1024) 72 sysno = 0; 73 74 return sysno; 75 } 76 77 // Print a seccomp-bpf failure to handle |sysno| to stderr in an 78 // async-signal safe way. 79 void PrintSyscallError(uint32_t sysno) { 80 if (sysno >= 1024) 81 sysno = 0; 82 // TODO(markus): replace with async-signal safe snprintf when available. 83 const size_t kNumDigits = 4; 84 char sysno_base10[kNumDigits]; 85 uint32_t rem = sysno; 86 uint32_t mod = 0; 87 for (int i = kNumDigits - 1; i >= 0; i--) { 88 mod = rem % 10; 89 rem /= 10; 90 sysno_base10[i] = '0' + mod; 91 } 92 #if defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32) 93 static const char kSeccompErrorPrefix[] = __FILE__ 94 ":**CRASHING**:" SECCOMP_MESSAGE_COMMON_CONTENT " in syscall 4000 + "; 95 #else 96 static const char kSeccompErrorPrefix[] = 97 __FILE__":**CRASHING**:" SECCOMP_MESSAGE_COMMON_CONTENT " in syscall "; 98 #endif 99 static const char kSeccompErrorPostfix[] = "\n"; 100 WriteToStdErr(kSeccompErrorPrefix, sizeof(kSeccompErrorPrefix) - 1); 101 WriteToStdErr(sysno_base10, sizeof(sysno_base10)); 102 WriteToStdErr(kSeccompErrorPostfix, sizeof(kSeccompErrorPostfix) - 1); 103 } 104 105 } // namespace. 106 107 namespace sandbox { 108 109 intptr_t CrashSIGSYS_Handler(const struct arch_seccomp_data& args, void* aux) { 110 uint32_t syscall = SyscallNumberToOffsetFromBase(args.nr); 111 112 PrintSyscallError(syscall); 113 114 // Encode 8-bits of the 1st two arguments too, so we can discern which socket 115 // type, which fcntl, ... etc., without being likely to hit a mapped 116 // address. 117 // Do not encode more bits here without thinking about increasing the 118 // likelihood of collision with mapped pages. 119 syscall |= ((args.args[0] & 0xffUL) << 12); 120 syscall |= ((args.args[1] & 0xffUL) << 20); 121 // Purposefully dereference the syscall as an address so it'll show up very 122 // clearly and easily in crash dumps. 123 volatile char* addr = reinterpret_cast<volatile char*>(syscall); 124 *addr = '\0'; 125 // In case we hit a mapped address, hit the null page with just the syscall, 126 // for paranoia. 127 syscall &= 0xfffUL; 128 addr = reinterpret_cast<volatile char*>(syscall); 129 *addr = '\0'; 130 for (;;) 131 _exit(1); 132 } 133 134 // TODO(jln): refactor the reporting functions. 135 136 intptr_t SIGSYSCloneFailure(const struct arch_seccomp_data& args, void* aux) { 137 static const char kSeccompCloneError[] = 138 __FILE__":**CRASHING**:" SECCOMP_MESSAGE_CLONE_CONTENT "\n"; 139 WriteToStdErr(kSeccompCloneError, sizeof(kSeccompCloneError) - 1); 140 // "flags" is the first argument in the kernel's clone(). 141 // Mark as volatile to be able to find the value on the stack in a minidump. 142 volatile uint64_t clone_flags = args.args[0]; 143 volatile char* addr; 144 if (IsArchitectureX86_64()) { 145 addr = reinterpret_cast<volatile char*>(clone_flags & 0xFFFFFF); 146 *addr = '\0'; 147 } 148 // Hit the NULL page if this fails to fault. 149 addr = reinterpret_cast<volatile char*>(clone_flags & 0xFFF); 150 *addr = '\0'; 151 for (;;) 152 _exit(1); 153 } 154 155 intptr_t SIGSYSPrctlFailure(const struct arch_seccomp_data& args, 156 void* /* aux */) { 157 static const char kSeccompPrctlError[] = 158 __FILE__":**CRASHING**:" SECCOMP_MESSAGE_PRCTL_CONTENT "\n"; 159 WriteToStdErr(kSeccompPrctlError, sizeof(kSeccompPrctlError) - 1); 160 // Mark as volatile to be able to find the value on the stack in a minidump. 161 volatile uint64_t option = args.args[0]; 162 volatile char* addr = 163 reinterpret_cast<volatile char*>(option & 0xFFF); 164 *addr = '\0'; 165 for (;;) 166 _exit(1); 167 } 168 169 intptr_t SIGSYSIoctlFailure(const struct arch_seccomp_data& args, 170 void* /* aux */) { 171 static const char kSeccompIoctlError[] = 172 __FILE__":**CRASHING**:" SECCOMP_MESSAGE_IOCTL_CONTENT "\n"; 173 WriteToStdErr(kSeccompIoctlError, sizeof(kSeccompIoctlError) - 1); 174 // Make "request" volatile so that we can see it on the stack in a minidump. 175 volatile uint64_t request = args.args[1]; 176 volatile char* addr = reinterpret_cast<volatile char*>(request & 0xFFFF); 177 *addr = '\0'; 178 // Hit the NULL page if this fails. 179 addr = reinterpret_cast<volatile char*>(request & 0xFFF); 180 *addr = '\0'; 181 for (;;) 182 _exit(1); 183 } 184 185 intptr_t SIGSYSKillFailure(const struct arch_seccomp_data& args, 186 void* /* aux */) { 187 static const char kSeccompKillError[] = 188 __FILE__":**CRASHING**:" SECCOMP_MESSAGE_KILL_CONTENT "\n"; 189 WriteToStdErr(kSeccompKillError, sizeof(kSeccompKillError) - 1); 190 // Make "request" volatile so that we can see it on the stack in a minidump. 191 volatile uint64_t pid = args.args[0]; 192 volatile char* addr = reinterpret_cast<volatile char*>(pid & 0xFFF); 193 *addr = '\0'; 194 // Hit the NULL page if this fails. 195 addr = reinterpret_cast<volatile char*>(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 = syscall(__NR_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