1 // Copyright (c) 2012 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 #include "sandbox/linux/seccomp-bpf/trap.h"
10 #include <sys/syscall.h>
15 #include "base/compiler_specific.h"
16 #include "base/logging.h"
17 #include "build/build_config.h"
18 #include "sandbox/linux/bpf_dsl/seccomp_macros.h"
19 #include "sandbox/linux/seccomp-bpf/die.h"
20 #include "sandbox/linux/seccomp-bpf/syscall.h"
21 #include "sandbox/linux/services/syscall_wrappers.h"
22 #include "sandbox/linux/system_headers/linux_seccomp.h"
23 #include "sandbox/linux/system_headers/linux_signal.h"
33 const int kCapacityIncrement
= 20;
35 // Unsafe traps can only be turned on, if the user explicitly allowed them
36 // by setting the CHROME_SANDBOX_DEBUGGING environment variable.
37 const char kSandboxDebuggingEnv
[] = "CHROME_SANDBOX_DEBUGGING";
39 // We need to tell whether we are performing a "normal" callback, or
40 // whether we were called recursively from within a UnsafeTrap() callback.
41 // This is a little tricky to do, because we need to somehow get access to
42 // per-thread data from within a signal context. Normal TLS storage is not
43 // safely accessible at this time. We could roll our own, but that involves
44 // a lot of complexity. Instead, we co-opt one bit in the signal mask.
45 // If BUS is blocked, we assume that we have been called recursively.
46 // There is a possibility for collision with other code that needs to do
47 // this, but in practice the risks are low.
48 // If SIGBUS turns out to be a problem, we could instead co-opt one of the
49 // realtime signals. There are plenty of them. Unfortunately, there is no
50 // way to mark a signal as allocated. So, the potential for collision is
51 // possibly even worse.
52 bool GetIsInSigHandler(const ucontext_t
* ctx
) {
53 // Note: on Android, sigismember does not take a pointer to const.
54 return sigismember(const_cast<sigset_t
*>(&ctx
->uc_sigmask
), LINUX_SIGBUS
);
57 void SetIsInSigHandler() {
59 if (sigemptyset(&mask
) || sigaddset(&mask
, LINUX_SIGBUS
) ||
60 sandbox::sys_sigprocmask(LINUX_SIG_BLOCK
, &mask
, NULL
)) {
61 SANDBOX_DIE("Failed to block SIGBUS");
65 bool IsDefaultSignalAction(const struct sigaction
& sa
) {
66 if (sa
.sa_flags
& SA_SIGINFO
|| sa
.sa_handler
!= SIG_DFL
) {
79 trap_array_capacity_(0),
80 has_unsafe_traps_(false) {
81 // Set new SIGSYS handler
82 struct sigaction sa
= {};
83 // In some toolchain, sa_sigaction is not declared in struct sigaction.
84 // So, here cast the pointer to the sa_handler's type. This works because
85 // |sa_handler| and |sa_sigaction| shares the same memory.
86 sa
.sa_handler
= reinterpret_cast<void (*)(int)>(SigSysAction
);
87 sa
.sa_flags
= LINUX_SA_SIGINFO
| LINUX_SA_NODEFER
;
88 struct sigaction old_sa
= {};
89 if (sys_sigaction(LINUX_SIGSYS
, &sa
, &old_sa
) < 0) {
90 SANDBOX_DIE("Failed to configure SIGSYS handler");
93 if (!IsDefaultSignalAction(old_sa
)) {
94 static const char kExistingSIGSYSMsg
[] =
95 "Existing signal handler when trying to install SIGSYS. SIGSYS needs "
96 "to be reserved for seccomp-bpf.";
97 DLOG(FATAL
) << kExistingSIGSYSMsg
;
98 LOG(ERROR
) << kExistingSIGSYSMsg
;
103 if (sigemptyset(&mask
) || sigaddset(&mask
, LINUX_SIGSYS
) ||
104 sys_sigprocmask(LINUX_SIG_UNBLOCK
, &mask
, NULL
)) {
105 SANDBOX_DIE("Failed to configure SIGSYS handler");
109 bpf_dsl::TrapRegistry
* Trap::Registry() {
110 // Note: This class is not thread safe. It is the caller's responsibility
111 // to avoid race conditions. Normally, this is a non-issue as the sandbox
112 // can only be initialized if there are no other threads present.
113 // Also, this is not a normal singleton. Once created, the global trap
114 // object must never be destroyed again.
116 global_trap_
= new Trap();
118 SANDBOX_DIE("Failed to allocate global trap handler");
124 void Trap::SigSysAction(int nr
, LinuxSigInfo
* info
, void* void_context
) {
126 MSAN_UNPOISON(info
, sizeof(*info
));
129 // Obtain the signal context. This, most notably, gives us access to
130 // all CPU registers at the time of the signal.
131 ucontext_t
* ctx
= reinterpret_cast<ucontext_t
*>(void_context
);
133 MSAN_UNPOISON(ctx
, sizeof(*ctx
));
138 "This can't happen. Found no global singleton instance "
139 "for Trap() handling.");
141 global_trap_
->SigSys(nr
, info
, ctx
);
144 void Trap::SigSys(int nr
, LinuxSigInfo
* info
, ucontext_t
* ctx
) {
145 // Signal handlers should always preserve "errno". Otherwise, we could
146 // trigger really subtle bugs.
147 const int old_errno
= errno
;
149 // Various sanity checks to make sure we actually received a signal
150 // triggered by a BPF filter. If something else triggered SIGSYS
151 // (e.g. kill()), there is really nothing we can do with this signal.
152 if (nr
!= LINUX_SIGSYS
|| info
->si_code
!= SYS_SECCOMP
|| !ctx
||
153 info
->si_errno
<= 0 ||
154 static_cast<size_t>(info
->si_errno
) > trap_array_size_
) {
155 // ATI drivers seem to send SIGSYS, so this cannot be FATAL.
156 // See crbug.com/178166.
157 // TODO(jln): add a DCHECK or move back to FATAL.
158 RAW_LOG(ERROR
, "Unexpected SIGSYS received.");
164 // Obtain the siginfo information that is specific to SIGSYS. Unfortunately,
165 // most versions of glibc don't include this information in siginfo_t. So,
166 // we need to explicitly copy it into a arch_sigsys structure.
167 struct arch_sigsys sigsys
;
168 memcpy(&sigsys
, &info
->_sifields
, sizeof(sigsys
));
170 #if defined(__mips__)
171 // When indirect syscall (syscall(__NR_foo, ...)) is made on Mips, the
172 // number in register SECCOMP_SYSCALL(ctx) is always __NR_syscall and the
173 // real number of a syscall (__NR_foo) is in SECCOMP_PARM1(ctx)
174 bool sigsys_nr_is_bad
= sigsys
.nr
!= static_cast<int>(SECCOMP_SYSCALL(ctx
)) &&
175 sigsys
.nr
!= static_cast<int>(SECCOMP_PARM1(ctx
));
177 bool sigsys_nr_is_bad
= sigsys
.nr
!= static_cast<int>(SECCOMP_SYSCALL(ctx
));
180 // Some more sanity checks.
181 if (sigsys
.ip
!= reinterpret_cast<void*>(SECCOMP_IP(ctx
)) ||
182 sigsys_nr_is_bad
|| sigsys
.arch
!= SECCOMP_ARCH
) {
184 // SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal
185 // safe and can lead to bugs. We should eventually implement a different
186 // logging and reporting mechanism that is safe to be called from
187 // the sigSys() handler.
188 RAW_SANDBOX_DIE("Sanity checks are failing after receiving SIGSYS.");
192 if (has_unsafe_traps_
&& GetIsInSigHandler(ctx
)) {
194 if (sigsys
.nr
== __NR_clone
) {
195 RAW_SANDBOX_DIE("Cannot call clone() from an UnsafeTrap() handler.");
197 #if defined(__mips__)
198 // Mips supports up to eight arguments for syscall.
199 // However, seccomp bpf can filter only up to six arguments, so using eight
200 // arguments has sense only when using UnsafeTrap() handler.
201 rc
= Syscall::Call(SECCOMP_SYSCALL(ctx
),
211 rc
= Syscall::Call(SECCOMP_SYSCALL(ctx
),
218 #endif // defined(__mips__)
220 const TrapKey
& trap
= trap_array_
[info
->si_errno
- 1];
225 // Copy the seccomp-specific data into a arch_seccomp_data structure. This
226 // is what we are showing to TrapFnc callbacks that the system call
227 // evaluator registered with the sandbox.
228 struct arch_seccomp_data data
= {
229 static_cast<int>(SECCOMP_SYSCALL(ctx
)),
231 reinterpret_cast<uint64_t>(sigsys
.ip
),
232 {static_cast<uint64_t>(SECCOMP_PARM1(ctx
)),
233 static_cast<uint64_t>(SECCOMP_PARM2(ctx
)),
234 static_cast<uint64_t>(SECCOMP_PARM3(ctx
)),
235 static_cast<uint64_t>(SECCOMP_PARM4(ctx
)),
236 static_cast<uint64_t>(SECCOMP_PARM5(ctx
)),
237 static_cast<uint64_t>(SECCOMP_PARM6(ctx
))}};
239 // Now call the TrapFnc callback associated with this particular instance
240 // of SECCOMP_RET_TRAP.
241 rc
= trap
.fnc(data
, const_cast<void*>(trap
.aux
));
244 // Update the CPU register that stores the return code of the system call
245 // that we just handled, and restore "errno" to the value that it had
246 // before entering the signal handler.
247 Syscall::PutValueInUcontext(rc
, ctx
);
253 bool Trap::TrapKey::operator<(const TrapKey
& o
) const {
256 } else if (aux
!= o
.aux
) {
259 return safe
< o
.safe
;
263 uint16_t Trap::Add(TrapFnc fnc
, const void* aux
, bool safe
) {
264 if (!safe
&& !SandboxDebuggingAllowedByUser()) {
265 // Unless the user set the CHROME_SANDBOX_DEBUGGING environment variable,
266 // we never return an ErrorCode that is marked as "unsafe". This also
267 // means, the BPF compiler will never emit code that allow unsafe system
268 // calls to by-pass the filter (because they use the magic return address
269 // from Syscall::Call(-1)).
271 // This SANDBOX_DIE() can optionally be removed. It won't break security,
272 // but it might make error messages from the BPF compiler a little harder
273 // to understand. Removing the SANDBOX_DIE() allows callers to easily check
274 // whether unsafe traps are supported (by checking whether the returned
275 // ErrorCode is ET_INVALID).
277 "Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING "
283 // Each unique pair of TrapFnc and auxiliary data make up a distinct instance
284 // of a SECCOMP_RET_TRAP.
285 TrapKey
key(fnc
, aux
, safe
);
287 // We return unique identifiers together with SECCOMP_RET_TRAP. This allows
288 // us to associate trap with the appropriate handler. The kernel allows us
289 // identifiers in the range from 0 to SECCOMP_RET_DATA (0xFFFF). We want to
290 // avoid 0, as it could be confused for a trap without any specific id.
291 // The nice thing about sequentially numbered identifiers is that we can also
292 // trivially look them up from our signal handler without making any system
293 // calls that might be async-signal-unsafe.
294 // In order to do so, we store all of our traps in a C-style trap_array_.
296 TrapIds::const_iterator iter
= trap_ids_
.find(key
);
297 if (iter
!= trap_ids_
.end()) {
298 // We have seen this pair before. Return the same id that we assigned
303 // This is a new pair. Remember it and assign a new id.
304 if (trap_array_size_
>= SECCOMP_RET_DATA
/* 0xFFFF */ ||
305 trap_array_size_
>= std::numeric_limits
<uint16_t>::max()) {
306 // In practice, this is pretty much impossible to trigger, as there
307 // are other kernel limitations that restrict overall BPF program sizes.
308 SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances");
311 // Our callers ensure that there are no other threads accessing trap_array_
312 // concurrently (typically this is done by ensuring that we are single-
313 // threaded while the sandbox is being set up). But we nonetheless are
314 // modifying a live data structure that could be accessed any time a
315 // system call is made; as system calls could be triggering SIGSYS.
316 // So, we have to be extra careful that we update trap_array_ atomically.
317 // In particular, this means we shouldn't be using realloc() to resize it.
318 // Instead, we allocate a new array, copy the values, and then switch the
319 // pointer. We only really care about the pointer being updated atomically
320 // and the data that is pointed to being valid, as these are the only
321 // values accessed from the signal handler. It is OK if trap_array_size_
322 // is inconsistent with the pointer, as it is monotonously increasing.
323 // Also, we only care about compiler barriers, as the signal handler is
324 // triggered synchronously from a system call. We don't have to protect
325 // against issues with the memory model or with completely asynchronous
327 if (trap_array_size_
>= trap_array_capacity_
) {
328 trap_array_capacity_
+= kCapacityIncrement
;
329 TrapKey
* old_trap_array
= trap_array_
;
330 TrapKey
* new_trap_array
= new TrapKey
[trap_array_capacity_
];
331 std::copy_n(old_trap_array
, trap_array_size_
, new_trap_array
);
333 // Language specs are unclear on whether the compiler is allowed to move
334 // the "delete[]" above our preceding assignments and/or memory moves,
335 // iff the compiler believes that "delete[]" doesn't have any other
336 // global side-effects.
337 // We insert optimization barriers to prevent this from happening.
338 // The first barrier is probably not needed, but better be explicit in
339 // what we want to tell the compiler.
340 // The clang developer mailing list couldn't answer whether this is a
341 // legitimate worry; but they at least thought that the barrier is
342 // sufficient to prevent the (so far hypothetical) problem of re-ordering
343 // of instructions by the compiler.
345 // TODO(mdempsky): Try to clean this up using base/atomicops or C++11
346 // atomics; see crbug.com/414363.
347 asm volatile("" : "=r"(new_trap_array
) : "0"(new_trap_array
) : "memory");
348 trap_array_
= new_trap_array
;
349 asm volatile("" : "=r"(trap_array_
) : "0"(trap_array_
) : "memory");
351 delete[] old_trap_array
;
354 uint16_t id
= trap_array_size_
+ 1;
356 trap_array_
[trap_array_size_
] = key
;
361 bool Trap::SandboxDebuggingAllowedByUser() {
362 const char* debug_flag
= getenv(kSandboxDebuggingEnv
);
363 return debug_flag
&& *debug_flag
;
366 bool Trap::EnableUnsafeTraps() {
367 if (!has_unsafe_traps_
) {
368 // Unsafe traps are a one-way fuse. Once enabled, they can never be turned
370 // We only allow enabling unsafe traps, if the user explicitly set an
371 // appropriate environment variable. This prevents bugs that accidentally
372 // disable all sandboxing for all users.
373 if (SandboxDebuggingAllowedByUser()) {
374 // We only ever print this message once, when we enable unsafe traps the
376 SANDBOX_INFO("WARNING! Disabling sandbox for debugging purposes");
377 has_unsafe_traps_
= true;
380 "Cannot disable sandbox and use unsafe traps unless "
381 "CHROME_SANDBOX_DEBUGGING is turned on first");
384 // Returns the, possibly updated, value of has_unsafe_traps_.
385 return has_unsafe_traps_
;
388 Trap
* Trap::global_trap_
;
390 } // namespace sandbox