OLD | NEW |
(Empty) | |
| 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. |
OLD | NEW |