| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "sandbox/linux/seccomp-bpf/die.h" | 
 |  | 
 | #include <errno.h> | 
 | #include <signal.h> | 
 | #include <stdio.h> | 
 | #include <sys/prctl.h> | 
 | #include <sys/syscall.h> | 
 | #include <unistd.h> | 
 |  | 
 | #include <string> | 
 |  | 
 | #include "base/logging.h" | 
 | #include "base/posix/eintr_wrapper.h" | 
 | #include "sandbox/linux/seccomp-bpf/syscall.h" | 
 | #include "sandbox/linux/services/syscall_wrappers.h" | 
 | #include "sandbox/linux/system_headers/linux_signal.h" | 
 |  | 
 | namespace sandbox { | 
 |  | 
 | void Die::ExitGroup() { | 
 |   // exit_group() should exit our program. After all, it is defined as a | 
 |   // function that doesn't return. But things can theoretically go wrong. | 
 |   // Especially, since we are dealing with system call filters. Continuing | 
 |   // execution would be very bad in most cases where ExitGroup() gets called. | 
 |   // So, we'll try a few other strategies too. | 
 |   Syscall::Call(__NR_exit_group, 1); | 
 |  | 
 |   // We have no idea what our run-time environment looks like. So, signal | 
 |   // handlers might or might not do the right thing. Try to reset settings | 
 |   // to a defined state; but we have not way to verify whether we actually | 
 |   // succeeded in doing so. Nonetheless, triggering a fatal signal could help | 
 |   // us terminate. | 
 |   struct sigaction sa = {}; | 
 |   sa.sa_handler = LINUX_SIG_DFL; | 
 |   sa.sa_flags = LINUX_SA_RESTART; | 
 |   sys_sigaction(LINUX_SIGSEGV, &sa, nullptr); | 
 |   Syscall::Call(__NR_prctl, PR_SET_DUMPABLE, (void*)0, (void*)0, (void*)0); | 
 |   if (*(volatile char*)0) { | 
 |   } | 
 |  | 
 |   // If there is no way for us to ask for the program to exit, the next | 
 |   // best thing we can do is to loop indefinitely. Maybe, somebody will notice | 
 |   // and file a bug... | 
 |   // We in fact retry the system call inside of our loop so that it will | 
 |   // stand out when somebody tries to diagnose the problem by using "strace". | 
 |   for (;;) { | 
 |     Syscall::Call(__NR_exit_group, 1); | 
 |   } | 
 | } | 
 |  | 
 | void Die::SandboxDie(const char* msg, const char* file, int line) { | 
 |   if (simple_exit_) { | 
 |     LogToStderr(msg, file, line); | 
 |   } else { | 
 |     logging::LogMessage(file, line, logging::LOG_FATAL).stream() << msg; | 
 |   } | 
 |   ExitGroup(); | 
 | } | 
 |  | 
 | void Die::RawSandboxDie(const char* msg) { | 
 |   if (!msg) | 
 |     msg = ""; | 
 |   RAW_LOG(FATAL, msg); | 
 |   ExitGroup(); | 
 | } | 
 |  | 
 | void Die::SandboxInfo(const char* msg, const char* file, int line) { | 
 |   if (!suppress_info_) { | 
 |     logging::LogMessage(file, line, logging::LOG_INFO).stream() << msg; | 
 |   } | 
 | } | 
 |  | 
 | void Die::LogToStderr(const char* msg, const char* file, int line) { | 
 |   if (msg) { | 
 |     char buf[40]; | 
 |     snprintf(buf, sizeof(buf), "%d", line); | 
 |     std::string s = std::string(file) + ":" + buf + ":" + msg + "\n"; | 
 |  | 
 |     // No need to loop. Short write()s are unlikely and if they happen we | 
 |     // probably prefer them over a loop that blocks. | 
 |     ignore_result( | 
 |         HANDLE_EINTR(Syscall::Call(__NR_write, 2, s.c_str(), s.length()))); | 
 |   } | 
 | } | 
 |  | 
 | bool Die::simple_exit_ = false; | 
 | bool Die::suppress_info_ = false; | 
 |  | 
 | }  // namespace sandbox |