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