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. | |
Jorge Lucangeli Obes
2013/12/05 16:46:30
nit: non-blocking.
jln (very slow on Chromium)
2013/12/05 18:02:46
Done.
| |
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" in the first argument in the kernel's clone(). | |
Jorge Lucangeli Obes
2013/12/05 16:46:30
"is" the first argument...
jln (very slow on Chromium)
2013/12/05 18:02:46
Done.
| |
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 |