Merge "Adding fuzzer for trusty-confirmationui service."
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 1be69c3..7afbbe7 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -426,8 +426,8 @@
local_include_dirs: ["include"],
}
-cc_binary {
- name: "tombstoned",
+cc_defaults {
+ name: "tombstoned_defaults",
srcs: [
"util.cpp",
"tombstoned/intercept_manager.cpp",
@@ -446,10 +446,20 @@
"libevent",
"liblog",
],
+}
+cc_binary {
+ name: "tombstoned",
+ defaults: ["tombstoned_defaults"],
init_rc: ["tombstoned/tombstoned.rc"],
}
+cc_binary {
+ name: "tombstoned.microdroid",
+ defaults: ["tombstoned_defaults"],
+ init_rc: ["tombstoned/tombstoned.microdroid.rc"],
+}
+
prebuilt_etc {
name: "crash_dump.policy",
sub_dir: "seccomp_policy",
diff --git a/debuggerd/crasher/Android.bp b/debuggerd/crasher/Android.bp
index effd480..3af806b 100644
--- a/debuggerd/crasher/Android.bp
+++ b/debuggerd/crasher/Android.bp
@@ -19,10 +19,6 @@
arch: {
arm: {
srcs: ["arm/crashglue.S"],
-
- neon: {
- asflags: ["-DHAS_VFP_D32"],
- },
},
arm64: {
srcs: ["arm64/crashglue.S"],
diff --git a/debuggerd/crasher/arm/crashglue.S b/debuggerd/crasher/arm/crashglue.S
index 4fbfd6e..8649056 100644
--- a/debuggerd/crasher/arm/crashglue.S
+++ b/debuggerd/crasher/arm/crashglue.S
@@ -32,7 +32,6 @@
fconstd d13, #13
fconstd d14, #14
fconstd d15, #15
-#if defined(HAS_VFP_D32)
fconstd d16, #16
fconstd d17, #17
fconstd d18, #18
@@ -49,7 +48,6 @@
fconstd d29, #29
fconstd d30, #30
fconstd d31, #31
-#endif
mov lr, #0
ldr lr, [lr]
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index c08721b..9c1b136 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -445,6 +445,8 @@
ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
#elif defined(__arm__)
ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
+#elif defined(__riscv)
+ ASSERT_MATCH(result, "memory near a0 \\(\\[anon:");
#elif defined(__x86_64__)
ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
#else
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index e5b4d74..375ed8a 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -77,9 +77,9 @@
.registers = std::move(regs), .uid = uid, .tid = target_tid,
.thread_name = std::move(thread_name), .pid = pid, .command_line = std::move(command_line),
.selinux_label = std::move(selinux_label), .siginfo = siginfo,
-#if defined(__aarch64__)
// Only supported on aarch64 for now.
- .tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0),
+#if defined(__aarch64__)
+ .tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0),
.pac_enabled_keys = prctl(PR_PAC_GET_ENABLED_KEYS, 0, 0, 0, 0),
#endif
};
@@ -88,7 +88,6 @@
if (target_tid == tid) {
return;
}
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "Adding thread %d", tid);
threads[tid] = ThreadInfo{
.uid = thread.uid,
.tid = tid,
diff --git a/debuggerd/tombstoned/tombstoned.microdroid.rc b/debuggerd/tombstoned/tombstoned.microdroid.rc
new file mode 100644
index 0000000..7f5c542
--- /dev/null
+++ b/debuggerd/tombstoned/tombstoned.microdroid.rc
@@ -0,0 +1,7 @@
+service tombstoned /system/bin/tombstoned.microdroid
+ user tombstoned
+ group system
+
+ socket tombstoned_crash seqpacket 0666 system system
+ socket tombstoned_intercept seqpacket 0666 system system
+ socket tombstoned_java_trace seqpacket 0666 system system
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 27137a2..1c1ab48 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -2191,36 +2191,22 @@
std::vector<std::string> tokens = android::base::Split(target.data, " \t\r\n");
if (tokens[0] != "0" && tokens[0] != "1") {
LOG(WARNING) << "Unrecognized device mapper version in " << target.data;
- return {};
}
// Hashtree algorithm & root digest are the 8th & 9th token in the output.
- return HashtreeInfo{.algorithm = android::base::Trim(tokens[7]),
- .root_digest = android::base::Trim(tokens[8])};
+ return HashtreeInfo{
+ .algorithm = android::base::Trim(tokens[7]),
+ .root_digest = android::base::Trim(tokens[8]),
+ .check_at_most_once = target.data.find("check_at_most_once") != std::string::npos};
}
return {};
}
bool fs_mgr_verity_is_check_at_most_once(const android::fs_mgr::FstabEntry& entry) {
- if (!entry.fs_mgr_flags.avb) {
- return false;
- }
-
- DeviceMapper& dm = DeviceMapper::Instance();
- std::string device = GetVerityDeviceName(entry);
-
- std::vector<DeviceMapper::TargetInfo> table;
- if (dm.GetState(device) == DmDeviceState::INVALID || !dm.GetTableInfo(device, &table)) {
- return false;
- }
- for (const auto& target : table) {
- if (strcmp(target.spec.target_type, "verity") == 0 &&
- target.data.find("check_at_most_once") != std::string::npos) {
- return true;
- }
- }
- return false;
+ auto hashtree_info = fs_mgr_get_hashtree_info(entry);
+ if (!hashtree_info) return false;
+ return hashtree_info->check_at_most_once;
}
std::string fs_mgr_get_super_partition_name(int slot) {
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index ef426dc..5468fb8 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -462,6 +462,28 @@
return true;
}
+OverlayfsTeardownResult TeardownDataScratch(IImageManager* images,
+ const std::string& partition_name, bool was_mounted) {
+ if (!images) {
+ return OverlayfsTeardownResult::Error;
+ }
+ if (!images->DisableImage(partition_name)) {
+ return OverlayfsTeardownResult::Error;
+ }
+ if (was_mounted) {
+ // If overlayfs was mounted, don't bother trying to unmap since
+ // it'll fail and create error spam.
+ return OverlayfsTeardownResult::Busy;
+ }
+ if (!images->UnmapImageIfExists(partition_name)) {
+ return OverlayfsTeardownResult::Busy;
+ }
+ if (!images->DeleteBackingImage(partition_name)) {
+ return OverlayfsTeardownResult::Busy;
+ }
+ return OverlayfsTeardownResult::Ok;
+}
+
OverlayfsTeardownResult fs_mgr_overlayfs_teardown_scratch(const std::string& overlay,
bool* change) {
// umount and delete kScratchMountPoint storage if we have logical partitions
@@ -484,24 +506,9 @@
auto images = IImageManager::Open("remount", 10s);
if (images && images->BackingImageExists(partition_name)) {
- if (!images->DisableImage(partition_name)) {
- return OverlayfsTeardownResult::Error;
- }
- if (was_mounted) {
- // If overlayfs was mounted, don't bother trying to unmap since
- // it'll fail and create error spam.
- return OverlayfsTeardownResult::Busy;
- }
- if (!images->UnmapImageIfExists(partition_name)) {
- return OverlayfsTeardownResult::Busy;
- }
- if (!images->DeleteBackingImage(partition_name)) {
- return OverlayfsTeardownResult::Busy;
- }
-
// No need to check super partition, if we knew we had a scratch device
// in /data.
- return OverlayfsTeardownResult::Ok;
+ return TeardownDataScratch(images.get(), partition_name, was_mounted);
}
auto slot_number = fs_mgr_overlayfs_slot_number();
@@ -1103,6 +1110,8 @@
}
if (!images->MapImageDevice(partition_name, 10s, scratch_device)) {
LERROR << "could not map scratch image";
+ // If we cannot use this image, then remove it.
+ TeardownDataScratch(images.get(), partition_name, false /* was_mounted */);
return false;
}
return true;
@@ -1133,7 +1142,10 @@
// Try ImageManager on /data first.
bool can_use_data = false;
if (FilesystemHasReliablePinning("/data", &can_use_data) && can_use_data) {
- return CreateScratchOnData(scratch_device, partition_exists);
+ if (CreateScratchOnData(scratch_device, partition_exists)) {
+ return true;
+ }
+ LOG(WARNING) << "Failed to allocate scratch on /data, fallback to use free space on super";
}
// If that fails, see if we can land on super.
if (CanUseSuperPartition(fstab)) {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 29a5e60..43de6d8 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -71,6 +71,8 @@
std::string algorithm;
// The root digest of the merkle tree.
std::string root_digest;
+ // If check_at_most_once is enabled.
+ bool check_at_most_once;
};
// fs_mgr_mount_all() updates fstab entries that reference device-mapper.
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 474d482..8e4b556 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -324,6 +324,22 @@
"libstatslog",
"libutils",
],
+ header_libs: [
+ "libstorage_literals_headers",
+ ],
+ product_variables: {
+ debuggable: {
+ cppflags: [
+ "-DSNAPSHOTCTL_USERDEBUG_OR_ENG",
+ ],
+ shared_libs: [
+ "android.hardware.boot@1.0",
+ "android.hardware.boot@1.1",
+ "android.hardware.boot-V1-ndk",
+ "libboot_control_client",
+ ],
+ },
+ },
}
cc_test {
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index 19f3649..b93fd32 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -165,10 +165,6 @@
bool is_dev_null_ = false;
bool merge_in_progress_ = false;
bool is_block_device_ = false;
-
- // :TODO: this is not efficient, but stringstream ubsan aborts because some
- // bytes overflow a signed char.
- std::basic_string<uint8_t> ops_;
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp
index 015bff0..5f5d1fb 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp
@@ -207,7 +207,6 @@
} else {
next_data_pos_ = next_op_pos_ + sizeof(CowOperation);
}
- ops_.clear();
current_cluster_size_ = 0;
current_data_size_ = 0;
}
@@ -432,7 +431,6 @@
auto continue_data_size = current_data_size_;
auto continue_data_pos = next_data_pos_;
auto continue_op_pos = next_op_pos_;
- auto continue_size = ops_.size();
auto continue_num_ops = footer_.op.num_ops;
bool extra_cluster = false;
@@ -458,7 +456,7 @@
extra_cluster = true;
}
- footer_.op.ops_size = ops_.size();
+ footer_.op.ops_size = footer_.op.num_ops * sizeof(CowOperation);
if (lseek(fd_.get(), next_op_pos_, SEEK_SET) < 0) {
PLOG(ERROR) << "Failed to seek to footer position.";
return false;
@@ -466,7 +464,6 @@
memset(&footer_.data.ops_checksum, 0, sizeof(uint8_t) * 32);
memset(&footer_.data.footer_checksum, 0, sizeof(uint8_t) * 32);
- SHA256(ops_.data(), ops_.size(), footer_.data.ops_checksum);
SHA256(&footer_.op, sizeof(footer_.op), footer_.data.footer_checksum);
// Write out footer at end of file
if (!android::base::WriteFully(fd_, reinterpret_cast<const uint8_t*>(&footer_),
@@ -493,7 +490,6 @@
next_data_pos_ = continue_data_pos;
next_op_pos_ = continue_op_pos;
footer_.op.num_ops = continue_num_ops;
- ops_.resize(continue_size);
}
return Sync();
}
@@ -544,7 +540,6 @@
next_data_pos_ += op.data_length + GetNextDataOffset(op, header_.cluster_ops);
next_op_pos_ += sizeof(CowOperation) + GetNextOpOffset(op, header_.cluster_ops);
- ops_.insert(ops_.size(), reinterpret_cast<const uint8_t*>(&op), sizeof(op));
}
bool CowWriter::WriteRawData(const void* data, size_t size) {
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index 67189d4..ad3f83c 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -25,9 +25,27 @@
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
+#include <fs_mgr.h>
+#include <fs_mgr_dm_linear.h>
+#include <fstab/fstab.h>
+#include <liblp/builder.h>
+#include <libsnapshot/cow_format.h>
#include <libsnapshot/snapshot.h>
+#include <storage_literals/storage_literals.h>
+#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
+#include <BootControlClient.h>
+#endif
+
+using namespace std::chrono_literals;
using namespace std::string_literals;
+using namespace android::storage_literals;
+using android::fs_mgr::CreateLogicalPartitionParams;
+using android::fs_mgr::FindPartition;
+using android::fs_mgr::GetPartitionSize;
+using android::fs_mgr::PartitionOpener;
+using android::fs_mgr::ReadMetadata;
+using android::fs_mgr::SlotNumberForSlotSuffix;
int Usage() {
std::cerr << "snapshotctl: Control snapshots.\n"
@@ -67,11 +85,136 @@
return false;
}
+#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
+bool CreateTestUpdate(SnapshotManager* sm) {
+ chromeos_update_engine::DeltaArchiveManifest manifest;
+
+ // We only copy system, to simplify things.
+ manifest.set_partial_update(true);
+
+ auto dap = manifest.mutable_dynamic_partition_metadata();
+ dap->set_snapshot_enabled(true);
+ dap->set_vabc_enabled(true);
+ dap->set_vabc_compression_param("none");
+ dap->set_cow_version(kCowVersionMajor);
+
+ auto source_slot = fs_mgr_get_slot_suffix();
+ auto source_slot_number = SlotNumberForSlotSuffix(source_slot);
+ auto target_slot = fs_mgr_get_other_slot_suffix();
+ auto target_slot_number = SlotNumberForSlotSuffix(target_slot);
+ auto super_source = fs_mgr_get_super_partition_name(source_slot_number);
+
+ // Get current partition information.
+ PartitionOpener opener;
+ auto source_metadata = ReadMetadata(opener, super_source, source_slot_number);
+ if (!source_metadata) {
+ std::cerr << "Could not read source partition metadata.\n";
+ return false;
+ }
+
+ auto system_source_name = "system" + source_slot;
+ auto system_source = FindPartition(*source_metadata.get(), system_source_name);
+ if (!system_source) {
+ std::cerr << "Could not find system partition: " << system_source_name << ".\n";
+ return false;
+ }
+ auto system_source_size = GetPartitionSize(*source_metadata.get(), *system_source);
+
+ // Since we only add copy operations, 64MB should be enough.
+ auto system_update = manifest.mutable_partitions()->Add();
+ system_update->set_partition_name("system");
+ system_update->set_estimate_cow_size(64_MiB);
+ system_update->mutable_new_partition_info()->set_size(system_source_size);
+
+ if (!sm->CreateUpdateSnapshots(manifest)) {
+ std::cerr << "Could not create update snapshots.\n";
+ return false;
+ }
+
+ // Write the "new" system partition.
+ auto system_target_name = "system" + target_slot;
+ auto source_device = "/dev/block/mapper/" + system_source_name;
+ CreateLogicalPartitionParams clpp = {
+ .block_device = fs_mgr_get_super_partition_name(target_slot_number),
+ .metadata_slot = {target_slot_number},
+ .partition_name = system_target_name,
+ .partition_opener = &opener,
+ .timeout_ms = 10s,
+ };
+ auto writer = sm->OpenSnapshotWriter(clpp, {source_device});
+ if (!writer) {
+ std::cerr << "Could not open snapshot writer.\n";
+ return false;
+ }
+ if (!writer->Initialize()) {
+ std::cerr << "Could not initialize snapshot for writing.\n";
+ return false;
+ }
+
+ for (uint64_t block = 0; block < system_source_size / 4096; block++) {
+ if (!writer->AddCopy(block, block)) {
+ std::cerr << "Unable to add copy operation for block " << block << ".\n";
+ return false;
+ }
+ }
+ if (!writer->Finalize()) {
+ std::cerr << "Could not finalize COW for " << system_target_name << ".\n";
+ return false;
+ }
+ writer = nullptr;
+
+ // Finished writing this partition, unmap.
+ if (!sm->UnmapUpdateSnapshot(system_target_name)) {
+ std::cerr << "Could not unmap snapshot for " << system_target_name << ".\n";
+ return false;
+ }
+
+ // All snapshots have been written.
+ if (!sm->FinishedSnapshotWrites(false /* wipe */)) {
+ std::cerr << "Could not finalize snapshot writes.\n";
+ return false;
+ }
+
+ auto hal = hal::BootControlClient::WaitForService();
+ if (!hal) {
+ std::cerr << "Could not find IBootControl HAL.\n";
+ return false;
+ }
+ auto cr = hal->SetActiveBootSlot(target_slot_number);
+ if (!cr.IsOk()) {
+ std::cerr << "Could not set active boot slot: " << cr.errMsg;
+ return false;
+ }
+
+ std::cerr << "It is now safe to reboot your device. If using a physical device, make\n"
+ << "sure that all physical partitions are flashed to both A and B slots.\n";
+ return true;
+}
+
+bool TestOtaHandler(int /* argc */, char** /* argv */) {
+ auto sm = SnapshotManager::New();
+
+ if (!sm->BeginUpdate()) {
+ std::cerr << "Error starting update.\n";
+ return false;
+ }
+
+ if (!CreateTestUpdate(sm.get())) {
+ sm->CancelUpdate();
+ return false;
+ }
+ return true;
+}
+#endif
+
static std::map<std::string, std::function<bool(int, char**)>> kCmdMap = {
// clang-format off
{"dump", DumpCmdHandler},
{"merge", MergeCmdHandler},
{"map", MapCmdHandler},
+#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
+ {"test-blank-ota", TestOtaHandler},
+#endif
{"unmap", UnmapCmdHandler},
// clang-format on
};
diff --git a/init/Android.bp b/init/Android.bp
index f6f1e8c..06f696e 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -39,6 +39,7 @@
"epoll.cpp",
"import_parser.cpp",
"interface_utils.cpp",
+ "interprocess_fifo.cpp",
"keychords.cpp",
"parser.cpp",
"property_type.cpp",
@@ -467,6 +468,7 @@
"epoll_test.cpp",
"firmware_handler_test.cpp",
"init_test.cpp",
+ "interprocess_fifo_test.cpp",
"keychords_test.cpp",
"oneshot_on_test.cpp",
"persistent_properties_test.cpp",
@@ -481,7 +483,10 @@
"ueventd_test.cpp",
"util_test.cpp",
],
- static_libs: ["libinit"],
+ static_libs: [
+ "libgmock",
+ "libinit",
+ ],
test_suites: [
"cts",
diff --git a/init/builtins.cpp b/init/builtins.cpp
index c8cb253..7cb8b11 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -879,6 +879,8 @@
SetProperty("partition." + partition + ".verified.hash_alg", hashtree_info->algorithm);
SetProperty("partition." + partition + ".verified.root_digest",
hashtree_info->root_digest);
+ SetProperty("partition." + partition + ".verified.check_at_most_once",
+ hashtree_info->check_at_most_once ? "1" : "0");
}
}
diff --git a/init/init.cpp b/init/init.cpp
index 4ca351c..57397b5 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -747,6 +747,9 @@
do {
ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo)));
if (bytes_read < 0 && errno == EAGAIN) {
+ if (one_off) {
+ return;
+ }
auto now = std::chrono::steady_clock::now();
std::chrono::duration<double> waited = now - started;
if (waited >= kDiagnosticTimeout) {
@@ -772,7 +775,7 @@
HandleSigtermSignal(siginfo);
break;
default:
- PLOG(ERROR) << "signal_fd: received unexpected signal " << siginfo.ssi_signo;
+ LOG(ERROR) << "signal_fd: received unexpected signal " << siginfo.ssi_signo;
break;
}
}
diff --git a/init/interprocess_fifo.cpp b/init/interprocess_fifo.cpp
new file mode 100644
index 0000000..6e0d031
--- /dev/null
+++ b/init/interprocess_fifo.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "interprocess_fifo.h"
+
+#include <android-base/logging.h>
+
+#include <unistd.h>
+
+using ::android::base::ErrnoError;
+using ::android::base::Error;
+using ::android::base::Result;
+
+namespace android {
+namespace init {
+
+InterprocessFifo::InterprocessFifo() noexcept : fds_({-1, -1}) {}
+
+InterprocessFifo::InterprocessFifo(InterprocessFifo&& orig) noexcept : fds_({-1, -1}) {
+ std::swap(fds_, orig.fds_);
+}
+
+InterprocessFifo::~InterprocessFifo() noexcept {
+ Close();
+}
+
+void InterprocessFifo::CloseFd(int& fd) noexcept {
+ if (fd >= 0) {
+ close(fd);
+ fd = -1;
+ }
+}
+
+void InterprocessFifo::CloseReadFd() noexcept {
+ CloseFd(fds_[0]);
+}
+
+void InterprocessFifo::CloseWriteFd() noexcept {
+ CloseFd(fds_[1]);
+}
+
+void InterprocessFifo::Close() noexcept {
+ CloseReadFd();
+ CloseWriteFd();
+}
+
+Result<void> InterprocessFifo::Initialize() noexcept {
+ if (fds_[0] >= 0) {
+ return Error() << "already initialized";
+ }
+ if (pipe(fds_.data()) < 0) { // NOLINT(android-cloexec-pipe)
+ return ErrnoError() << "pipe()";
+ }
+ return {};
+}
+
+Result<uint8_t> InterprocessFifo::Read() noexcept {
+ uint8_t byte;
+ ssize_t count = read(fds_[0], &byte, 1);
+ if (count < 0) {
+ return ErrnoError() << "read()";
+ }
+ if (count == 0) {
+ return Error() << "read() EOF";
+ }
+ DCHECK_EQ(count, 1);
+ return byte;
+}
+
+Result<void> InterprocessFifo::Write(uint8_t byte) noexcept {
+ ssize_t written = write(fds_[1], &byte, 1);
+ if (written < 0) {
+ return ErrnoError() << "write()";
+ }
+ if (written == 0) {
+ return Error() << "write() EOF";
+ }
+ DCHECK_EQ(written, 1);
+ return {};
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/interprocess_fifo.h b/init/interprocess_fifo.h
new file mode 100644
index 0000000..cdaac86
--- /dev/null
+++ b/init/interprocess_fifo.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <array>
+
+#include <android-base/result.h>
+
+namespace android {
+namespace init {
+
+// A FIFO for inter-process communication that uses a Unix pipe internally.
+class InterprocessFifo {
+ public:
+ template <typename T>
+ using Result = ::android::base::Result<T>;
+
+ InterprocessFifo() noexcept;
+ InterprocessFifo(const InterprocessFifo& orig) noexcept = delete;
+ InterprocessFifo(InterprocessFifo&& orig) noexcept;
+ InterprocessFifo& operator=(const InterprocessFifo& orig) noexcept = delete;
+ InterprocessFifo& operator=(InterprocessFifo&& orig) noexcept = delete;
+ ~InterprocessFifo() noexcept;
+ void CloseReadFd() noexcept;
+ void CloseWriteFd() noexcept;
+ void Close() noexcept;
+ Result<void> Initialize() noexcept;
+ Result<void> Write(uint8_t byte) noexcept;
+ Result<uint8_t> Read() noexcept;
+
+ private:
+ static void CloseFd(int& fd) noexcept;
+
+ std::array<int, 2> fds_;
+};
+
+} // namespace init
+} // namespace android
diff --git a/init/interprocess_fifo_test.cpp b/init/interprocess_fifo_test.cpp
new file mode 100644
index 0000000..81cfbac
--- /dev/null
+++ b/init/interprocess_fifo_test.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "interprocess_fifo.h"
+
+#include <android-base/result-gmock.h>
+#include <gtest/gtest.h>
+
+#define ASSERT_OK(e) ASSERT_THAT(e, Ok())
+#define ASSERT_NOT_OK(e) ASSERT_THAT(e, Not(Ok()))
+
+using ::android::base::Result;
+using ::android::base::testing::Ok;
+using ::testing::Not;
+
+namespace android {
+namespace init {
+
+TEST(FifoTest, WriteAndRead) {
+ InterprocessFifo fifo;
+ ASSERT_OK(fifo.Initialize());
+ ASSERT_OK(fifo.Write('a'));
+ ASSERT_OK(fifo.Write('b'));
+ Result<uint8_t> result = fifo.Read();
+ ASSERT_OK(result);
+ EXPECT_EQ(*result, 'a');
+ result = fifo.Read();
+ ASSERT_OK(result);
+ EXPECT_EQ(*result, 'b');
+ InterprocessFifo fifo2 = std::move(fifo);
+ ASSERT_NOT_OK(fifo.Write('c'));
+ ASSERT_NOT_OK(fifo.Read());
+ ASSERT_OK(fifo2.Write('d'));
+ result = fifo2.Read();
+ ASSERT_OK(result);
+ EXPECT_EQ(*result, 'd');
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/security.cpp b/init/security.cpp
index 0e9f6c2..2ecf687 100644
--- a/init/security.cpp
+++ b/init/security.cpp
@@ -116,6 +116,13 @@
if (SetMmapRndBitsMin(33, 24, false) && (!Has32BitAbi() || SetMmapRndBitsMin(16, 16, true))) {
return {};
}
+#elif defined(__riscv)
+ // TODO: sv48 and sv57 were both added to the kernel this year, so we
+ // probably just need some kernel fixes to enable higher ASLR randomization,
+ // but for now 24 is the maximum that the kernel supports.
+ if (SetMmapRndBitsMin(24, 18, false)) {
+ return {};
+ }
#elif defined(__x86_64__)
// x86_64 supports 28 - 32 rnd bits, but Android wants to ensure that the
// theoretical maximum of 32 bits is always supported and used.
diff --git a/init/service.cpp b/init/service.cpp
index 6a9343d..caa9095 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -38,6 +38,7 @@
#include <string>
+#include "interprocess_fifo.h"
#include "lmkd_service.h"
#include "service_list.h"
#include "util.h"
@@ -442,14 +443,6 @@
return {};
}
-static void ClosePipe(const std::array<int, 2>* pipe) {
- for (const auto fd : *pipe) {
- if (fd >= 0) {
- close(fd);
- }
- }
-}
-
Result<void> Service::CheckConsole() {
if (!(flags_ & SVC_CONSOLE)) {
return {};
@@ -514,7 +507,7 @@
// Enters namespaces, sets environment variables, writes PID files and runs the service executable.
void Service::RunService(const std::vector<Descriptor>& descriptors,
- std::unique_ptr<std::array<int, 2>, decltype(&ClosePipe)> pipefd) {
+ InterprocessFifo cgroups_activated, InterprocessFifo setsid_finished) {
if (auto result = EnterNamespaces(namespaces_, name_, mount_namespace_); !result.ok()) {
LOG(FATAL) << "Service '" << name_ << "' failed to set up namespaces: " << result.error();
}
@@ -536,12 +529,12 @@
// Wait until the cgroups have been created and until the cgroup controllers have been
// activated.
- char byte = 0;
- if (read((*pipefd)[0], &byte, 1) < 0) {
- PLOG(ERROR) << "failed to read from notification channel";
+ Result<uint8_t> byte = cgroups_activated.Read();
+ if (!byte.ok()) {
+ LOG(ERROR) << name_ << ": failed to read from notification channel: " << byte.error();
}
- pipefd.reset();
- if (!byte) {
+ cgroups_activated.Close();
+ if (!*byte) {
LOG(FATAL) << "Service '" << name_ << "' failed to start due to a fatal error";
_exit(EXIT_FAILURE);
}
@@ -564,6 +557,12 @@
// priority. Aborts on failure.
SetProcessAttributesAndCaps();
+ // If SetProcessAttributes() called setsid(), report this to the parent.
+ if (!proc_attr_.console.empty()) {
+ setsid_finished.Write(2);
+ }
+ setsid_finished.Close();
+
if (!ExpandArgsAndExecv(args_, sigstop_)) {
PLOG(ERROR) << "cannot execv('" << args_[0]
<< "'). See the 'Debugging init' section of init's README.md for tips";
@@ -605,16 +604,23 @@
return {};
}
- std::unique_ptr<std::array<int, 2>, decltype(&ClosePipe)> pipefd(new std::array<int, 2>{-1, -1},
- ClosePipe);
- if (pipe(pipefd->data()) < 0) {
- return ErrnoError() << "pipe()";
+ InterprocessFifo cgroups_activated, setsid_finished;
+
+ if (Result<void> result = cgroups_activated.Initialize(); !result.ok()) {
+ return result;
}
if (Result<void> result = CheckConsole(); !result.ok()) {
return result;
}
+ // Only check proc_attr_.console after the CheckConsole() call.
+ if (!proc_attr_.console.empty()) {
+ if (Result<void> result = setsid_finished.Initialize(); !result.ok()) {
+ return result;
+ }
+ }
+
struct stat sb;
if (stat(args_[0].c_str(), &sb) == -1) {
flags_ |= SVC_DISABLED;
@@ -667,8 +673,13 @@
if (pid == 0) {
umask(077);
- RunService(descriptors, std::move(pipefd));
+ cgroups_activated.CloseWriteFd();
+ setsid_finished.CloseReadFd();
+ RunService(descriptors, std::move(cgroups_activated), std::move(setsid_finished));
_exit(127);
+ } else {
+ cgroups_activated.CloseReadFd();
+ setsid_finished.CloseWriteFd();
}
if (pid < 0) {
@@ -697,8 +708,9 @@
limit_percent_ != -1 || !limit_property_.empty();
errno = -createProcessGroup(proc_attr_.uid, pid_, use_memcg);
if (errno != 0) {
- if (char byte = 0; write((*pipefd)[1], &byte, 1) < 0) {
- return ErrnoError() << "sending notification failed";
+ Result<void> result = cgroups_activated.Write(0);
+ if (!result.ok()) {
+ return Error() << "Sending notification failed: " << result.error();
}
return Error() << "createProcessGroup(" << proc_attr_.uid << ", " << pid_
<< ") failed for service '" << name_ << "'";
@@ -720,8 +732,25 @@
LmkdRegister(name_, proc_attr_.uid, pid_, oom_score_adjust_);
}
- if (char byte = 1; write((*pipefd)[1], &byte, 1) < 0) {
- return ErrnoError() << "sending notification failed";
+ if (Result<void> result = cgroups_activated.Write(1); !result.ok()) {
+ return Error() << "Sending cgroups activated notification failed: " << result.error();
+ }
+
+ // Call setpgid() from the parent process to make sure that this call has
+ // finished before the parent process calls kill(-pgid, ...).
+ if (proc_attr_.console.empty()) {
+ if (setpgid(pid, pid) == -1) {
+ return ErrnoError() << "setpgid failed";
+ }
+ } else {
+ // The Read() call below will return an error if the child is killed.
+ if (Result<uint8_t> result = setsid_finished.Read(); !result.ok() || *result != 2) {
+ if (!result.ok()) {
+ return Error() << "Waiting for setsid() failed: " << result.error();
+ } else {
+ return Error() << "Waiting for setsid() failed: " << *result << " <> 2";
+ }
+ }
}
NotifyStateChange("running");
diff --git a/init/service.h b/init/service.h
index ab19865..10a0790 100644
--- a/init/service.h
+++ b/init/service.h
@@ -31,6 +31,7 @@
#include "action.h"
#include "capabilities.h"
+#include "interprocess_fifo.h"
#include "keyword_map.h"
#include "mount_namespace.h"
#include "parser.h"
@@ -154,9 +155,8 @@
void ResetFlagsForStart();
Result<void> CheckConsole();
void ConfigureMemcg();
- void RunService(
- const std::vector<Descriptor>& descriptors,
- std::unique_ptr<std::array<int, 2>, void (*)(const std::array<int, 2>* pipe)> pipefd);
+ void RunService(const std::vector<Descriptor>& descriptors, InterprocessFifo cgroups_activated,
+ InterprocessFifo setsid_finished);
void SetMountNamespace();
static unsigned long next_start_order_;
static bool is_exec_service_running_;
diff --git a/init/service_utils.cpp b/init/service_utils.cpp
index a14969e..56a80b5 100644
--- a/init/service_utils.cpp
+++ b/init/service_utils.cpp
@@ -244,7 +244,11 @@
setsid();
OpenConsole(attr.console);
} else {
- if (setpgid(0, getpid()) == -1) {
+ // Without PID namespaces, this call duplicates the setpgid() call from
+ // the parent process. With PID namespaces, this setpgid() call sets the
+ // process group ID for a child of the init process in the PID
+ // namespace.
+ if (setpgid(0, 0) == -1) {
return ErrnoError() << "setpgid failed";
}
SetupStdio(attr.stdio_to_kmsg);
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index 6fc64df..f8c501f 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -24,6 +24,7 @@
#include <unistd.h>
#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
@@ -36,6 +37,7 @@
using android::base::boot_clock;
using android::base::make_scope_guard;
+using android::base::ReadFileToString;
using android::base::StringPrintf;
using android::base::Timer;
@@ -51,8 +53,13 @@
return 0;
}
- auto pid = siginfo.si_pid;
- if (pid == 0) return 0;
+ const pid_t pid = siginfo.si_pid;
+ if (pid == 0) {
+ DCHECK_EQ(siginfo.si_signo, 0);
+ return 0;
+ }
+
+ DCHECK_EQ(siginfo.si_signo, SIGCHLD);
// At this point we know we have a zombie pid, so we use this scopeguard to reap the pid
// whenever the function returns from this point forward.
@@ -132,6 +139,11 @@
}
LOG(INFO) << "Waiting for " << pids.size() << " pids to be reaped took " << t << " with "
<< alive_pids.size() << " of them still running";
+ for (pid_t pid : pids) {
+ std::string status = "(no-such-pid)";
+ ReadFileToString(StringPrintf("/proc/%d/status", pid), &status);
+ LOG(INFO) << "Still running: " << pid << ' ' << status;
+ }
}
} // namespace init
diff --git a/init/subcontext.h b/init/subcontext.h
index 8acc032..93ebace 100644
--- a/init/subcontext.h
+++ b/init/subcontext.h
@@ -36,8 +36,10 @@
class Subcontext {
public:
- Subcontext(std::vector<std::string> path_prefixes, std::string context, bool host = false)
- : path_prefixes_(std::move(path_prefixes)), context_(std::move(context)), pid_(0) {
+ Subcontext(std::vector<std::string> path_prefixes, std::string_view context, bool host = false)
+ : path_prefixes_(std::move(path_prefixes)),
+ context_(context.begin(), context.end()),
+ pid_(0) {
if (!host) {
Fork();
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index ec760d3..123148e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -952,9 +952,10 @@
mkdir /data_mirror/data_de/null 0700 root root
# Bind mount CE and DE data directory to mirror's default volume directory.
- # The 'slave' option (MS_SLAVE) is needed to cause the later bind mount of
- # /data/data onto /data/user/0 to propagate to /data_mirror/data_ce/null/0.
- mount none /data/user /data_mirror/data_ce/null bind rec slave
+ # Note that because the /data mount has the "shared" propagation type, the
+ # later bind mount of /data/data onto /data/user/0 will automatically
+ # propagate to /data_mirror/data_ce/null/0 as well.
+ mount none /data/user /data_mirror/data_ce/null bind rec
mount none /data/user_de /data_mirror/data_de/null bind rec
# Create mirror directory for jit profiles
@@ -1037,6 +1038,9 @@
# Enable FUSE by default
setprop persist.sys.fuse true
+ # Update dm-verity state and set partition.*.verified properties.
+ verity_update_state
+
# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
on zygote-start && property:ro.crypto.state=unencrypted
@@ -1175,9 +1179,6 @@
# Define default initial receive window size in segments.
setprop net.tcp_def_init_rwnd 60
- # Update dm-verity state and set partition.*.verified properties.
- verity_update_state
-
# Start standard binderized HAL daemons
class_start hal
diff --git a/trusty/confirmationui/service.cpp b/trusty/confirmationui/service.cpp
index b286c0a..44fa3a6 100644
--- a/trusty/confirmationui/service.cpp
+++ b/trusty/confirmationui/service.cpp
@@ -31,12 +31,8 @@
const auto instance = std::string(IConfirmationUI::descriptor) + "/default";
binder_status_t status =
AServiceManager_addService(confirmationui->asBinder().get(), instance.c_str());
-
- if (status != STATUS_OK) {
- LOG(FATAL) << "Could not register service for " << instance.c_str() << "(" << status << ")";
- return -1;
- }
+ CHECK_EQ(status, STATUS_OK) << "Could not register " << instance;
ABinderProcess_joinThreadPool();
- return -1;
+ return EXIT_FAILURE;
}