From 519e5f0592eb7ceb812f9e0e61b3bc2d9fc27c74 Mon Sep 17 00:00:00 2001 From: Luis Hector Chavez Date: Thu, 29 Jun 2017 09:50:30 -0700 Subject: [PATCH 1/2] init: Reland "Terminate gracefully when CAP_SYS_BOOT is absent" This change makes it possible for Android running in a container to terminate cleanly instead of calling abort() when requested to shut down. Bug: 62388055 Test: `adb reboot` on bullhead causes no kernel panics Test: `adb reboot` on a system without CAP_SYS_BOOT makes init terminate nicely Change-Id: I36b2298610f5b4a2bf8b05103d04804883df2c88 --- init/capabilities.h | 8 +++++++- init/reboot.cpp | 31 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/init/capabilities.h b/init/capabilities.h index ef507a617..ede85c324 100644 --- a/init/capabilities.h +++ b/init/capabilities.h @@ -15,15 +15,21 @@ #ifndef _INIT_CAPABILITIES_H #define _INIT_CAPABILITIES_H -#include +#include #include #include +#include namespace android { namespace init { +struct CapDeleter { + void operator()(cap_t caps) const { cap_free(caps); } +}; + using CapSet = std::bitset; +using ScopedCaps = std::unique_ptr::type, CapDeleter>; int LookupCap(const std::string& cap_name); bool CapAmbientSupported(); diff --git a/init/reboot.cpp b/init/reboot.cpp index df7912f96..c8bb98b54 100644 --- a/init/reboot.cpp +++ b/init/reboot.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,7 @@ #include #include +#include "capabilities.h" #include "property_service.h" #include "service.h" @@ -162,9 +164,38 @@ static void LogShutdownTime(UmountStat stat, Timer* t) { LOG(WARNING) << "powerctl_shutdown_time_ms:" << std::to_string(t->duration_ms()) << ":" << stat; } +// Determines whether the system is capable of rebooting. This is conservative, +// so if any of the attempts to determine this fail, it will still return true. +static bool IsRebootCapable() { + if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) { + PLOG(WARNING) << "CAP_SYS_BOOT is not supported"; + return true; + } + + ScopedCaps caps(cap_get_proc()); + if (!caps) { + PLOG(WARNING) << "cap_get_proc() failed"; + return true; + } + + cap_flag_value_t value = CAP_SET; + if (cap_get_flag(caps.get(), CAP_SYS_BOOT, CAP_EFFECTIVE, &value) != 0) { + PLOG(WARNING) << "cap_get_flag(CAP_SYS_BOOT, EFFECTIVE) failed"; + return true; + } + return value == CAP_SET; +} + static void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) { LOG(INFO) << "Reboot ending, jumping to kernel"; + + if (!IsRebootCapable()) { + // On systems where init does not have the capability of rebooting the + // device, just exit cleanly. + exit(0); + } + switch (cmd) { case ANDROID_RB_POWEROFF: reboot(RB_POWER_OFF); From 7bb360230d01f2eb2194cd362874ef199517a064 Mon Sep 17 00:00:00 2001 From: Luis Hector Chavez Date: Thu, 29 Jun 2017 09:47:51 -0700 Subject: [PATCH 2/2] init: Use ScopedCaps for cap_init() This change homogenizes the use of std::unique_ptr for storing capabilities in system/core/. Bug: None Test: m Change-Id: I0a95f87a27b0261e9d321841d5140fc000473293 --- init/capabilities.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/init/capabilities.cpp b/init/capabilities.cpp index 53832a493..642a3642f 100644 --- a/init/capabilities.cpp +++ b/init/capabilities.cpp @@ -107,17 +107,15 @@ static bool DropBoundingSet(const CapSet& to_keep) { } static bool SetProcCaps(const CapSet& to_keep, bool add_setpcap) { - cap_t caps = cap_init(); - auto deleter = [](cap_t* p) { cap_free(*p); }; - std::unique_ptr ptr_caps(&caps, deleter); + ScopedCaps caps(cap_init()); - cap_clear(caps); + cap_clear(caps.get()); cap_value_t value[1]; for (size_t cap = 0; cap < to_keep.size(); ++cap) { if (to_keep.test(cap)) { value[0] = cap; - if (cap_set_flag(caps, CAP_INHERITABLE, arraysize(value), value, CAP_SET) != 0 || - cap_set_flag(caps, CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0) { + if (cap_set_flag(caps.get(), CAP_INHERITABLE, arraysize(value), value, CAP_SET) != 0 || + cap_set_flag(caps.get(), CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0) { PLOG(ERROR) << "cap_set_flag(INHERITABLE|PERMITTED, " << cap << ") failed"; return false; } @@ -126,14 +124,14 @@ static bool SetProcCaps(const CapSet& to_keep, bool add_setpcap) { if (add_setpcap) { value[0] = CAP_SETPCAP; - if (cap_set_flag(caps, CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0 || - cap_set_flag(caps, CAP_EFFECTIVE, arraysize(value), value, CAP_SET) != 0) { + if (cap_set_flag(caps.get(), CAP_PERMITTED, arraysize(value), value, CAP_SET) != 0 || + cap_set_flag(caps.get(), CAP_EFFECTIVE, arraysize(value), value, CAP_SET) != 0) { PLOG(ERROR) << "cap_set_flag(PERMITTED|EFFECTIVE, " << CAP_SETPCAP << ") failed"; return false; } } - if (cap_set_proc(caps) != 0) { + if (cap_set_proc(caps.get()) != 0) { PLOG(ERROR) << "cap_set_proc(" << to_keep.to_ulong() << ") failed"; return false; }