diff options
-rw-r--r-- | fs_mgr/fs_mgr.cpp | 35 | ||||
-rw-r--r-- | init/builtins.cpp | 25 | ||||
-rw-r--r-- | init/mount_namespace.cpp | 56 | ||||
-rw-r--r-- | init/mount_namespace.h | 7 | ||||
-rw-r--r-- | init/reboot.cpp | 2 | ||||
-rw-r--r-- | init/service.cpp | 13 | ||||
-rw-r--r-- | init/service_utils.cpp | 10 | ||||
-rw-r--r-- | init/service_utils.h | 5 | ||||
-rw-r--r-- | logd/LogBufferTest.cpp | 98 |
9 files changed, 185 insertions, 66 deletions
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 566cd1184..325afc00d 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -301,10 +301,13 @@ static bool is_ext4_superblock_valid(const struct ext4_super_block* es) { return true; } +static bool needs_block_encryption(const FstabEntry& entry); +static bool should_use_metadata_encryption(const FstabEntry& entry); + // Read the primary superblock from an ext4 filesystem. On failure return // false. If it's not an ext4 filesystem, also set FS_STAT_INVALID_MAGIC. -static bool read_ext4_superblock(const std::string& blk_device, struct ext4_super_block* sb, - int* fs_stat) { +static bool read_ext4_superblock(const std::string& blk_device, const FstabEntry& entry, + struct ext4_super_block* sb, int* fs_stat) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device.c_str(), O_RDONLY | O_CLOEXEC))); if (fd < 0) { @@ -321,7 +324,29 @@ static bool read_ext4_superblock(const std::string& blk_device, struct ext4_supe LINFO << "Invalid ext4 superblock on '" << blk_device << "'"; // not a valid fs, tune2fs, fsck, and mount will all fail. *fs_stat |= FS_STAT_INVALID_MAGIC; - return false; + + bool encrypted = should_use_metadata_encryption(entry) || needs_block_encryption(entry); + if (entry.mount_point == "/data" && + (!encrypted || android::base::StartsWith(blk_device, "/dev/block/dm-"))) { + // try backup superblock, if main superblock is corrupted + for (unsigned int blocksize = EXT4_MIN_BLOCK_SIZE; blocksize <= EXT4_MAX_BLOCK_SIZE; + blocksize *= 2) { + unsigned int superblock = blocksize * 8; + if (blocksize == EXT4_MIN_BLOCK_SIZE) superblock++; + + if (TEMP_FAILURE_RETRY(pread(fd, sb, sizeof(*sb), superblock * blocksize)) != + sizeof(*sb)) { + PERROR << "Can't read '" << blk_device << "' superblock"; + return false; + } + if (is_ext4_superblock_valid(sb) && + (1 << (10 + sb->s_log_block_size) == blocksize)) { + *fs_stat &= ~FS_STAT_INVALID_MAGIC; + break; + } + } + } + if (*fs_stat & FS_STAT_INVALID_MAGIC) return false; } *fs_stat |= FS_STAT_IS_EXT4; LINFO << "superblock s_max_mnt_count:" << sb->s_max_mnt_count << "," << blk_device; @@ -662,7 +687,7 @@ static int prepare_fs_for_mount(const std::string& blk_device, const FstabEntry& if (is_extfs(entry.fs_type)) { struct ext4_super_block sb; - if (read_ext4_superblock(blk_device, &sb, &fs_stat)) { + if (read_ext4_superblock(blk_device, entry, &sb, &fs_stat)) { if ((sb.s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) != 0 || (sb.s_state & EXT4_VALID_FS) == 0) { LINFO << "Filesystem on " << blk_device << " was not cleanly shutdown; " @@ -692,7 +717,7 @@ static int prepare_fs_for_mount(const std::string& blk_device, const FstabEntry& entry.fs_mgr_flags.fs_verity || entry.fs_mgr_flags.ext_meta_csum)) { struct ext4_super_block sb; - if (read_ext4_superblock(blk_device, &sb, &fs_stat)) { + if (read_ext4_superblock(blk_device, entry, &sb, &fs_stat)) { tune_reserved_size(blk_device, entry, &sb, &fs_stat); tune_encrypt(blk_device, entry, &sb, &fs_stat); tune_verity(blk_device, entry, &sb, &fs_stat); diff --git a/init/builtins.cpp b/init/builtins.cpp index 0ac66f272..0b456e70a 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -1221,6 +1221,20 @@ static Result<void> GenerateLinkerConfiguration() { return {}; } +static Result<void> MountLinkerConfigForDefaultNamespace() { + // No need to mount linkerconfig for default mount namespace if the path does not exist (which + // would mean it is already mounted) + if (access("/linkerconfig/default", 0) != 0) { + return {}; + } + + if (mount("/linkerconfig/default", "/linkerconfig", nullptr, MS_BIND | MS_REC, nullptr) != 0) { + return ErrnoError() << "Failed to mount linker configuration for default mount namespace."; + } + + return {}; +} + static bool IsApexUpdatable() { static bool updatable = android::sysprop::ApexProperties::updatable().value_or(false); return updatable; @@ -1319,11 +1333,14 @@ static Result<void> do_perform_apex_config(const BuiltinArguments& args) { } static Result<void> do_enter_default_mount_ns(const BuiltinArguments& args) { - if (SwitchToDefaultMountNamespace()) { - return {}; - } else { - return Error() << "Failed to enter into default mount namespace"; + if (auto result = SwitchToMountNamespaceIfNeeded(NS_DEFAULT); !result.ok()) { + return result.error(); + } + if (auto result = MountLinkerConfigForDefaultNamespace(); !result.ok()) { + return result.error(); } + LOG(INFO) << "Switched to default mount namespace"; + return {}; } // Builtin-function-map start diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp index f3b584c4c..b9d5d674c 100644 --- a/init/mount_namespace.cpp +++ b/init/mount_namespace.cpp @@ -176,20 +176,6 @@ static bool ActivateFlattenedApexesIfPossible() { return true; } -static Result<void> MountLinkerConfigForDefaultNamespace() { - // No need to mount linkerconfig for default mount namespace if the path does not exist (which - // would mean it is already mounted) - if (access("/linkerconfig/default", 0) != 0) { - return {}; - } - - if (mount("/linkerconfig/default", "/linkerconfig", nullptr, MS_BIND | MS_REC, nullptr) != 0) { - return ErrnoError() << "Failed to mount linker configuration for default mount namespace."; - } - - return {}; -} - static android::base::unique_fd bootstrap_ns_fd; static android::base::unique_fd default_ns_fd; @@ -290,40 +276,20 @@ bool SetupMountNamespaces() { return success; } -bool SwitchToDefaultMountNamespace() { - if (IsRecoveryMode()) { - // we don't have multiple namespaces in recovery mode - return true; - } - if (default_ns_id != GetMountNamespaceId()) { - if (setns(default_ns_fd.get(), CLONE_NEWNS) == -1) { - PLOG(ERROR) << "Failed to switch back to the default mount namespace."; - return false; - } - - if (auto result = MountLinkerConfigForDefaultNamespace(); !result.ok()) { - LOG(ERROR) << result.error(); - return false; - } - } - - LOG(INFO) << "Switched to default mount namespace"; - return true; -} - -bool SwitchToBootstrapMountNamespaceIfNeeded() { - if (IsRecoveryMode()) { - // we don't have multiple namespaces in recovery mode - return true; +Result<void> SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace) { + if (IsRecoveryMode() || !IsApexUpdatable()) { + // we don't have multiple namespaces in recovery mode or if apex is not updatable + return {}; } - if (bootstrap_ns_id != GetMountNamespaceId() && bootstrap_ns_fd.get() != -1 && - IsApexUpdatable()) { - if (setns(bootstrap_ns_fd.get(), CLONE_NEWNS) == -1) { - PLOG(ERROR) << "Failed to switch to bootstrap mount namespace."; - return false; + const auto& ns_id = target_mount_namespace == NS_BOOTSTRAP ? bootstrap_ns_id : default_ns_id; + const auto& ns_fd = target_mount_namespace == NS_BOOTSTRAP ? bootstrap_ns_fd : default_ns_fd; + const auto& ns_name = target_mount_namespace == NS_BOOTSTRAP ? "bootstrap" : "default"; + if (ns_id != GetMountNamespaceId() && ns_fd.get() != -1) { + if (setns(ns_fd.get(), CLONE_NEWNS) == -1) { + return ErrnoError() << "Failed to switch to " << ns_name << " mount namespace."; } } - return true; + return {}; } } // namespace init diff --git a/init/mount_namespace.h b/init/mount_namespace.h index c41a449f3..d4d6f82da 100644 --- a/init/mount_namespace.h +++ b/init/mount_namespace.h @@ -16,12 +16,15 @@ #pragma once +#include <android-base/result.h> + namespace android { namespace init { +enum MountNamespace { NS_BOOTSTRAP, NS_DEFAULT }; + bool SetupMountNamespaces(); -bool SwitchToDefaultMountNamespace(); -bool SwitchToBootstrapMountNamespaceIfNeeded(); +base::Result<void> SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace); } // namespace init } // namespace android diff --git a/init/reboot.cpp b/init/reboot.cpp index 23a07aa64..dc932a909 100644 --- a/init/reboot.cpp +++ b/init/reboot.cpp @@ -834,7 +834,7 @@ static Result<void> DoUserspaceReboot() { sub_reason = "apex"; return result; } - if (!SwitchToBootstrapMountNamespaceIfNeeded()) { + if (!SwitchToMountNamespaceIfNeeded(NS_BOOTSTRAP)) { sub_reason = "ns_switch"; return Error() << "Failed to switch to bootstrap namespace"; } diff --git a/init/service.cpp b/init/service.cpp index 165b848a2..68365b3c3 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -465,6 +465,16 @@ Result<void> Service::Start() { pre_apexd_ = true; } + // For pre-apexd services, override mount namespace as "bootstrap" one before starting. + // Note: "ueventd" is supposed to be run in "default" mount namespace even if it's pre-apexd + // to support loading firmwares from APEXes. + std::optional<MountNamespace> override_mount_namespace; + if (name_ == "ueventd") { + override_mount_namespace = NS_DEFAULT; + } else if (pre_apexd_) { + override_mount_namespace = NS_BOOTSTRAP; + } + post_data_ = ServiceList::GetInstance().IsPostData(); LOG(INFO) << "starting service '" << name_ << "'..."; @@ -496,7 +506,8 @@ Result<void> Service::Start() { if (pid == 0) { umask(077); - if (auto result = EnterNamespaces(namespaces_, name_, pre_apexd_); !result.ok()) { + if (auto result = EnterNamespaces(namespaces_, name_, override_mount_namespace); + !result.ok()) { LOG(FATAL) << "Service '" << name_ << "' failed to set up namespaces: " << result.error(); } diff --git a/init/service_utils.cpp b/init/service_utils.cpp index 484c2c89f..05e632b68 100644 --- a/init/service_utils.cpp +++ b/init/service_utils.cpp @@ -194,7 +194,8 @@ Result<Descriptor> FileDescriptor::Create() const { return Descriptor(ANDROID_FILE_ENV_PREFIX + name, std::move(fd)); } -Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name, bool pre_apexd) { +Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name, + std::optional<MountNamespace> override_mount_namespace) { for (const auto& [nstype, path] : info.namespaces_to_enter) { if (auto result = EnterNamespace(nstype, path.c_str()); !result.ok()) { return result; @@ -202,9 +203,10 @@ Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name, } #if defined(__ANDROID__) - if (pre_apexd) { - if (!SwitchToBootstrapMountNamespaceIfNeeded()) { - return Error() << "could not enter into the bootstrap mount namespace"; + if (override_mount_namespace.has_value()) { + if (auto result = SwitchToMountNamespaceIfNeeded(override_mount_namespace.value()); + !result.ok()) { + return result; } } #endif diff --git a/init/service_utils.h b/init/service_utils.h index 3f1071e5b..e74f8c17e 100644 --- a/init/service_utils.h +++ b/init/service_utils.h @@ -19,12 +19,14 @@ #include <sys/resource.h> #include <sys/types.h> +#include <optional> #include <string> #include <vector> #include <android-base/unique_fd.h> #include <cutils/iosched_policy.h> +#include "mount_namespace.h" #include "result.h" namespace android { @@ -66,7 +68,8 @@ struct NamespaceInfo { // Pair of namespace type, path to name. std::vector<std::pair<int, std::string>> namespaces_to_enter; }; -Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name, bool pre_apexd); +Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name, + std::optional<MountNamespace> override_mount_namespace); struct ProcessAttributes { std::string console; diff --git a/logd/LogBufferTest.cpp b/logd/LogBufferTest.cpp index e651b4fec..412b6f1d7 100644 --- a/logd/LogBufferTest.cpp +++ b/logd/LogBufferTest.cpp @@ -26,6 +26,7 @@ #include <android-base/stringprintf.h> #include <android-base/strings.h> +#include "LogBuffer.h" #include "LogReaderThread.h" #include "LogWriter.h" @@ -240,7 +241,7 @@ TEST_P(LogBufferTest, smoke_with_reader_thread) { std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released)); std::unique_ptr<LogReaderThread> log_reader( new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true, - 0, ~0, 0, {}, 1, {})); + 0, kLogMaskAll, 0, {}, 1, {})); reader_list_.reader_threads().emplace_back(std::move(log_reader)); } @@ -314,7 +315,7 @@ TEST_P(LogBufferTest, random_messages) { std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released)); std::unique_ptr<LogReaderThread> log_reader( new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true, - 0, ~0, 0, {}, 1, {})); + 0, kLogMaskAll, 0, {}, 1, {})); reader_list_.reader_threads().emplace_back(std::move(log_reader)); } @@ -348,7 +349,7 @@ TEST_P(LogBufferTest, read_last_sequence) { std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released)); std::unique_ptr<LogReaderThread> log_reader( new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true, - 0, ~0, 0, {}, 3, {})); + 0, kLogMaskAll, 0, {}, 3, {})); reader_list_.reader_threads().emplace_back(std::move(log_reader)); } @@ -363,4 +364,95 @@ TEST_P(LogBufferTest, read_last_sequence) { CompareLogMessages(expected_log_messages, read_log_messages); } +TEST_P(LogBufferTest, clear_logs) { + // Log 3 initial logs. + std::vector<LogMessage> log_messages = { + {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0}, + "first"}, + {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0}, + "second"}, + {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0}, + "third"}, + }; + FixupMessages(&log_messages); + LogMessages(log_messages); + + std::vector<LogMessage> read_log_messages; + bool released = false; + + // Connect a blocking reader. + { + auto lock = std::unique_lock{reader_list_.reader_threads_lock()}; + std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released)); + std::unique_ptr<LogReaderThread> log_reader( + new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), false, + 0, kLogMaskAll, 0, {}, 1, {})); + reader_list_.reader_threads().emplace_back(std::move(log_reader)); + } + + // Wait up to 250ms for the reader to read the first 3 logs. + constexpr int kMaxRetryCount = 50; + int count = 0; + for (; count < kMaxRetryCount; ++count) { + usleep(5000); + auto lock = std::unique_lock{reader_list_.reader_threads_lock()}; + if (reader_list_.reader_threads().back()->start() == 4) { + break; + } + } + ASSERT_LT(count, kMaxRetryCount); + + // Clear the log buffer. + log_buffer_->Clear(LOG_ID_MAIN, 0); + + // Log 3 more logs. + std::vector<LogMessage> after_clear_messages = { + {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0}, + "4th"}, + {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0}, + "5th"}, + {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0}, + "6th"}, + }; + FixupMessages(&after_clear_messages); + LogMessages(after_clear_messages); + + // Wait up to 250ms for the reader to read the 3 additional logs. + for (count = 0; count < kMaxRetryCount; ++count) { + usleep(5000); + auto lock = std::unique_lock{reader_list_.reader_threads_lock()}; + if (reader_list_.reader_threads().back()->start() == 7) { + break; + } + } + ASSERT_LT(count, kMaxRetryCount); + + // Release the reader, wait for it to get the signal then check that it has been deleted. + { + auto lock = std::unique_lock{reader_list_.reader_threads_lock()}; + reader_list_.reader_threads().back()->release_Locked(); + } + while (!released) { + usleep(5000); + } + { + auto lock = std::unique_lock{reader_list_.reader_threads_lock()}; + EXPECT_EQ(0U, reader_list_.reader_threads().size()); + } + + // Check that we have read all 6 messages. + std::vector<LogMessage> expected_log_messages = log_messages; + expected_log_messages.insert(expected_log_messages.end(), after_clear_messages.begin(), + after_clear_messages.end()); + CompareLogMessages(expected_log_messages, read_log_messages); + + // Finally, call FlushTo and ensure that only the 3 logs after the clear remain in the buffer. + std::vector<LogMessage> read_log_messages_after_clear; + std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages_after_clear, nullptr)); + std::unique_ptr<FlushToState> flush_to_state = log_buffer_->CreateFlushToState(1, kLogMaskAll); + EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr)); + EXPECT_EQ(7ULL, flush_to_state->start()); + CompareLogMessages(after_clear_messages, read_log_messages_after_clear); +} + INSTANTIATE_TEST_CASE_P(LogBufferTests, LogBufferTest, testing::Values("chatty", "simple")); |