system/core
Revisão | 1fcd51255a8eb1bf2e114ab9fcda73ecc0ac05b4 (tree) |
---|---|
Hora | 2019-05-31 04:08:42 |
Autor | Tom Cherry <tomcherry@goog...> |
Commiter | Keun young Park |
init: dump stack when aborting
Dump init stacks when aborting either due to LOG(FATAL) or in
userdebug/eng builds due to signals, including signals from
sanitizers.
Doesn't work for static first stage init yet, b/133450393 tracks
that.
Also, ensure that LOG(FATAL) in child processes calls abort() in all
stages of init, not just 2nd stage init.
Bug: 131747478
Test: abort init in various ways and see stacks
Test: hang or crash in backtrace handler and see child reboot
Change-Id: Ib53b5d3e7e814244203f875de016ada9900dfce8
Merged-In: Ib53b5d3e7e814244203f875de016ada9900dfce8
(cherry picked from commit 59656fb37769b3c0de927c20f8e9f5855a0f7ac3)
@@ -68,6 +68,7 @@ cc_defaults { | ||
68 | 68 | "libpropertyinfoparser", |
69 | 69 | ], |
70 | 70 | shared_libs: [ |
71 | + "libbacktrace", | |
71 | 72 | "libbase", |
72 | 73 | "libbinder", |
73 | 74 | "libbootloader_message", |
@@ -105,6 +105,10 @@ LOCAL_STATIC_LIBRARIES := \ | ||
105 | 105 | libcap \ |
106 | 106 | libgsi \ |
107 | 107 | libcom.android.sysprop.apex \ |
108 | + liblzma \ | |
109 | + libdexfile_support \ | |
110 | + libunwindstack \ | |
111 | + libbacktrace \ | |
108 | 112 | |
109 | 113 | LOCAL_SANITIZE := signed-integer-overflow |
110 | 114 | # First stage init is weird: it may start without stdout/stderr, and no /proc. |
@@ -33,7 +33,6 @@ | ||
33 | 33 | #include <android-base/chrono_utils.h> |
34 | 34 | #include <android-base/file.h> |
35 | 35 | #include <android-base/logging.h> |
36 | -#include <cutils/android_reboot.h> | |
37 | 36 | #include <private/android_filesystem_config.h> |
38 | 37 | |
39 | 38 | #include "debug_ramdisk.h" |
@@ -168,13 +167,10 @@ int FirstStageMain(int argc, char** argv) { | ||
168 | 167 | "mode=0755,uid=0,gid=0")); |
169 | 168 | #undef CHECKCALL |
170 | 169 | |
170 | + SetStdioToDevNull(argv); | |
171 | 171 | // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually |
172 | 172 | // talk to the outside world... |
173 | - // We need to set up stdin/stdout/stderr for child processes forked from first | |
174 | - // stage init as part of the mount process. This closes /dev/console if the | |
175 | - // kernel had previously opened it. | |
176 | - auto reboot_bootloader = [](const char*) { RebootSystem(ANDROID_RB_RESTART2, "bootloader"); }; | |
177 | - InitKernelLogging(argv, reboot_bootloader); | |
173 | + InitKernelLogging(argv); | |
178 | 174 | |
179 | 175 | if (!errors.empty()) { |
180 | 176 | for (const auto& [error_string, error_errno] : errors) { |
@@ -44,6 +44,11 @@ extern uint32_t (*property_set)(const std::string& name, const std::string& valu | ||
44 | 44 | uint32_t HandlePropertySet(const std::string& name, const std::string& value, |
45 | 45 | const std::string& source_context, const ucred& cr, std::string* error); |
46 | 46 | |
47 | +// reboot_utils.h | |
48 | +inline void __attribute__((noreturn)) InitFatalReboot() { | |
49 | + abort(); | |
50 | +} | |
51 | + | |
47 | 52 | // selinux.h |
48 | 53 | int SelinuxGetVendorAndroidVersion(); |
49 | 54 | void SelabelInitialize(); |
@@ -38,7 +38,6 @@ | ||
38 | 38 | #include <android-base/properties.h> |
39 | 39 | #include <android-base/stringprintf.h> |
40 | 40 | #include <android-base/strings.h> |
41 | -#include <cutils/android_reboot.h> | |
42 | 41 | #include <fs_avb/fs_avb.h> |
43 | 42 | #include <fs_mgr_vendor_overlay.h> |
44 | 43 | #include <keyutils.h> |
@@ -601,17 +600,6 @@ void HandleKeychord(const std::vector<int>& keycodes) { | ||
601 | 600 | } |
602 | 601 | } |
603 | 602 | |
604 | -static void InitAborter(const char* abort_message) { | |
605 | - // When init forks, it continues to use this aborter for LOG(FATAL), but we want children to | |
606 | - // simply abort instead of trying to reboot the system. | |
607 | - if (getpid() != 1) { | |
608 | - android::base::DefaultAborter(abort_message); | |
609 | - return; | |
610 | - } | |
611 | - | |
612 | - RebootSystem(ANDROID_RB_RESTART2, "bootloader"); | |
613 | -} | |
614 | - | |
615 | 603 | static void GlobalSeccomp() { |
616 | 604 | import_kernel_cmdline(false, [](const std::string& key, const std::string& value, |
617 | 605 | bool in_qemu) { |
@@ -632,8 +620,8 @@ int SecondStageMain(int argc, char** argv) { | ||
632 | 620 | InstallRebootSignalHandlers(); |
633 | 621 | } |
634 | 622 | |
635 | - // We need to set up stdin/stdout/stderr again now that we're running in init's context. | |
636 | - InitKernelLogging(argv, InitAborter); | |
623 | + SetStdioToDevNull(argv); | |
624 | + InitKernelLogging(argv); | |
637 | 625 | LOG(INFO) << "init second stage started!"; |
638 | 626 | |
639 | 627 | // Set init and its forked children's oom_adj. |
@@ -19,8 +19,13 @@ | ||
19 | 19 | #include <sys/syscall.h> |
20 | 20 | #include <unistd.h> |
21 | 21 | |
22 | -#include <android-base/logging.h> | |
23 | -#include <cutils/android_reboot.h> | |
22 | +#include <string> | |
23 | + | |
24 | +#include "android-base/file.h" | |
25 | +#include "android-base/logging.h" | |
26 | +#include "android-base/strings.h" | |
27 | +#include "backtrace/Backtrace.h" | |
28 | +#include "cutils/android_reboot.h" | |
24 | 29 | |
25 | 30 | #include "capabilities.h" |
26 | 31 |
@@ -75,6 +80,32 @@ void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& | ||
75 | 80 | abort(); |
76 | 81 | } |
77 | 82 | |
83 | +void __attribute__((noreturn)) InitFatalReboot() { | |
84 | + auto pid = fork(); | |
85 | + | |
86 | + if (pid == -1) { | |
87 | + // Couldn't fork, don't even try to backtrace, just reboot. | |
88 | + RebootSystem(ANDROID_RB_RESTART2, "bootloader"); | |
89 | + } else if (pid == 0) { | |
90 | + // Fork a child for safety, since we always want to shut down if something goes wrong, but | |
91 | + // its worth trying to get the backtrace, even in the signal handler, since typically it | |
92 | + // does work despite not being async-signal-safe. | |
93 | + sleep(5); | |
94 | + RebootSystem(ANDROID_RB_RESTART2, "bootloader"); | |
95 | + } | |
96 | + | |
97 | + // In the parent, let's try to get a backtrace then shutdown. | |
98 | + std::unique_ptr<Backtrace> backtrace( | |
99 | + Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); | |
100 | + if (!backtrace->Unwind(0)) { | |
101 | + LOG(ERROR) << __FUNCTION__ << ": Failed to unwind callstack."; | |
102 | + } | |
103 | + for (size_t i = 0; i < backtrace->NumFrames(); i++) { | |
104 | + LOG(ERROR) << backtrace->FormatFrameData(i); | |
105 | + } | |
106 | + RebootSystem(ANDROID_RB_RESTART2, "bootloader"); | |
107 | +} | |
108 | + | |
78 | 109 | void InstallRebootSignalHandlers() { |
79 | 110 | // Instead of panic'ing the kernel as is the default behavior when init crashes, |
80 | 111 | // we prefer to reboot to bootloader on development builds, as this will prevent |
@@ -94,7 +125,7 @@ void InstallRebootSignalHandlers() { | ||
94 | 125 | // RebootSystem uses syscall() which isn't actually async-signal-safe, but our only option |
95 | 126 | // and probably good enough given this is already an error case and only enabled for |
96 | 127 | // development builds. |
97 | - RebootSystem(ANDROID_RB_RESTART2, "bootloader"); | |
128 | + InitFatalReboot(); | |
98 | 129 | }; |
99 | 130 | action.sa_flags = SA_RESTART; |
100 | 131 | sigaction(SIGABRT, &action, nullptr); |
@@ -26,6 +26,7 @@ namespace init { | ||
26 | 26 | bool IsRebootCapable(); |
27 | 27 | // This is a wrapper around the actual reboot calls. |
28 | 28 | void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& reboot_target); |
29 | +void __attribute__((noreturn)) InitFatalReboot(); | |
29 | 30 | void InstallRebootSignalHandlers(); |
30 | 31 | |
31 | 32 | } // namespace init |
@@ -60,7 +60,6 @@ | ||
60 | 60 | #include <android-base/logging.h> |
61 | 61 | #include <android-base/parseint.h> |
62 | 62 | #include <android-base/unique_fd.h> |
63 | -#include <cutils/android_reboot.h> | |
64 | 63 | #include <fs_avb/fs_avb.h> |
65 | 64 | #include <selinux/android.h> |
66 | 65 |
@@ -518,9 +517,7 @@ int SelinuxGetVendorAndroidVersion() { | ||
518 | 517 | |
519 | 518 | // This function initializes SELinux then execs init to run in the init SELinux context. |
520 | 519 | int SetupSelinux(char** argv) { |
521 | - android::base::InitLogging(argv, &android::base::KernelLogger, [](const char*) { | |
522 | - RebootSystem(ANDROID_RB_RESTART2, "bootloader"); | |
523 | - }); | |
520 | + InitKernelLogging(argv); | |
524 | 521 | |
525 | 522 | if (REBOOT_BOOTLOADER_ON_PANIC) { |
526 | 523 | InstallRebootSignalHandlers(); |
@@ -40,6 +40,7 @@ | ||
40 | 40 | #include <selinux/android.h> |
41 | 41 | |
42 | 42 | #if defined(__ANDROID__) |
43 | +#include "reboot_utils.h" | |
43 | 44 | #include "selinux.h" |
44 | 45 | #else |
45 | 46 | #include "host_init_stubs.h" |
@@ -425,20 +426,49 @@ bool IsLegalPropertyName(const std::string& name) { | ||
425 | 426 | return true; |
426 | 427 | } |
427 | 428 | |
428 | -void InitKernelLogging(char** argv, std::function<void(const char*)> abort_function) { | |
429 | +static void InitAborter(const char* abort_message) { | |
430 | + // When init forks, it continues to use this aborter for LOG(FATAL), but we want children to | |
431 | + // simply abort instead of trying to reboot the system. | |
432 | + if (getpid() != 1) { | |
433 | + android::base::DefaultAborter(abort_message); | |
434 | + return; | |
435 | + } | |
436 | + | |
437 | + InitFatalReboot(); | |
438 | +} | |
439 | + | |
440 | +// The kernel opens /dev/console and uses that fd for stdin/stdout/stderr if there is a serial | |
441 | +// console enabled and no initramfs, otherwise it does not provide any fds for stdin/stdout/stderr. | |
442 | +// SetStdioToDevNull() is used to close these existing fds if they exist and replace them with | |
443 | +// /dev/null regardless. | |
444 | +// | |
445 | +// In the case that these fds are provided by the kernel, the exec of second stage init causes an | |
446 | +// SELinux denial as it does not have access to /dev/console. In the case that they are not | |
447 | +// provided, exec of any further process is potentially dangerous as the first fd's opened by that | |
448 | +// process will take the stdin/stdout/stderr fileno's, which can cause issues if printf(), etc is | |
449 | +// then used by that process. | |
450 | +// | |
451 | +// Lastly, simply calling SetStdioToDevNull() in first stage init is not enough, since first | |
452 | +// stage init still runs in kernel context, future child processes will not have permissions to | |
453 | +// access any fds that it opens, including the one opened below for /dev/null. Therefore, | |
454 | +// SetStdioToDevNull() must be called again in second stage init. | |
455 | +void SetStdioToDevNull(char** argv) { | |
429 | 456 | // Make stdin/stdout/stderr all point to /dev/null. |
430 | 457 | int fd = open("/dev/null", O_RDWR); |
431 | 458 | if (fd == -1) { |
432 | 459 | int saved_errno = errno; |
433 | - android::base::InitLogging(argv, &android::base::KernelLogger, std::move(abort_function)); | |
460 | + android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter); | |
434 | 461 | errno = saved_errno; |
435 | 462 | PLOG(FATAL) << "Couldn't open /dev/null"; |
436 | 463 | } |
437 | - dup2(fd, 0); | |
438 | - dup2(fd, 1); | |
439 | - dup2(fd, 2); | |
440 | - if (fd > 2) close(fd); | |
441 | - android::base::InitLogging(argv, &android::base::KernelLogger, std::move(abort_function)); | |
464 | + dup2(fd, STDIN_FILENO); | |
465 | + dup2(fd, STDOUT_FILENO); | |
466 | + dup2(fd, STDERR_FILENO); | |
467 | + if (fd > STDERR_FILENO) close(fd); | |
468 | +} | |
469 | + | |
470 | +void InitKernelLogging(char** argv) { | |
471 | + android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter); | |
442 | 472 | } |
443 | 473 | |
444 | 474 | bool IsRecoveryMode() { |
@@ -63,7 +63,8 @@ bool is_android_dt_value_expected(const std::string& sub_path, const std::string | ||
63 | 63 | |
64 | 64 | bool IsLegalPropertyName(const std::string& name); |
65 | 65 | |
66 | -void InitKernelLogging(char** argv, std::function<void(const char*)> abort_function); | |
66 | +void SetStdioToDevNull(char** argv); | |
67 | +void InitKernelLogging(char** argv); | |
67 | 68 | bool IsRecoveryMode(); |
68 | 69 | } // namespace init |
69 | 70 | } // namespace android |