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 <unistd.h> 10 11 #include "base/basictypes.h" 12 #include "base/logging.h" 13 #include "base/posix/eintr_wrapper.h" 14 #include "build/build_config.h" 15 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 16 17 namespace { 18 19 inline bool IsArchitectureX86_64() { 20 #if defined(__x86_64__) 21 return true; 22 #else 23 return false; 24 #endif 25 } 26 27 // Write |error_message| to stderr. Similar to RawLog(), but a bit more careful 28 // about async-signal safety. |size| is the size to write and should typically 29 // not include a terminating \0. 30 void WriteToStdErr(const char* error_message, size_t size) { 31 while (size > 0) { 32 // TODO(jln): query the current policy to check if send() is available and 33 // use it to perform a non-blocking write. 34 const int ret = HANDLE_EINTR(write(STDERR_FILENO, error_message, size)); 35 // We can't handle any type of error here. 36 if (ret <= 0 || static_cast<size_t>(ret) > size) break; 37 size -= ret; 38 error_message += ret; 39 } 40 } 41 42 // Print a seccomp-bpf failure to handle |sysno| to stderr in an 43 // async-signal safe way. 44 void PrintSyscallError(uint32_t sysno) { 45 if (sysno >= 1024) 46 sysno = 0; 47 // TODO(markus): replace with async-signal safe snprintf when available. 48 const size_t kNumDigits = 4; 49 char sysno_base10[kNumDigits]; 50 uint32_t rem = sysno; 51 uint32_t mod = 0; 52 for (int i = kNumDigits - 1; i >= 0; i--) { 53 mod = rem % 10; 54 rem /= 10; 55 sysno_base10[i] = '0' + mod; 56 } 57 static const char kSeccompErrorPrefix[] = 58 __FILE__":**CRASHING**:seccomp-bpf failure in syscall "; 59 static const char kSeccompErrorPostfix[] = "\n"; 60 WriteToStdErr(kSeccompErrorPrefix, sizeof(kSeccompErrorPrefix) - 1); 61 WriteToStdErr(sysno_base10, sizeof(sysno_base10)); 62 WriteToStdErr(kSeccompErrorPostfix, sizeof(kSeccompErrorPostfix) - 1); 63 } 64 65 } // namespace. 66 67 namespace sandbox { 68 69 intptr_t CrashSIGSYS_Handler(const struct arch_seccomp_data& args, void* aux) { 70 uint32_t syscall = args.nr; 71 if (syscall >= 1024) 72 syscall = 0; 73 PrintSyscallError(syscall); 74 75 // Encode 8-bits of the 1st two arguments too, so we can discern which socket 76 // type, which fcntl, ... etc., without being likely to hit a mapped 77 // address. 78 // Do not encode more bits here without thinking about increasing the 79 // likelihood of collision with mapped pages. 80 syscall |= ((args.args[0] & 0xffUL) << 12); 81 syscall |= ((args.args[1] & 0xffUL) << 20); 82 // Purposefully dereference the syscall as an address so it'll show up very 83 // clearly and easily in crash dumps. 84 volatile char* addr = reinterpret_cast<volatile char*>(syscall); 85 *addr = '\0'; 86 // In case we hit a mapped address, hit the null page with just the syscall, 87 // for paranoia. 88 syscall &= 0xfffUL; 89 addr = reinterpret_cast<volatile char*>(syscall); 90 *addr = '\0'; 91 for (;;) 92 _exit(1); 93 } 94 95 // TODO(jln): refactor the reporting functions. 96 97 intptr_t SIGSYSCloneFailure(const struct arch_seccomp_data& args, void* aux) { 98 // "flags" is the first argument in the kernel's clone(). 99 // Mark as volatile to be able to find the value on the stack in a minidump. 100 #if !defined(NDEBUG) 101 RAW_LOG(ERROR, __FILE__":**CRASHING**:clone() failure\n"); 102 #endif 103 volatile uint64_t clone_flags = args.args[0]; 104 volatile char* addr; 105 if (IsArchitectureX86_64()) { 106 addr = reinterpret_cast<volatile char*>(clone_flags & 0xFFFFFF); 107 *addr = '\0'; 108 } 109 // Hit the NULL page if this fails to fault. 110 addr = reinterpret_cast<volatile char*>(clone_flags & 0xFFF); 111 *addr = '\0'; 112 for (;;) 113 _exit(1); 114 } 115 116 intptr_t SIGSYSPrctlFailure(const struct arch_seccomp_data& args, 117 void* /* aux */) { 118 // Mark as volatile to be able to find the value on the stack in a minidump. 119 #if !defined(NDEBUG) 120 RAW_LOG(ERROR, __FILE__":**CRASHING**:prctl() failure\n"); 121 #endif 122 volatile uint64_t option = args.args[0]; 123 volatile char* addr = 124 reinterpret_cast<volatile char*>(option & 0xFFF); 125 *addr = '\0'; 126 for (;;) 127 _exit(1); 128 } 129 130 intptr_t SIGSYSIoctlFailure(const struct arch_seccomp_data& args, 131 void* /* aux */) { 132 // Make "request" volatile so that we can see it on the stack in a minidump. 133 #if !defined(NDEBUG) 134 RAW_LOG(ERROR, __FILE__":**CRASHING**:ioctl() failure\n"); 135 #endif 136 volatile uint64_t request = args.args[1]; 137 volatile char* addr = reinterpret_cast<volatile char*>(request & 0xFFFF); 138 *addr = '\0'; 139 // Hit the NULL page if this fails. 140 addr = reinterpret_cast<volatile char*>(request & 0xFFF); 141 *addr = '\0'; 142 for (;;) 143 _exit(1); 144 } 145 146 } // namespace sandbox. 147