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
IsArchitectureX86_64()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.
WriteToStdErr(const char * error_message,size_t size)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.
PrintSyscallError(uint32_t sysno)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
CrashSIGSYS_Handler(const struct arch_seccomp_data & args,void * aux)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
SIGSYSCloneFailure(const struct arch_seccomp_data & args,void * aux)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
SIGSYSPrctlFailure(const struct arch_seccomp_data & args,void *)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
SIGSYSIoctlFailure(const struct arch_seccomp_data & args,void *)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
SIGSYSKillFailure(const struct arch_seccomp_data & args,void *)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
SIGSYSFutexFailure(const struct arch_seccomp_data & args,void *)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
GetErrorMessageContentForTests()180 const char* GetErrorMessageContentForTests() {
181 return SECCOMP_MESSAGE_COMMON_CONTENT;
182 }
183
GetCloneErrorMessageContentForTests()184 const char* GetCloneErrorMessageContentForTests() {
185 return SECCOMP_MESSAGE_CLONE_CONTENT;
186 }
187
GetPrctlErrorMessageContentForTests()188 const char* GetPrctlErrorMessageContentForTests() {
189 return SECCOMP_MESSAGE_PRCTL_CONTENT;
190 }
191
GetIoctlErrorMessageContentForTests()192 const char* GetIoctlErrorMessageContentForTests() {
193 return SECCOMP_MESSAGE_IOCTL_CONTENT;
194 }
195
GetKillErrorMessageContentForTests()196 const char* GetKillErrorMessageContentForTests() {
197 return SECCOMP_MESSAGE_KILL_CONTENT;
198 }
199
GetFutexErrorMessageContentForTests()200 const char* GetFutexErrorMessageContentForTests() {
201 return SECCOMP_MESSAGE_FUTEX_CONTENT;
202 }
203
204 } // namespace sandbox.
205