• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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