From d8db7ab80d8a79c89393fa0c4ab343e85312d8d5 Mon Sep 17 00:00:00 2001 From: Tom Cherry Date: Thu, 17 Aug 2017 17:28:30 -0700 Subject: [PATCH] init: replace panic() with LOG(FATAL) Test: boot bullhead Test: Introduce LOG(FATAL) at various points of init and ensure that it reboots to the bootloader successfully Test: Introduce LOG(FATAL) during DoReboot() and ensure that it reboots instead of recursing infinitely Test: Ensure that fatal signals reboot to bootloader Change-Id: I409005b6fab379df2d635e3e33d2df48a1a97df3 --- init/init.cpp | 23 +++++++++++------------ init/log.cpp | 22 ++++++++++++++++++++-- init/reboot.cpp | 5 ++--- init/reboot.h | 3 +++ init/security.cpp | 8 ++------ init/selinux.cpp | 8 +++----- init/service.cpp | 3 +-- init/util.cpp | 6 ------ init/util.h | 2 -- 9 files changed, 42 insertions(+), 38 deletions(-) diff --git a/init/init.cpp b/init/init.cpp index c65d8460b..d0afac11d 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -252,8 +253,7 @@ static Result wait_for_coldboot_done_action(const std::vector queue_property_triggers_action(const std::vector #include +#include #include +#include "reboot.h" + namespace android { namespace init { +static void RebootAborter(const char* abort_message) { + // DoReboot() does a lot to try to shutdown the system cleanly. If something happens to call + // LOG(FATAL) in the shutdown path, we want to catch this and immediately use the syscall to + // reboot instead of recursing here. + static bool has_aborted = false; + if (!has_aborted) { + has_aborted = true; + // Do not queue "shutdown" trigger since we want to shutdown immediately and it's not likely + // that we can even run the ActionQueue at this point. + DoReboot(ANDROID_RB_RESTART2, "reboot", "bootloader", false); + } else { + RebootSystem(ANDROID_RB_RESTART2, "bootloader"); + } +} + void InitKernelLogging(char* argv[]) { // Make stdin/stdout/stderr all point to /dev/null. int fd = open("/sys/fs/selinux/null", O_RDWR); if (fd == -1) { int saved_errno = errno; - android::base::InitLogging(argv, &android::base::KernelLogger); + android::base::InitLogging(argv, &android::base::KernelLogger, RebootAborter); errno = saved_errno; PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null"; } @@ -40,7 +58,7 @@ void InitKernelLogging(char* argv[]) { dup2(fd, 2); if (fd > 2) close(fd); - android::base::InitLogging(argv, &android::base::KernelLogger); + android::base::InitLogging(argv, &android::base::KernelLogger, RebootAborter); } int selinux_klog_callback(int type, const char *fmt, ...) { diff --git a/init/reboot.cpp b/init/reboot.cpp index 24ccdfc6a..e2453c3b0 100644 --- a/init/reboot.cpp +++ b/init/reboot.cpp @@ -191,8 +191,7 @@ static bool IsRebootCapable() { return value == CAP_SET; } -static void __attribute__((noreturn)) -RebootSystem(unsigned int cmd, const std::string& rebootTarget) { +void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) { LOG(INFO) << "Reboot ending, jumping to kernel"; if (!IsRebootCapable()) { @@ -216,7 +215,7 @@ RebootSystem(unsigned int cmd, const std::string& rebootTarget) { break; } // In normal case, reboot should not return. - PLOG(FATAL) << "reboot call returned"; + PLOG(ERROR) << "reboot call returned"; abort(); } diff --git a/init/reboot.h b/init/reboot.h index e55954015..8586556e7 100644 --- a/init/reboot.h +++ b/init/reboot.h @@ -22,6 +22,9 @@ namespace android { namespace init { +// This is a wrapper around the actual reboot calls. DoReboot() should be preferred in most cases. +void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget); + /* Reboot / shutdown the system. * cmd ANDROID_RB_* as defined in android_reboot.h * reason Reason string like "reboot", "userrequested" diff --git a/init/security.cpp b/init/security.cpp index f8976dec2..aac8f2e74 100644 --- a/init/security.cpp +++ b/init/security.cpp @@ -25,8 +25,6 @@ #include #include -#include "util.h" - using android::base::unique_fd; namespace android { @@ -178,8 +176,7 @@ Result SetMmapRndBitsAction(const std::vector& args) { LOG(ERROR) << "Unknown architecture"; #endif - LOG(ERROR) << "Unable to set adequate mmap entropy value!"; - panic(); + LOG(FATAL) << "Unable to set adequate mmap entropy value!"; return Error(); } @@ -194,8 +191,7 @@ Result SetKptrRestrictAction(const std::vector& args) { std::string path = KPTR_RESTRICT_PATH; if (!SetHighestAvailableOptionValue(path, KPTR_RESTRICT_MINVALUE, KPTR_RESTRICT_MAXVALUE)) { - LOG(ERROR) << "Unable to set adequate kptr_restrict value!"; - panic(); + LOG(FATAL) << "Unable to set adequate kptr_restrict value!"; return Error(); } return Success(); diff --git a/init/selinux.cpp b/init/selinux.cpp index b9305ed47..0628cb0a7 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -327,21 +327,19 @@ void SelinuxInitialize() { LOG(INFO) << "Loading SELinux policy"; if (!LoadPolicy()) { - panic(); + LOG(FATAL) << "Unable to load SELinux policy"; } bool kernel_enforcing = (security_getenforce() == 1); bool is_enforcing = IsEnforcing(); if (kernel_enforcing != is_enforcing) { if (security_setenforce(is_enforcing)) { - PLOG(ERROR) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false"); - panic(); + PLOG(FATAL) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false"); } } if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result) { - LOG(ERROR) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error(); - panic(); + LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error(); } // init's first stage can't set properties, so pass the time to the second stage. diff --git a/init/service.cpp b/init/service.cpp index 1b5cc19e4..c201ec938 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -306,8 +306,7 @@ void Service::Reap() { if ((flags_ & SVC_CRITICAL) && !(flags_ & SVC_RESTART)) { if (now < time_crashed_ + 4min) { if (++crash_count_ > 4) { - LOG(ERROR) << "critical process '" << name_ << "' exited 4 times in 4 minutes"; - panic(); + LOG(FATAL) << "critical process '" << name_ << "' exited 4 times in 4 minutes"; } } else { time_crashed_ = now; diff --git a/init/util.cpp b/init/util.cpp index fcf7ca882..9112c3fd3 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -345,12 +345,6 @@ bool expand_props(const std::string& src, std::string* dst) { return true; } -void panic() { - LOG(ERROR) << "panic: rebooting to bootloader"; - // Do not queue "shutdown" trigger since we want to shutdown immediately - DoReboot(ANDROID_RB_RESTART2, "reboot", "bootloader", false); -} - static std::string init_android_dt_dir() { // Use the standard procfs-based path by default std::string android_dt_dir = kDefaultAndroidDtDir; diff --git a/init/util.h b/init/util.h index 298aa1cb2..2cfcf6c78 100644 --- a/init/util.h +++ b/init/util.h @@ -55,8 +55,6 @@ std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len); bool is_dir(const char* pathname); bool expand_props(const std::string& src, std::string* dst); -void panic() __attribute__((__noreturn__)); - // Returns the platform's Android DT directory as specified in the kernel cmdline. // If the platform does not configure a custom DT path, returns the standard one (based in procfs). const std::string& get_android_dt_dir();