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.
5 // Note: any code in this file MUST be async-signal safe.
7 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
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"
19 inline bool IsArchitectureX86_64() {
20 #if defined(__x86_64__)
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
) {
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;
42 // Print a seccomp-bpf failure to handle |sysno| to stderr in an
43 // async-signal safe way.
44 void PrintSyscallError(uint32_t sysno
) {
47 // TODO(markus): replace with async-signal safe snprintf when available.
48 const size_t kNumDigits
= 4;
49 char sysno_base10
[kNumDigits
];
52 for (int i
= kNumDigits
- 1; i
>= 0; i
--) {
55 sysno_base10
[i
] = '0' + mod
;
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);
69 intptr_t CrashSIGSYS_Handler(const struct arch_seccomp_data
& args
, void* aux
) {
70 uint32_t syscall
= args
.nr
;
73 PrintSyscallError(syscall
);
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
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
);
86 // In case we hit a mapped address, hit the null page with just the syscall,
89 addr
= reinterpret_cast<volatile char*>(syscall
);
95 // TODO(jln): refactor the reporting functions.
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.
101 RAW_LOG(ERROR
, __FILE__
":**CRASHING**:clone() failure\n");
103 volatile uint64_t clone_flags
= args
.args
[0];
105 if (IsArchitectureX86_64()) {
106 addr
= reinterpret_cast<volatile char*>(clone_flags
& 0xFFFFFF);
109 // Hit the NULL page if this fails to fault.
110 addr
= reinterpret_cast<volatile char*>(clone_flags
& 0xFFF);
116 intptr_t SIGSYSPrctlFailure(const struct arch_seccomp_data
& args
,
118 // Mark as volatile to be able to find the value on the stack in a minidump.
120 RAW_LOG(ERROR
, __FILE__
":**CRASHING**:prctl() failure\n");
122 volatile uint64_t option
= args
.args
[0];
123 volatile char* addr
=
124 reinterpret_cast<volatile char*>(option
& 0xFFF);
130 intptr_t SIGSYSIoctlFailure(const struct arch_seccomp_data
& args
,
132 // Make "request" volatile so that we can see it on the stack in a minidump.
134 RAW_LOG(ERROR
, __FILE__
":**CRASHING**:ioctl() failure\n");
136 volatile uint64_t request
= args
.args
[1];
137 volatile char* addr
= reinterpret_cast<volatile char*>(request
& 0xFFFF);
139 // Hit the NULL page if this fails.
140 addr
= reinterpret_cast<volatile char*>(request
& 0xFFF);
146 } // namespace sandbox.