Merge changes I5d17fc87,If1cc6b9a
* changes:
Cgroup APIs are guarded
Remove __ANDROID_API__ guards
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 7938a61..45e555f 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -16,6 +16,7 @@
#include <err.h>
#include <fcntl.h>
+#include <malloc.h>
#include <stdlib.h>
#include <sys/capability.h>
#include <sys/mman.h>
@@ -32,7 +33,6 @@
#include <android/fdsan.h>
#include <android/set_abort_message.h>
-#include <bionic/malloc.h>
#include <bionic/mte.h>
#include <bionic/reserved_signals.h>
@@ -385,8 +385,7 @@
#if defined(__aarch64__)
static void SetTagCheckingLevelSync() {
- HeapTaggingLevel heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC;
- if (!android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &heap_tagging_level, sizeof(heap_tagging_level))) {
+ if (mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_SYNC) == 0) {
abort();
}
}
diff --git a/fastboot/fastboot.bash b/fastboot/fastboot.bash
index 406e8b8..f5a3384 100644
--- a/fastboot/fastboot.bash
+++ b/fastboot/fastboot.bash
@@ -109,7 +109,7 @@
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ $i -eq $COMP_CWORD ]]; then
- partitions="boot bootloader dtbo modem odm odm_dlkm oem product radio recovery system vbmeta vendor vendor_dlkm"
+ partitions="boot bootloader dtbo modem odm odm_dlkm oem product pvmfw radio recovery system vbmeta vendor vendor_dlkm"
COMPREPLY=( $(compgen -W "$partitions" -- $cur) )
else
_fastboot_util_complete_local_file "${cur}" '!*.img'
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 62f6ac7..f7edf8e 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -147,6 +147,7 @@
{ "odm", "odm.img", "odm.sig", "odm", true, ImageType::Normal },
{ "odm_dlkm", "odm_dlkm.img", "odm_dlkm.sig", "odm_dlkm", true, ImageType::Normal },
{ "product", "product.img", "product.sig", "product", true, ImageType::Normal },
+ { "pvmfw", "pvmfw.img", "pvmfw.sig", "pvmfw", true, ImageType::BootCritical },
{ "recovery", "recovery.img", "recovery.sig", "recovery", true, ImageType::BootCritical },
{ "super", "super.img", "super.sig", "super", true, ImageType::Extra },
{ "system", "system.img", "system.sig", "system", false, ImageType::Normal },
diff --git a/fs_mgr/libsnapshot/cow_api_test.cpp b/fs_mgr/libsnapshot/cow_api_test.cpp
index defe8d4..a96352a 100644
--- a/fs_mgr/libsnapshot/cow_api_test.cpp
+++ b/fs_mgr/libsnapshot/cow_api_test.cpp
@@ -60,6 +60,7 @@
TEST_F(CowTest, ReadWrite) {
CowOptions options;
+ options.cluster_ops = 0;
CowWriter writer(options);
ASSERT_TRUE(writer.Initialize(cow_->fd));
@@ -137,6 +138,7 @@
TEST_F(CowTest, CompressGz) {
CowOptions options;
+ options.cluster_ops = 0;
options.compression = "gz";
CowWriter writer(options);
@@ -238,6 +240,7 @@
TEST_F(CowTest, CompressTwoBlocks) {
CowOptions options;
options.compression = "gz";
+ options.cluster_ops = 0;
CowWriter writer(options);
ASSERT_TRUE(writer.Initialize(cow_->fd));
@@ -280,6 +283,7 @@
TEST_P(CompressionTest, HorribleSink) {
CowOptions options;
options.compression = GetParam();
+ options.cluster_ops = 0;
CowWriter writer(options);
ASSERT_TRUE(writer.Initialize(cow_->fd));
@@ -309,6 +313,7 @@
TEST_F(CowTest, GetSize) {
CowOptions options;
+ options.cluster_ops = 0;
CowWriter writer(options);
if (ftruncate(cow_->fd, 0) < 0) {
perror("Fails to set temp file size");
@@ -334,6 +339,7 @@
TEST_F(CowTest, AppendLabelSmall) {
CowOptions options;
+ options.cluster_ops = 0;
auto writer = std::make_unique<CowWriter>(options);
ASSERT_TRUE(writer->Initialize(cow_->fd));
@@ -399,6 +405,7 @@
TEST_F(CowTest, AppendLabelMissing) {
CowOptions options;
+ options.cluster_ops = 0;
auto writer = std::make_unique<CowWriter>(options);
ASSERT_TRUE(writer->Initialize(cow_->fd));
@@ -452,6 +459,7 @@
TEST_F(CowTest, AppendExtendedCorrupted) {
CowOptions options;
+ options.cluster_ops = 0;
auto writer = std::make_unique<CowWriter>(options);
ASSERT_TRUE(writer->Initialize(cow_->fd));
@@ -504,6 +512,7 @@
TEST_F(CowTest, AppendbyLabel) {
CowOptions options;
+ options.cluster_ops = 0;
auto writer = std::make_unique<CowWriter>(options);
ASSERT_TRUE(writer->Initialize(cow_->fd));
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index fd43cce..22ddfa6 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -35,7 +35,7 @@
std::optional<uint64_t> max_blocks;
// Number of CowOperations in a cluster. 0 for no clustering. Cannot be 1.
- uint32_t cluster_ops = 0;
+ uint32_t cluster_ops = 200;
};
// Interface for writing to a snapuserd COW. All operations are ordered; merges
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index f8d3cdc..397ff2e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -306,13 +306,17 @@
// Helper function for second stage init to restorecon on the rollback indicator.
static std::string GetGlobalRollbackIndicatorPath();
- // Initiate the transition from first-stage to second-stage snapuserd. This
- // process involves re-creating the dm-user table entries for each device,
- // so that they connect to the new daemon. Once all new tables have been
- // activated, we ask the first-stage daemon to cleanly exit.
- //
- // The caller must pass a function which starts snapuserd.
- bool PerformSecondStageTransition();
+ // Detach dm-user devices from the current snapuserd, and populate
+ // |snapuserd_argv| with the necessary arguments to restart snapuserd
+ // and reattach them.
+ bool DetachSnapuserdForSelinux(std::vector<std::string>* snapuserd_argv);
+
+ // Perform the transition from the selinux stage of snapuserd into the
+ // second-stage of snapuserd. This process involves re-creating the dm-user
+ // table entries for each device, so that they connect to the new daemon.
+ // Once all new tables have been activated, we ask the first-stage daemon
+ // to cleanly exit.
+ bool PerformSecondStageInitTransition();
// ISnapshotManager overrides.
bool BeginUpdate() override;
@@ -626,6 +630,9 @@
// The reverse of MapPartitionWithSnapshot.
bool UnmapPartitionWithSnapshot(LockedFile* lock, const std::string& target_partition_name);
+ // Unmap a dm-user device through snapuserd.
+ bool UnmapDmUserDevice(const std::string& snapshot_name);
+
// If there isn't a previous update, return true. |needs_merge| is set to false.
// If there is a previous update but the device has not boot into it, tries to cancel the
// update and delete any snapshots. Return true if successful. |needs_merge| is set to false.
@@ -693,6 +700,19 @@
// returns true.
bool WaitForDevice(const std::string& device, std::chrono::milliseconds timeout_ms);
+ enum class InitTransition { SELINUX_DETACH, SECOND_STAGE };
+
+ // Initiate the transition from first-stage to second-stage snapuserd. This
+ // process involves re-creating the dm-user table entries for each device,
+ // so that they connect to the new daemon. Once all new tables have been
+ // activated, we ask the first-stage daemon to cleanly exit.
+ //
+ // If the mode is SELINUX_DETACH, snapuserd_argv must be non-null and will
+ // be populated with a list of snapuserd arguments to pass to execve(). It
+ // is otherwise ignored.
+ bool PerformInitTransition(InitTransition transition,
+ std::vector<std::string>* snapuserd_argv = nullptr);
+
std::string gsid_dir_;
std::string metadata_dir_;
std::unique_ptr<IDeviceInfo> device_;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
index aa9ba6e..1dab361 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
@@ -32,8 +32,6 @@
static constexpr char kSnapuserdSocket[] = "snapuserd";
-static constexpr char kSnapuserdFirstStagePidVar[] = "FIRST_STAGE_SNAPUSERD_PID";
-
// Ensure that the second-stage daemon for snapuserd is running.
bool EnsureSnapuserdStarted();
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 04c3ccc..f0646fc 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -1247,6 +1247,10 @@
return false;
}
+ if (status.compression_enabled()) {
+ UnmapDmUserDevice(name);
+ }
+
// Cleanup the base device as well, since it is no longer used. This does
// not block cleanup.
auto base_name = GetBaseDeviceName(name);
@@ -1291,12 +1295,13 @@
return RemoveAllUpdateState(lock, before_cancel);
}
-bool SnapshotManager::PerformSecondStageTransition() {
- LOG(INFO) << "Performing second-stage transition for snapuserd.";
+bool SnapshotManager::PerformInitTransition(InitTransition transition,
+ std::vector<std::string>* snapuserd_argv) {
+ LOG(INFO) << "Performing transition for snapuserd.";
// Don't use EnsuerSnapuserdConnected() because this is called from init,
// and attempting to do so will deadlock.
- if (!snapuserd_client_) {
+ if (!snapuserd_client_ && transition != InitTransition::SELINUX_DETACH) {
snapuserd_client_ = SnapuserdClient::Connect(kSnapuserdSocket, 10s);
if (!snapuserd_client_) {
LOG(ERROR) << "Unable to connect to snapuserd";
@@ -1343,6 +1348,9 @@
}
auto misc_name = user_cow_name;
+ if (transition == InitTransition::SELINUX_DETACH) {
+ misc_name += "-selinux";
+ }
DmTable table;
table.Emplace<DmTargetUser>(0, target.spec.length, misc_name);
@@ -1378,6 +1386,17 @@
continue;
}
+ if (transition == InitTransition::SELINUX_DETACH) {
+ auto message = misc_name + "," + cow_image_device + "," + backing_device;
+ snapuserd_argv->emplace_back(std::move(message));
+
+ // Do not attempt to connect to the new snapuserd yet, it hasn't
+ // been started. We do however want to wait for the misc device
+ // to have been created.
+ ok_cows++;
+ continue;
+ }
+
uint64_t base_sectors =
snapuserd_client_->InitDmUserCow(misc_name, cow_image_device, backing_device);
if (base_sectors == 0) {
@@ -2048,27 +2067,8 @@
auto& dm = DeviceMapper::Instance();
- auto dm_user_name = GetDmUserCowName(name);
- if (IsCompressionEnabled() && dm.GetState(dm_user_name) != DmDeviceState::INVALID) {
- if (!EnsureSnapuserdConnected()) {
- return false;
- }
- if (!dm.DeleteDeviceIfExists(dm_user_name)) {
- LOG(ERROR) << "Cannot unmap " << dm_user_name;
- return false;
- }
-
- if (!snapuserd_client_->WaitForDeviceDelete(dm_user_name)) {
- LOG(ERROR) << "Failed to wait for " << dm_user_name << " control device to delete";
- return false;
- }
-
- // Ensure the control device is gone so we don't run into ABA problems.
- auto control_device = "/dev/dm-user/" + dm_user_name;
- if (!android::fs_mgr::WaitForFileDeleted(control_device, 10s)) {
- LOG(ERROR) << "Timed out waiting for " << control_device << " to unlink";
- return false;
- }
+ if (IsCompressionEnabled() && !UnmapDmUserDevice(name)) {
+ return false;
}
auto cow_name = GetCowName(name);
@@ -2085,6 +2085,37 @@
return true;
}
+bool SnapshotManager::UnmapDmUserDevice(const std::string& snapshot_name) {
+ auto& dm = DeviceMapper::Instance();
+
+ if (!EnsureSnapuserdConnected()) {
+ return false;
+ }
+
+ auto dm_user_name = GetDmUserCowName(snapshot_name);
+ if (dm.GetState(dm_user_name) == DmDeviceState::INVALID) {
+ return true;
+ }
+
+ if (!dm.DeleteDeviceIfExists(dm_user_name)) {
+ LOG(ERROR) << "Cannot unmap " << dm_user_name;
+ return false;
+ }
+
+ if (!snapuserd_client_->WaitForDeviceDelete(dm_user_name)) {
+ LOG(ERROR) << "Failed to wait for " << dm_user_name << " control device to delete";
+ return false;
+ }
+
+ // Ensure the control device is gone so we don't run into ABA problems.
+ auto control_device = "/dev/dm-user/" + dm_user_name;
+ if (!android::fs_mgr::WaitForFileDeleted(control_device, 10s)) {
+ LOG(ERROR) << "Timed out waiting for " << control_device << " to unlink";
+ return false;
+ }
+ return true;
+}
+
bool SnapshotManager::MapAllSnapshots(const std::chrono::milliseconds& timeout_ms) {
auto lock = LockExclusive();
if (!lock) return false;
@@ -3311,5 +3342,13 @@
return status.state() != UpdateState::None && status.compression_enabled();
}
+bool SnapshotManager::DetachSnapuserdForSelinux(std::vector<std::string>* snapuserd_argv) {
+ return PerformInitTransition(InitTransition::SELINUX_DETACH, snapuserd_argv);
+}
+
+bool SnapshotManager::PerformSecondStageInitTransition() {
+ return PerformInitTransition(InitTransition::SECOND_STAGE);
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index c6a1786..bb44425 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -146,6 +146,7 @@
"base-device",
"test_partition_b",
"test_partition_b-base",
+ "test_partition_b-base",
};
for (const auto& partition : partitions) {
DeleteDevice(partition);
@@ -180,12 +181,22 @@
}
// If |path| is non-null, the partition will be mapped after creation.
- bool CreatePartition(const std::string& name, uint64_t size, std::string* path = nullptr) {
+ bool CreatePartition(const std::string& name, uint64_t size, std::string* path = nullptr,
+ const std::optional<std::string> group = {}) {
TestPartitionOpener opener(fake_super);
auto builder = MetadataBuilder::New(opener, "super", 0);
if (!builder) return false;
- auto partition = builder->AddPartition(name, 0);
+ std::string partition_group = std::string(android::fs_mgr::kDefaultGroup);
+ if (group) {
+ partition_group = *group;
+ }
+ return CreatePartition(builder.get(), name, size, path, partition_group);
+ }
+
+ bool CreatePartition(MetadataBuilder* builder, const std::string& name, uint64_t size,
+ std::string* path, const std::string& group) {
+ auto partition = builder->AddPartition(name, group, 0);
if (!partition) return false;
if (!builder->ResizePartition(partition, size)) {
return false;
@@ -194,6 +205,8 @@
// Update the source slot.
auto metadata = builder->Export();
if (!metadata) return false;
+
+ TestPartitionOpener opener(fake_super);
if (!UpdatePartitionTable(opener, "super", *metadata.get(), 0)) {
return false;
}
@@ -210,39 +223,54 @@
return CreateLogicalPartition(params, path);
}
- bool MapUpdatePartitions() {
+ AssertionResult MapUpdateSnapshot(const std::string& name,
+ std::unique_ptr<ICowWriter>* writer) {
TestPartitionOpener opener(fake_super);
- auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1);
- if (!builder) return false;
+ CreateLogicalPartitionParams params{
+ .block_device = fake_super,
+ .metadata_slot = 1,
+ .partition_name = name,
+ .timeout_ms = 10s,
+ .partition_opener = &opener,
+ };
- auto metadata = builder->Export();
- if (!metadata) return false;
-
- // Update the destination slot, mark it as updated.
- if (!UpdatePartitionTable(opener, "super", *metadata.get(), 1)) {
- return false;
+ auto result = sm->OpenSnapshotWriter(params, {});
+ if (!result) {
+ return AssertionFailure() << "Cannot open snapshot for writing: " << name;
+ }
+ if (!result->Initialize()) {
+ return AssertionFailure() << "Cannot initialize snapshot for writing: " << name;
}
- for (const auto& partition : metadata->partitions) {
- CreateLogicalPartitionParams params = {
- .block_device = fake_super,
- .metadata = metadata.get(),
- .partition = &partition,
- .force_writable = true,
- .timeout_ms = 10s,
- .device_name = GetPartitionName(partition) + "-base",
- };
- std::string ignore_path;
- if (!CreateLogicalPartition(params, &ignore_path)) {
- return false;
- }
+ if (writer) {
+ *writer = std::move(result);
}
- return true;
+ return AssertionSuccess();
+ }
+
+ AssertionResult MapUpdateSnapshot(const std::string& name, std::string* path) {
+ TestPartitionOpener opener(fake_super);
+ CreateLogicalPartitionParams params{
+ .block_device = fake_super,
+ .metadata_slot = 1,
+ .partition_name = name,
+ .timeout_ms = 10s,
+ .partition_opener = &opener,
+ };
+
+ auto result = sm->MapUpdateSnapshot(params, path);
+ if (!result) {
+ return AssertionFailure() << "Cannot open snapshot for writing: " << name;
+ }
+ return AssertionSuccess();
}
AssertionResult DeleteSnapshotDevice(const std::string& snapshot) {
AssertionResult res = AssertionSuccess();
if (!(res = DeleteDevice(snapshot))) return res;
+ if (!sm->UnmapDmUserDevice(snapshot)) {
+ return AssertionFailure() << "Cannot delete dm-user device for " << snapshot;
+ }
if (!(res = DeleteDevice(snapshot + "-inner"))) return res;
if (!(res = DeleteDevice(snapshot + "-cow"))) return res;
if (!image_manager_->UnmapImageIfExists(snapshot + "-cow-img")) {
@@ -289,37 +317,55 @@
// Prepare A/B slot for a partition named "test_partition".
AssertionResult PrepareOneSnapshot(uint64_t device_size,
- std::string* out_snap_device = nullptr) {
- std::string base_device, cow_device, snap_device;
- if (!CreatePartition("test_partition_a", device_size)) {
- return AssertionFailure();
+ std::unique_ptr<ICowWriter>* writer = nullptr) {
+ lock_ = nullptr;
+
+ DeltaArchiveManifest manifest;
+
+ auto group = manifest.mutable_dynamic_partition_metadata()->add_groups();
+ group->set_name("group");
+ group->set_size(device_size * 2);
+ group->add_partition_names("test_partition");
+
+ auto pu = manifest.add_partitions();
+ pu->set_partition_name("test_partition");
+ pu->set_estimate_cow_size(device_size);
+ SetSize(pu, device_size);
+
+ auto extent = pu->add_operations()->add_dst_extents();
+ extent->set_start_block(0);
+ if (device_size) {
+ extent->set_num_blocks(device_size / manifest.block_size());
}
- if (!MapUpdatePartitions()) {
- return AssertionFailure();
+
+ TestPartitionOpener opener(fake_super);
+ auto builder = MetadataBuilder::New(opener, "super", 0);
+ if (!builder) {
+ return AssertionFailure() << "Failed to open MetadataBuilder";
}
- if (!dm_.GetDmDevicePathByName("test_partition_b-base", &base_device)) {
- return AssertionFailure();
+ builder->AddGroup("group_a", 16_GiB);
+ builder->AddGroup("group_b", 16_GiB);
+ if (!CreatePartition(builder.get(), "test_partition_a", device_size, nullptr, "group_a")) {
+ return AssertionFailure() << "Failed create test_partition_a";
}
- SnapshotStatus status;
- status.set_name("test_partition_b");
- status.set_device_size(device_size);
- status.set_snapshot_size(device_size);
- status.set_cow_file_size(device_size);
- if (!sm->CreateSnapshot(lock_.get(), &status)) {
- return AssertionFailure();
+
+ if (!sm->CreateUpdateSnapshots(manifest)) {
+ return AssertionFailure() << "Failed to create update snapshots";
}
- if (!CreateCowImage("test_partition_b")) {
- return AssertionFailure();
+
+ if (writer) {
+ auto res = MapUpdateSnapshot("test_partition_b", writer);
+ if (!res) {
+ return res;
+ }
+ } else if (!IsCompressionEnabled()) {
+ std::string ignore;
+ if (!MapUpdateSnapshot("test_partition_b", &ignore)) {
+ return AssertionFailure() << "Failed to map test_partition_b";
+ }
}
- if (!MapCowImage("test_partition_b", 10s, &cow_device)) {
- return AssertionFailure();
- }
- if (!sm->MapSnapshot(lock_.get(), "test_partition_b", base_device, cow_device, 10s,
- &snap_device)) {
- return AssertionFailure();
- }
- if (out_snap_device) {
- *out_snap_device = std::move(snap_device);
+ if (!AcquireLock()) {
+ return AssertionFailure() << "Failed to acquire lock";
}
return AssertionSuccess();
}
@@ -328,20 +374,37 @@
AssertionResult SimulateReboot() {
lock_ = nullptr;
if (!sm->FinishedSnapshotWrites(false)) {
- return AssertionFailure();
+ return AssertionFailure() << "Failed to finish snapshot writes";
}
- if (!dm_.DeleteDevice("test_partition_b")) {
- return AssertionFailure();
+ if (!sm->UnmapUpdateSnapshot("test_partition_b")) {
+ return AssertionFailure() << "Failed to unmap COW for test_partition_b";
}
- if (!DestroyLogicalPartition("test_partition_b-base")) {
- return AssertionFailure();
+ if (!dm_.DeleteDeviceIfExists("test_partition_b")) {
+ return AssertionFailure() << "Failed to delete test_partition_b";
}
- if (!sm->UnmapCowImage("test_partition_b")) {
- return AssertionFailure();
+ if (!dm_.DeleteDeviceIfExists("test_partition_b-base")) {
+ return AssertionFailure() << "Failed to destroy test_partition_b-base";
}
return AssertionSuccess();
}
+ std::unique_ptr<SnapshotManager> NewManagerForFirstStageMount(
+ const std::string& slot_suffix = "_a") {
+ auto info = new TestDeviceInfo(fake_super, slot_suffix);
+ return NewManagerForFirstStageMount(info);
+ }
+
+ std::unique_ptr<SnapshotManager> NewManagerForFirstStageMount(TestDeviceInfo* info) {
+ auto init = SnapshotManager::NewForFirstStageMount(info);
+ if (!init) {
+ return nullptr;
+ }
+ init->SetUeventRegenCallback([](const std::string& device) -> bool {
+ return android::fs_mgr::WaitForFile(device, snapshot_timeout_);
+ });
+ return init;
+ }
+
static constexpr std::chrono::milliseconds snapshot_timeout_ = 5s;
DeviceMapper& dm_;
std::unique_ptr<SnapshotManager::LockedFile> lock_;
@@ -439,8 +502,7 @@
TEST_F(SnapshotTest, CleanFirstStageMount) {
// If there's no update in progress, there should be no first-stage mount
// needed.
- TestDeviceInfo* info = new TestDeviceInfo(fake_super);
- auto sm = SnapshotManager::NewForFirstStageMount(info);
+ auto sm = NewManagerForFirstStageMount();
ASSERT_NE(sm, nullptr);
ASSERT_FALSE(sm->NeedSnapshotsInFirstStageMount());
}
@@ -449,8 +511,7 @@
ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
// We didn't change the slot, so we shouldn't need snapshots.
- TestDeviceInfo* info = new TestDeviceInfo(fake_super);
- auto sm = SnapshotManager::NewForFirstStageMount(info);
+ auto sm = NewManagerForFirstStageMount();
ASSERT_NE(sm, nullptr);
ASSERT_FALSE(sm->NeedSnapshotsInFirstStageMount());
@@ -462,32 +523,30 @@
ASSERT_TRUE(AcquireLock());
static const uint64_t kDeviceSize = 1024 * 1024;
- std::string snap_device;
- ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize, &snap_device));
- std::string test_string = "This is a test string.";
- {
- unique_fd fd(open(snap_device.c_str(), O_RDWR | O_CLOEXEC | O_SYNC));
- ASSERT_GE(fd, 0);
- ASSERT_TRUE(android::base::WriteFully(fd, test_string.data(), test_string.size()));
- }
-
- // Note: we know there is no inner/outer dm device since we didn't request
- // a linear segment.
- DeviceMapper::TargetInfo target;
- ASSERT_TRUE(sm->IsSnapshotDevice("test_partition_b", &target));
- ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
+ std::unique_ptr<ICowWriter> writer;
+ ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize, &writer));
// Release the lock.
lock_ = nullptr;
+ std::string test_string = "This is a test string.";
+ test_string.resize(writer->options().block_size);
+ ASSERT_TRUE(writer->AddRawBlocks(0, test_string.data(), test_string.size()));
+ ASSERT_TRUE(writer->Finalize());
+ writer = nullptr;
+
// Done updating.
ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
+ ASSERT_TRUE(sm->UnmapUpdateSnapshot("test_partition_b"));
+
test_device->set_slot_suffix("_b");
+ ASSERT_TRUE(sm->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
ASSERT_TRUE(sm->InitiateMerge());
// The device should have been switched to a snapshot-merge target.
+ DeviceMapper::TargetInfo target;
ASSERT_TRUE(sm->IsSnapshotDevice("test_partition_b", &target));
ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot-merge");
@@ -503,7 +562,7 @@
// Test that we can read back the string we wrote to the snapshot. Note
// that the base device is gone now. |snap_device| contains the correct
// partition.
- unique_fd fd(open(snap_device.c_str(), O_RDONLY | O_CLOEXEC));
+ unique_fd fd(open("/dev/block/mapper/test_partition_b", O_RDONLY | O_CLOEXEC));
ASSERT_GE(fd, 0);
std::string buffer(test_string.size(), '\0');
@@ -518,7 +577,7 @@
ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize));
ASSERT_TRUE(SimulateReboot());
- auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
+ auto init = NewManagerForFirstStageMount("_b");
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
@@ -547,7 +606,7 @@
FormatFakeSuper();
ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize));
- auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
+ auto init = NewManagerForFirstStageMount("_b");
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
@@ -574,7 +633,7 @@
ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize));
ASSERT_TRUE(SimulateReboot());
- auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
+ auto init = NewManagerForFirstStageMount("_b");
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
@@ -899,47 +958,7 @@
return AssertionSuccess();
}
- AssertionResult MapUpdateSnapshot(const std::string& name,
- std::unique_ptr<ICowWriter>* writer) {
- CreateLogicalPartitionParams params{
- .block_device = fake_super,
- .metadata_slot = 1,
- .partition_name = name,
- .timeout_ms = 10s,
- .partition_opener = opener_.get(),
- };
-
- auto result = sm->OpenSnapshotWriter(params, {});
- if (!result) {
- return AssertionFailure() << "Cannot open snapshot for writing: " << name;
- }
- if (!result->Initialize()) {
- return AssertionFailure() << "Cannot initialize snapshot for writing: " << name;
- }
-
- if (writer) {
- *writer = std::move(result);
- }
- return AssertionSuccess();
- }
-
- AssertionResult MapUpdateSnapshot(const std::string& name, std::string* path) {
- CreateLogicalPartitionParams params{
- .block_device = fake_super,
- .metadata_slot = 1,
- .partition_name = name,
- .timeout_ms = 10s,
- .partition_opener = opener_.get(),
- };
-
- auto result = sm->MapUpdateSnapshot(params, path);
- if (!result) {
- return AssertionFailure() << "Cannot open snapshot for writing: " << name;
- }
- return AssertionSuccess();
- }
-
- AssertionResult MapUpdateSnapshot(const std::string& name) {
+ AssertionResult MapOneUpdateSnapshot(const std::string& name) {
if (IsCompressionEnabled()) {
std::unique_ptr<ICowWriter> writer;
return MapUpdateSnapshot(name, &writer);
@@ -983,7 +1002,7 @@
AssertionResult MapUpdateSnapshots(const std::vector<std::string>& names = {"sys_b", "vnd_b",
"prd_b"}) {
for (const auto& name : names) {
- auto res = MapUpdateSnapshot(name);
+ auto res = MapOneUpdateSnapshot(name);
if (!res) {
return res;
}
@@ -1070,7 +1089,7 @@
ASSERT_TRUE(UnmapAll());
// After reboot, init does first stage mount.
- auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
+ auto init = NewManagerForFirstStageMount("_b");
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
@@ -1202,7 +1221,7 @@
ASSERT_TRUE(UnmapAll());
// After reboot, init does first stage mount.
- auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
+ auto init = NewManagerForFirstStageMount("_b");
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
@@ -1214,7 +1233,7 @@
// Simulate shutting down the device again.
ASSERT_TRUE(UnmapAll());
- init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_a"));
+ init = NewManagerForFirstStageMount("_a");
ASSERT_NE(init, nullptr);
ASSERT_FALSE(init->NeedSnapshotsInFirstStageMount());
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
@@ -1251,7 +1270,7 @@
ASSERT_TRUE(UnmapAll());
// After reboot, init does first stage mount.
- auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
+ auto init = NewManagerForFirstStageMount("_b");
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
@@ -1387,8 +1406,8 @@
ASSERT_TRUE(UnmapAll());
// After reboot, init does first stage mount.
- // Normally we should use NewForFirstStageMount, but if so, "gsid.mapped_image.sys_b-cow-img"
- // won't be set.
+ // Normally we should use NewManagerForFirstStageMount, but if so,
+ // "gsid.mapped_image.sys_b-cow-img" won't be set.
auto init = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
@@ -1495,7 +1514,7 @@
ASSERT_TRUE(UnmapAll());
// After reboot, init does first stage mount.
- auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
+ auto init = NewManagerForFirstStageMount("_b");
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
@@ -1509,7 +1528,7 @@
// Simulate a reboot into recovery.
auto test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
test_device->set_recovery(true);
- new_sm = SnapshotManager::NewForFirstStageMount(test_device.release());
+ new_sm = NewManagerForFirstStageMount(test_device.release());
ASSERT_TRUE(new_sm->HandleImminentDataWipe());
ASSERT_EQ(new_sm->GetUpdateState(), UpdateState::None);
@@ -1527,7 +1546,7 @@
ASSERT_TRUE(UnmapAll());
// After reboot, init does first stage mount.
- auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
+ auto init = NewManagerForFirstStageMount("_b");
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
@@ -1541,7 +1560,7 @@
// Simulate a reboot into recovery.
auto test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
test_device->set_recovery(true);
- new_sm = SnapshotManager::NewForFirstStageMount(test_device.release());
+ new_sm = NewManagerForFirstStageMount(test_device.release());
ASSERT_TRUE(new_sm->FinishMergeInRecovery());
@@ -1551,12 +1570,12 @@
// Finish the merge in a normal boot.
test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
- init = SnapshotManager::NewForFirstStageMount(test_device.release());
+ init = NewManagerForFirstStageMount(test_device.release());
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
init = nullptr;
test_device = std::make_unique<TestDeviceInfo>(fake_super, "_b");
- new_sm = SnapshotManager::NewForFirstStageMount(test_device.release());
+ new_sm = NewManagerForFirstStageMount(test_device.release());
ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::MergeCompleted);
ASSERT_EQ(new_sm->ProcessUpdateState(), UpdateState::None);
}
@@ -1575,7 +1594,7 @@
// Simulate a reboot into recovery.
auto test_device = new TestDeviceInfo(fake_super, "_b");
test_device->set_recovery(true);
- auto new_sm = SnapshotManager::NewForFirstStageMount(test_device);
+ auto new_sm = NewManagerForFirstStageMount(test_device);
ASSERT_TRUE(new_sm->HandleImminentDataWipe());
// Manually mount metadata so that we can call GetUpdateState() below.
@@ -1600,7 +1619,7 @@
// Simulate a rollback, with reboot into recovery.
auto test_device = new TestDeviceInfo(fake_super, "_a");
test_device->set_recovery(true);
- auto new_sm = SnapshotManager::NewForFirstStageMount(test_device);
+ auto new_sm = NewManagerForFirstStageMount(test_device);
ASSERT_TRUE(new_sm->HandleImminentDataWipe());
EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::None);
@@ -1628,7 +1647,7 @@
// Simulate a reboot into recovery.
auto test_device = new TestDeviceInfo(fake_super, "_b");
test_device->set_recovery(true);
- auto new_sm = SnapshotManager::NewForFirstStageMount(test_device);
+ auto new_sm = NewManagerForFirstStageMount(test_device);
ASSERT_TRUE(new_sm->HandleImminentDataWipe());
// Manually mount metadata so that we can call GetUpdateState() below.
@@ -1639,7 +1658,7 @@
// Now reboot into new slot.
test_device = new TestDeviceInfo(fake_super, "_b");
- auto init = SnapshotManager::NewForFirstStageMount(test_device);
+ auto init = NewManagerForFirstStageMount(test_device);
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
// Verify that we are on the downgraded build.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
@@ -1685,7 +1704,7 @@
ASSERT_TRUE(UnmapAll());
// After reboot, init does first stage mount.
- auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
+ auto init = NewManagerForFirstStageMount("_b");
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
@@ -1773,7 +1792,7 @@
ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
ASSERT_TRUE(UnmapAll());
- auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
+ auto init = NewManagerForFirstStageMount("_b");
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->EnsureSnapuserdConnected());
@@ -1785,7 +1804,7 @@
ASSERT_EQ(access("/dev/dm-user/sys_b-user-cow-init", F_OK), 0);
ASSERT_EQ(access("/dev/dm-user/sys_b-user-cow", F_OK), -1);
- ASSERT_TRUE(init->PerformSecondStageTransition());
+ ASSERT_TRUE(init->PerformInitTransition(SnapshotManager::InitTransition::SECOND_STAGE));
// The control device should have been renamed.
ASSERT_TRUE(android::fs_mgr::WaitForFileDeleted("/dev/dm-user/sys_b-user-cow-init", 10s));
@@ -1887,8 +1906,7 @@
ASSERT_TRUE(UnmapAll());
// Simulate reboot. After reboot, init does first stage mount.
- auto init = SnapshotManager::NewForFirstStageMount(
- new TestDeviceInfo(fake_super, flashed_slot_suffix));
+ auto init = NewManagerForFirstStageMount(flashed_slot_suffix);
ASSERT_NE(init, nullptr);
if (flashed_slot && after_merge) {
diff --git a/fs_mgr/libsnapshot/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd_server.cpp
index 8351155..38abaec 100644
--- a/fs_mgr/libsnapshot/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_server.cpp
@@ -77,9 +77,8 @@
JoinAllThreads();
}
-const std::string& DmUserHandler::GetMiscName() const {
- return snapuserd_->GetMiscName();
-}
+DmUserHandler::DmUserHandler(std::unique_ptr<Snapuserd>&& snapuserd)
+ : snapuserd_(std::move(snapuserd)), misc_name_(snapuserd_->GetMiscName()) {}
bool SnapuserdServer::Sendmsg(android::base::borrowed_fd fd, const std::string& msg) {
ssize_t ret = TEMP_FAILURE_RETRY(send(fd.get(), msg.data(), msg.size(), 0));
@@ -148,7 +147,7 @@
LOG(ERROR) << "Could not find handler: " << out[1];
return Sendmsg(fd, "fail");
}
- if ((*iter)->snapuserd()->IsAttached()) {
+ if (!(*iter)->snapuserd() || (*iter)->snapuserd()->IsAttached()) {
LOG(ERROR) << "Tried to re-attach control device: " << out[1];
return Sendmsg(fd, "fail");
}
@@ -185,7 +184,7 @@
LOG(ERROR) << "Malformed delete message, " << out.size() << " parts";
return Sendmsg(fd, "fail");
}
- if (!RemoveHandler(out[1], true)) {
+ if (!RemoveAndJoinHandler(out[1])) {
return Sendmsg(fd, "fail");
}
return Sendmsg(fd, "success");
@@ -203,20 +202,38 @@
}
void SnapuserdServer::RunThread(std::shared_ptr<DmUserHandler> handler) {
- LOG(INFO) << "Entering thread for handler: " << handler->GetMiscName();
+ LOG(INFO) << "Entering thread for handler: " << handler->misc_name();
while (!StopRequested()) {
if (!handler->snapuserd()->Run()) {
- LOG(INFO) << "Snapuserd: Thread terminating";
break;
}
}
- LOG(INFO) << "Exiting thread for handler: " << handler->GetMiscName();
+ auto misc_name = handler->misc_name();
+ LOG(INFO) << "Handler thread about to exit: " << misc_name;
- // If the main thread called RemoveHandler, the handler was already removed
- // from within the lock, and calling RemoveHandler again has no effect.
- RemoveHandler(handler->GetMiscName(), false);
+ {
+ std::lock_guard<std::mutex> lock(lock_);
+ auto iter = FindHandler(&lock, handler->misc_name());
+ if (iter == dm_users_.end()) {
+ // RemoveAndJoinHandler() already removed us from the list, and is
+ // now waiting on a join(), so just return.
+ LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name;
+ return;
+ }
+
+ LOG(INFO) << "Exiting handler thread and freeing resources: " << misc_name;
+
+ if (handler->snapuserd()->IsAttached()) {
+ handler->thread().detach();
+ }
+
+ // Important: free resources within the lock. This ensures that if
+ // WaitForDelete() is called, the handler is either in the list, or
+ // it's not and its resources are guaranteed to be freed.
+ handler->FreeResources();
+ }
}
bool SnapuserdServer::Start(const std::string& socketname) {
@@ -351,7 +368,7 @@
CHECK(!handler->snapuserd()->IsAttached());
if (!handler->snapuserd()->InitBackingAndControlDevice()) {
- LOG(ERROR) << "Failed to initialize control device: " << handler->GetMiscName();
+ LOG(ERROR) << "Failed to initialize control device: " << handler->misc_name();
return false;
}
@@ -364,14 +381,14 @@
CHECK(proof_of_lock);
for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) {
- if ((*iter)->GetMiscName() == misc_name) {
+ if ((*iter)->misc_name() == misc_name) {
return iter;
}
}
return dm_users_.end();
}
-bool SnapuserdServer::RemoveHandler(const std::string& misc_name, bool wait) {
+bool SnapuserdServer::RemoveAndJoinHandler(const std::string& misc_name) {
std::shared_ptr<DmUserHandler> handler;
{
std::lock_guard<std::mutex> lock(lock_);
@@ -386,10 +403,8 @@
}
auto& th = handler->thread();
- if (th.joinable() && wait) {
+ if (th.joinable()) {
th.join();
- } else if (handler->snapuserd()->IsAttached()) {
- th.detach();
}
return true;
}
diff --git a/fs_mgr/libsnapshot/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd_server.h
index 01e2365..7cbc2de 100644
--- a/fs_mgr/libsnapshot/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/snapuserd_server.h
@@ -46,18 +46,19 @@
};
class DmUserHandler {
- private:
- std::thread thread_;
- std::unique_ptr<Snapuserd> snapuserd_;
-
public:
- explicit DmUserHandler(std::unique_ptr<Snapuserd>&& snapuserd)
- : snapuserd_(std::move(snapuserd)) {}
+ explicit DmUserHandler(std::unique_ptr<Snapuserd>&& snapuserd);
+ void FreeResources() { snapuserd_ = nullptr; }
const std::unique_ptr<Snapuserd>& snapuserd() const { return snapuserd_; }
std::thread& thread() { return thread_; }
- const std::string& GetMiscName() const;
+ const std::string& misc_name() const { return misc_name_; }
+
+ private:
+ std::thread thread_;
+ std::unique_ptr<Snapuserd> snapuserd_;
+ std::string misc_name_;
};
class Stoppable {
@@ -71,8 +72,9 @@
bool StopRequested() {
// checks if value in future object is available
- if (futureObj_.wait_for(std::chrono::milliseconds(0)) == std::future_status::timeout)
+ if (futureObj_.wait_for(std::chrono::milliseconds(0)) == std::future_status::timeout) {
return false;
+ }
return true;
}
// Request the thread to stop by setting value in promise object
@@ -98,7 +100,7 @@
bool Receivemsg(android::base::borrowed_fd fd, const std::string& str);
void ShutdownThreads();
- bool RemoveHandler(const std::string& control_device, bool wait);
+ bool RemoveAndJoinHandler(const std::string& control_device);
DaemonOperations Resolveop(std::string& input);
std::string GetDaemonStatus();
void Parsemsg(std::string const& msg, const char delim, std::vector<std::string>& out);
diff --git a/gatekeeperd/Android.bp b/gatekeeperd/Android.bp
index 27a6452..2d9a820 100644
--- a/gatekeeperd/Android.bp
+++ b/gatekeeperd/Android.bp
@@ -28,6 +28,7 @@
shared_libs: [
"libbinder",
+ "libbinder_ndk",
"libgatekeeper",
"libgsi",
"liblog",
@@ -40,6 +41,8 @@
"libhidlbase",
"android.hardware.gatekeeper@1.0",
"libgatekeeper_aidl",
+ "android.hardware.security.keymint-unstable-ndk_platform",
+ "android.security.authorization-ndk_platform",
],
static_libs: ["libscrypt_static"],
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index b982dbc..ced7573 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -19,42 +19,44 @@
#include <android/service/gatekeeper/BnGateKeeperService.h>
#include <gatekeeper/GateKeeperResponse.h>
+#include <endian.h>
#include <errno.h>
#include <fcntl.h>
-#include <inttypes.h>
-#include <stdint.h>
#include <unistd.h>
#include <memory>
-#include <android/security/keystore/IKeystoreService.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <android/binder_manager.h>
+#include <android/security/keystore/IKeystoreService.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
-#include <gatekeeper/password_handle.h> // for password_handle_t
-#include <hardware/gatekeeper.h>
+#include <gatekeeper/password_handle.h> // for password_handle_t
#include <hardware/hw_auth_token.h>
-#include <keystore/keystore.h> // For error code
#include <keystore/keystore_return_types.h>
#include <libgsi/libgsi.h>
#include <log/log.h>
-#include <utils/Log.h>
#include <utils/String16.h>
-#include <hidl/HidlSupport.h>
+#include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
+#include <aidl/android/security/authorization/IKeystoreAuthorization.h>
#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+#include <hidl/HidlSupport.h>
using android::sp;
-using android::hardware::gatekeeper::V1_0::IGatekeeper;
-using android::hardware::gatekeeper::V1_0::GatekeeperStatusCode;
-using android::hardware::gatekeeper::V1_0::GatekeeperResponse;
using android::hardware::Return;
+using android::hardware::gatekeeper::V1_0::GatekeeperResponse;
+using android::hardware::gatekeeper::V1_0::GatekeeperStatusCode;
+using android::hardware::gatekeeper::V1_0::IGatekeeper;
using ::android::binder::Status;
using ::android::service::gatekeeper::BnGateKeeperService;
using GKResponse = ::android::service::gatekeeper::GateKeeperResponse;
using GKResponseCode = ::android::service::gatekeeper::ResponseCode;
+using ::aidl::android::hardware::security::keymint::HardwareAuthenticatorType;
+using ::aidl::android::hardware::security::keymint::HardwareAuthToken;
+using ::aidl::android::security::authorization::IKeystoreAuthorization;
namespace android {
@@ -62,7 +64,7 @@
static const String16 DUMP_PERMISSION("android.permission.DUMP");
class GateKeeperProxy : public BnGateKeeperService {
-public:
+ public:
GateKeeperProxy() {
clear_state_if_needed_done = false;
hw_device = IGatekeeper::getService();
@@ -73,8 +75,7 @@
}
}
- virtual ~GateKeeperProxy() {
- }
+ virtual ~GateKeeperProxy() {}
void store_sid(uint32_t userId, uint64_t sid) {
char filename[21];
@@ -96,7 +97,7 @@
if (mark_cold_boot() && !is_running_gsi) {
ALOGI("cold boot: clearing state");
if (hw_device) {
- hw_device->deleteAllUsers([](const GatekeeperResponse &){});
+ hw_device->deleteAllUsers([](const GatekeeperResponse&) {});
}
}
@@ -104,7 +105,7 @@
}
bool mark_cold_boot() {
- const char *filename = ".coldboot";
+ const char* filename = ".coldboot";
if (access(filename, F_OK) == -1) {
int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0) {
@@ -299,7 +300,34 @@
if (gkResponse->response_code() == GKResponseCode::OK) {
if (gkResponse->payload().size() != 0) {
+ // try to connect to IKeystoreAuthorization AIDL service first.
+ ::ndk::SpAIBinder authzBinder(
+ AServiceManager_getService("android.security.authorization"));
+ auto authzService = IKeystoreAuthorization::fromBinder(authzBinder);
+ if (authzService) {
+ if (gkResponse->payload().size() != sizeof(hw_auth_token_t)) {
+ LOG(ERROR) << "Incorrect size of AuthToken payload.";
+ return GK_ERROR;
+ }
+
+ const hw_auth_token_t* hwAuthToken =
+ reinterpret_cast<const hw_auth_token_t*>(gkResponse->payload().data());
+ HardwareAuthToken authToken;
+
+ authToken.timestamp.milliSeconds = betoh64(hwAuthToken->timestamp);
+ authToken.challenge = hwAuthToken->challenge;
+ authToken.authenticatorId = hwAuthToken->authenticator_id;
+ authToken.authenticatorType = static_cast<HardwareAuthenticatorType>(
+ betoh32(hwAuthToken->authenticator_type));
+ authToken.mac.assign(&hwAuthToken->hmac[0], &hwAuthToken->hmac[32]);
+ auto result = authzService->addAuthToken(authToken);
+ if (!result.isOk()) {
+ LOG(ERROR) << "Failure in sending AuthToken to AuthorizationService.";
+ return GK_ERROR;
+ }
+ }
sp<IServiceManager> sm = defaultServiceManager();
+
sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
sp<security::keystore::IKeystoreService> service =
interface_cast<security::keystore::IKeystoreService>(binder);
@@ -310,9 +338,12 @@
if (!binder_result.isOk() ||
!keystore::KeyStoreServiceReturnCode(result).isOk()) {
LOG(ERROR) << "Failure sending auth token to KeyStore: " << result;
+ return GK_ERROR;
}
} else {
- LOG(ERROR) << "Cannot deliver auth token. Unable to communicate with Keystore.";
+ LOG(ERROR) << "Cannot deliver auth token. Unable to communicate with "
+ "Keystore.";
+ return GK_ERROR;
}
}
@@ -366,23 +397,23 @@
}
if (hw_device == NULL) {
- const char *result = "Device not available";
+ const char* result = "Device not available";
write(fd, result, strlen(result) + 1);
} else {
- const char *result = "OK";
+ const char* result = "OK";
write(fd, result, strlen(result) + 1);
}
return OK;
}
-private:
+ private:
sp<IGatekeeper> hw_device;
bool clear_state_if_needed_done;
bool is_running_gsi;
};
-}// namespace android
+} // namespace android
int main(int argc, char* argv[]) {
ALOGI("Starting gatekeeperd...");
diff --git a/healthd/Android.bp b/healthd/Android.bp
index b3de9c4..251a45b 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -62,29 +62,6 @@
srcs: [
"HealthServiceDefault.cpp",
],
-
- overrides: [
- "healthd",
- ]
-}
-
-cc_binary {
- name: "healthd",
- defaults: ["android.hardware.health@2.0-service_defaults"],
-
- init_rc: ["healthd.rc"],
- srcs: [
- "HealthServiceHealthd.cpp",
- ],
- local_include_dirs: ["include"],
-
- shared_libs: [
- "android.hardware.health@1.0",
- ],
-
- vintf_fragments: [
- "manifest_healthd.xml"
- ],
}
cc_library_static {
diff --git a/healthd/HealthServiceHealthd.cpp b/healthd/HealthServiceHealthd.cpp
deleted file mode 100644
index 5fd2597..0000000
--- a/healthd/HealthServiceHealthd.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#define LOG_TAG "healthd"
-#include <android-base/logging.h>
-
-#include <android/hardware/health/1.0/IHealth.h>
-#include <android/hardware/health/1.0/types.h>
-#include <hal_conversion.h>
-#include <health2/service.h>
-#include <healthd/healthd.h>
-#include <hidl/HidlTransportSupport.h>
-
-using android::OK;
-using android::NAME_NOT_FOUND;
-using android::hardware::health::V1_0::HealthConfig;
-using android::hardware::health::V1_0::HealthInfo;
-using android::hardware::health::V1_0::Result;
-using android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig;
-using android::hardware::health::V1_0::hal_conversion::convertToHealthConfig;
-using android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
-using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
-
-using IHealthLegacy = android::hardware::health::V1_0::IHealth;
-
-static android::sp<IHealthLegacy> gHealth_1_0;
-
-static int healthd_board_get_energy_counter(int64_t* energy) {
- if (gHealth_1_0 == nullptr) {
- return NAME_NOT_FOUND;
- }
-
- Result result = Result::NOT_SUPPORTED;
- gHealth_1_0->energyCounter([energy, &result](Result ret, int64_t energyOut) {
- result = ret;
- *energy = energyOut;
- });
-
- return result == Result::SUCCESS ? OK : NAME_NOT_FOUND;
-}
-
-void healthd_board_init(struct healthd_config* config) {
- gHealth_1_0 = IHealthLegacy::getService();
-
- if (gHealth_1_0 == nullptr) {
- return;
- }
-
- HealthConfig halConfig{};
- convertToHealthConfig(config, halConfig);
- gHealth_1_0->init(halConfig, [config](const auto& halConfigOut) {
- convertFromHealthConfig(halConfigOut, config);
- // always redirect energy counter queries
- config->energyCounter = healthd_board_get_energy_counter;
- });
- LOG(INFO) << LOG_TAG << ": redirecting calls to 1.0 health HAL";
-}
-
-// TODO(b/68724651): Move this function into healthd_mode_service_2_0_battery_update
-// with logthis returned.
-int healthd_board_battery_update(struct android::BatteryProperties* props) {
- int logthis = 0;
-
- if (gHealth_1_0 == nullptr) {
- return logthis;
- }
-
- HealthInfo info;
- convertToHealthInfo(props, info);
- gHealth_1_0->update(info, [props, &logthis](int32_t ret, const auto& infoOut) {
- logthis = ret;
- convertFromHealthInfo(infoOut, props);
- });
-
- return logthis;
-}
-
-int main() {
- return health_service_main("backup");
-}
diff --git a/healthd/manifest_healthd.xml b/healthd/manifest_healthd.xml
deleted file mode 100644
index 097a7d8..0000000
--- a/healthd/manifest_healthd.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<manifest version="1.0" type="framework">
- <hal>
- <name>android.hardware.health</name>
- <transport>hwbinder</transport>
- <version>2.0</version>
- <interface>
- <name>IHealth</name>
- <instance>backup</instance>
- </interface>
- </hal>
-</manifest>
diff --git a/init/Android.bp b/init/Android.bp
index 19ba21b..cd295cf 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -60,6 +60,7 @@
"selabel.cpp",
"selinux.cpp",
"sigchld_handler.cpp",
+ "snapuserd_transition.cpp",
"switch_root.cpp",
"uevent_listener.cpp",
"ueventd.cpp",
diff --git a/init/Android.mk b/init/Android.mk
index c881e2f..561d641 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -57,6 +57,8 @@
reboot_utils.cpp \
selabel.cpp \
selinux.cpp \
+ service_utils.cpp \
+ snapuserd_transition.cpp \
switch_root.cpp \
uevent_listener.cpp \
util.cpp \
diff --git a/init/block_dev_initializer.h b/init/block_dev_initializer.h
index 79fe4ec..ec39ce0 100644
--- a/init/block_dev_initializer.h
+++ b/init/block_dev_initializer.h
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#pragma once
+
#include <memory>
#include <set>
#include <string>
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 0949fc5..6954c03 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -42,6 +42,7 @@
#include "first_stage_mount.h"
#include "reboot_utils.h"
#include "second_stage_resources.h"
+#include "snapuserd_transition.h"
#include "switch_root.h"
#include "util.h"
@@ -90,6 +91,12 @@
}
}
}
+ } else if (de->d_type == DT_REG) {
+ // Do not free snapuserd if we will need the ramdisk copy during the
+ // selinux transition.
+ if (de->d_name == "snapuserd"s && IsFirstStageSnapuserdRunning()) {
+ continue;
+ }
}
unlinkat(dfd, de->d_name, is_dir ? AT_REMOVEDIR : 0);
}
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index a0511cc..7c46281 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -44,6 +44,7 @@
#include "block_dev_initializer.h"
#include "devices.h"
+#include "snapuserd_transition.h"
#include "switch_root.h"
#include "uevent.h"
#include "uevent_listener.h"
@@ -87,6 +88,7 @@
protected:
bool InitRequiredDevices(std::set<std::string> devices);
bool CreateLogicalPartitions();
+ bool CreateSnapshotPartitions(android::snapshot::SnapshotManager* sm);
bool MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
Fstab::iterator* end = nullptr);
@@ -109,6 +111,7 @@
bool need_dm_verity_;
bool dsu_not_on_userdata_ = false;
+ bool use_snapuserd_ = false;
Fstab fstab_;
// The super path is only set after InitDevices, and is invalid before.
@@ -338,21 +341,7 @@
return false;
}
if (sm->NeedSnapshotsInFirstStageMount()) {
- // When COW images are present for snapshots, they are stored on
- // the data partition.
- if (!InitRequiredDevices({"userdata"})) {
- return false;
- }
- sm->SetUeventRegenCallback([this](const std::string& device) -> bool {
- if (android::base::StartsWith(device, "/dev/block/dm-")) {
- return block_dev_init_.InitDmDevice(device);
- }
- if (android::base::StartsWith(device, "/dev/dm-user/")) {
- return block_dev_init_.InitDmUser(android::base::Basename(device));
- }
- return block_dev_init_.InitDevices({device});
- });
- return sm->CreateLogicalAndSnapshotPartitions(super_path_);
+ return CreateSnapshotPartitions(sm.get());
}
}
@@ -367,6 +356,37 @@
return android::fs_mgr::CreateLogicalPartitions(*metadata.get(), super_path_);
}
+bool FirstStageMount::CreateSnapshotPartitions(SnapshotManager* sm) {
+ // When COW images are present for snapshots, they are stored on
+ // the data partition.
+ if (!InitRequiredDevices({"userdata"})) {
+ return false;
+ }
+
+ use_snapuserd_ = sm->IsSnapuserdRequired();
+ if (use_snapuserd_) {
+ LaunchFirstStageSnapuserd();
+ }
+
+ sm->SetUeventRegenCallback([this](const std::string& device) -> bool {
+ if (android::base::StartsWith(device, "/dev/block/dm-")) {
+ return block_dev_init_.InitDmDevice(device);
+ }
+ if (android::base::StartsWith(device, "/dev/dm-user/")) {
+ return block_dev_init_.InitDmUser(android::base::Basename(device));
+ }
+ return block_dev_init_.InitDevices({device});
+ });
+ if (!sm->CreateLogicalAndSnapshotPartitions(super_path_)) {
+ return false;
+ }
+
+ if (use_snapuserd_) {
+ CleanupSnapuserdSocket();
+ }
+ return true;
+}
+
bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
Fstab::iterator* end) {
// Sets end to begin + 1, so we can just return on failure below.
@@ -466,6 +486,10 @@
if (system_partition == fstab_.end()) return true;
+ if (use_snapuserd_) {
+ SaveRamdiskPathToSnapuserd();
+ }
+
if (MountPartition(system_partition, false /* erase_same_mounts */)) {
if (dsu_not_on_userdata_ && fs_mgr_verity_is_check_at_most_once(*system_partition)) {
LOG(ERROR) << "check_most_at_once forbidden on external media";
diff --git a/init/init.cpp b/init/init.cpp
index d1998a5..ca2d5da 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -79,6 +79,7 @@
#include "service.h"
#include "service_parser.h"
#include "sigchld_handler.h"
+#include "snapuserd_transition.h"
#include "subcontext.h"
#include "system/core/init/property_service.pb.h"
#include "util.h"
@@ -741,10 +742,15 @@
return {};
}
svc->Start();
+ svc->SetShutdownCritical();
- if (!sm->PerformSecondStageTransition()) {
+ if (!sm->PerformSecondStageInitTransition()) {
LOG(FATAL) << "Failed to transition snapuserd to second-stage";
}
+
+ if (auto pid = GetSnapuserdFirstStagePid()) {
+ KillFirstStageSnapuserd(pid.value());
+ }
return {};
}
@@ -872,6 +878,21 @@
auto is_installed = android::gsi::IsGsiInstalled() ? "1" : "0";
SetProperty(gsi::kGsiInstalledProp, is_installed);
+ /*
+ * For debug builds of S launching devices, init mounts debugfs for
+ * enabling vendor debug data collection setup at boot time. Init will unmount it on
+ * boot-complete after vendor code has performed the required initializations
+ * during boot. Dumpstate will then mount debugfs in order to read data
+ * from the same using the dumpstate HAL during bugreport creation.
+ * Dumpstate will also unmount debugfs after bugreport creation.
+ * first_api_level comparison is done here instead
+ * of init.rc since init.rc parser does not support >/< operators.
+ */
+ auto api_level = android::base::GetIntProperty("ro.product.first_api_level", 0);
+ bool is_debuggable = android::base::GetBoolProperty("ro.debuggable", false);
+ auto mount_debugfs = (is_debuggable && (api_level >= 31)) ? "1" : "0";
+ SetProperty("init.mount_debugfs", mount_debugfs);
+
am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
diff --git a/init/property_service.cpp b/init/property_service.cpp
index e71c386..ce67386 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -890,6 +890,69 @@
}
}
+// If the ro.product.cpu.abilist* properties have not been explicitly
+// set, derive them from ro.${partition}.product.cpu.abilist* properties.
+static void property_initialize_ro_cpu_abilist() {
+ // From high to low priority.
+ const char* kAbilistSources[] = {
+ "product",
+ "odm",
+ "vendor",
+ "system",
+ };
+ const std::string EMPTY = "";
+ const char* kAbilistProp = "ro.product.cpu.abilist";
+ const char* kAbilist32Prop = "ro.product.cpu.abilist32";
+ const char* kAbilist64Prop = "ro.product.cpu.abilist64";
+
+ // If the properties are defined explicitly, just use them.
+ if (GetProperty(kAbilistProp, EMPTY) != EMPTY) {
+ return;
+ }
+
+ // Find the first source defining these properties by order.
+ std::string abilist32_prop_val;
+ std::string abilist64_prop_val;
+ for (const auto& source : kAbilistSources) {
+ const auto abilist32_prop = std::string("ro.") + source + ".product.cpu.abilist32";
+ const auto abilist64_prop = std::string("ro.") + source + ".product.cpu.abilist64";
+ abilist32_prop_val = GetProperty(abilist32_prop, EMPTY);
+ abilist64_prop_val = GetProperty(abilist64_prop, EMPTY);
+ // The properties could be empty on 32-bit-only or 64-bit-only devices,
+ // but we cannot identify a property is empty or undefined by GetProperty().
+ // So, we assume both of these 2 properties are empty as undefined.
+ if (abilist32_prop_val != EMPTY || abilist64_prop_val != EMPTY) {
+ break;
+ }
+ }
+
+ // Merge ABI lists for ro.product.cpu.abilist
+ auto abilist_prop_val = abilist64_prop_val;
+ if (abilist32_prop_val != EMPTY) {
+ if (abilist_prop_val != EMPTY) {
+ abilist_prop_val += ",";
+ }
+ abilist_prop_val += abilist32_prop_val;
+ }
+
+ // Set these properties
+ const std::pair<const char*, const std::string&> set_prop_list[] = {
+ {kAbilistProp, abilist_prop_val},
+ {kAbilist32Prop, abilist32_prop_val},
+ {kAbilist64Prop, abilist64_prop_val},
+ };
+ for (const auto& [prop, prop_val] : set_prop_list) {
+ LOG(INFO) << "Setting property '" << prop << "' to '" << prop_val << "'";
+
+ std::string error;
+ uint32_t res = PropertySet(prop, prop_val, &error);
+ if (res != PROP_SUCCESS) {
+ LOG(ERROR) << "Error setting property '" << prop << "': err=" << res << " (" << error
+ << ")";
+ }
+ }
+}
+
void PropertyLoadBootDefaults() {
// We read the properties and their values into a map, in order to always allow properties
// loaded in the later property files to override the properties in loaded in the earlier
@@ -957,8 +1020,6 @@
load_properties_from_partition("odm", /* support_legacy_path_until */ 28);
load_properties_from_partition("product", /* support_legacy_path_until */ 30);
- load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
-
if (access(kDebugRamdiskProp, R_OK) == 0) {
LOG(INFO) << "Loading " << kDebugRamdiskProp;
load_properties_from_file(kDebugRamdiskProp, nullptr, &properties);
@@ -974,6 +1035,7 @@
property_initialize_ro_product_props();
property_derive_build_fingerprint();
+ property_initialize_ro_cpu_abilist();
update_sys_usb_config();
}
diff --git a/init/selinux.cpp b/init/selinux.cpp
index f03ca6b..0336936 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -45,7 +45,7 @@
// 2) If these hashes do not match, then either /system or /system_ext or /product (or some of them)
// have been updated out of sync with /vendor (or /odm if it is present) and the init needs to
// compile the SEPolicy. /system contains the SEPolicy compiler, secilc, and it is used by the
-// LoadSplitPolicy() function below to compile the SEPolicy to a temp directory and load it.
+// OpenSplitPolicy() function below to compile the SEPolicy to a temp directory and load it.
// That function contains even more documentation with the specific implementation details of how
// the SEPolicy is compiled if needed.
@@ -74,6 +74,7 @@
#include "block_dev_initializer.h"
#include "debug_ramdisk.h"
#include "reboot_utils.h"
+#include "snapuserd_transition.h"
#include "util.h"
using namespace std::string_literals;
@@ -298,7 +299,12 @@
return access(plat_policy_cil_file, R_OK) != -1;
}
-bool LoadSplitPolicy() {
+struct PolicyFile {
+ unique_fd fd;
+ std::string path;
+};
+
+bool OpenSplitPolicy(PolicyFile* policy_file) {
// IMPLEMENTATION NOTE: Split policy consists of three CIL files:
// * platform -- policy needed due to logic contained in the system image,
// * non-platform -- policy needed due to logic contained in the vendor image,
@@ -325,10 +331,8 @@
if (!use_userdebug_policy && FindPrecompiledSplitPolicy(&precompiled_sepolicy_file)) {
unique_fd fd(open(precompiled_sepolicy_file.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY));
if (fd != -1) {
- if (selinux_android_load_policy_from_fd(fd, precompiled_sepolicy_file.c_str()) < 0) {
- LOG(ERROR) << "Failed to load SELinux policy from " << precompiled_sepolicy_file;
- return false;
- }
+ policy_file->fd = std::move(fd);
+ policy_file->path = std::move(precompiled_sepolicy_file);
return true;
}
}
@@ -446,34 +450,39 @@
}
unlink(compiled_sepolicy);
- LOG(INFO) << "Loading compiled SELinux policy";
- if (selinux_android_load_policy_from_fd(compiled_sepolicy_fd, compiled_sepolicy) < 0) {
- LOG(ERROR) << "Failed to load SELinux policy from " << compiled_sepolicy;
- return false;
- }
-
+ policy_file->fd = std::move(compiled_sepolicy_fd);
+ policy_file->path = compiled_sepolicy;
return true;
}
-bool LoadMonolithicPolicy() {
- LOG(VERBOSE) << "Loading SELinux policy from monolithic file";
- if (selinux_android_load_policy() < 0) {
- PLOG(ERROR) << "Failed to load monolithic SELinux policy";
+bool OpenMonolithicPolicy(PolicyFile* policy_file) {
+ static constexpr char kSepolicyFile[] = "/sepolicy";
+
+ LOG(VERBOSE) << "Opening SELinux policy from monolithic file";
+ policy_file->fd.reset(open(kSepolicyFile, O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+ if (policy_file->fd < 0) {
+ PLOG(ERROR) << "Failed to open monolithic SELinux policy";
return false;
}
+ policy_file->path = kSepolicyFile;
return true;
}
-bool LoadPolicy() {
- return IsSplitPolicyDevice() ? LoadSplitPolicy() : LoadMonolithicPolicy();
-}
+void ReadPolicy(std::string* policy) {
+ PolicyFile policy_file;
-void SelinuxInitialize() {
- LOG(INFO) << "Loading SELinux policy";
- if (!LoadPolicy()) {
- LOG(FATAL) << "Unable to load SELinux policy";
+ bool ok = IsSplitPolicyDevice() ? OpenSplitPolicy(&policy_file)
+ : OpenMonolithicPolicy(&policy_file);
+ if (!ok) {
+ LOG(FATAL) << "Unable to open SELinux policy";
}
+ if (!android::base::ReadFdToString(policy_file.fd, policy)) {
+ PLOG(FATAL) << "Failed to read policy file: " << policy_file.path;
+ }
+}
+
+void SelinuxSetEnforcement() {
bool kernel_enforcing = (security_getenforce() == 1);
bool is_enforcing = IsEnforcing();
if (kernel_enforcing != is_enforcing) {
@@ -670,6 +679,30 @@
}
}
+static void LoadSelinuxPolicy(std::string& policy) {
+ LOG(INFO) << "Loading SELinux policy";
+
+ set_selinuxmnt("/sys/fs/selinux");
+ if (security_load_policy(policy.data(), policy.size()) < 0) {
+ PLOG(FATAL) << "SELinux: Could not load policy";
+ }
+}
+
+// The SELinux setup process is carefully orchestrated around snapuserd. Policy
+// must be loaded off dynamic partitions, and during an OTA, those partitions
+// cannot be read without snapuserd. But, with kernel-privileged snapuserd
+// running, loading the policy will immediately trigger audits.
+//
+// We use a five-step process to address this:
+// (1) Read the policy into a string, with snapuserd running.
+// (2) Rewrite the snapshot device-mapper tables, to generate new dm-user
+// devices and to flush I/O.
+// (3) Kill snapuserd, which no longer has any dm-user devices to attach to.
+// (4) Load the sepolicy and issue critical restorecons in /dev, carefully
+// avoiding anything that would read from /system.
+// (5) Re-launch snapuserd and attach it to the dm-user devices from step (2).
+//
+// After this sequence, it is safe to enable enforcing mode and continue booting.
int SetupSelinux(char** argv) {
SetStdioToDevNull(argv);
InitKernelLogging(argv);
@@ -682,9 +715,31 @@
MountMissingSystemPartitions();
- // Set up SELinux, loading the SELinux policy.
SelinuxSetupKernelLogging();
- SelinuxInitialize();
+
+ LOG(INFO) << "Opening SELinux policy";
+
+ // Read the policy before potentially killing snapuserd.
+ std::string policy;
+ ReadPolicy(&policy);
+
+ auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded();
+ if (snapuserd_helper) {
+ // Kill the old snapused to avoid audit messages. After this we cannot
+ // read from /system (or other dynamic partitions) until we call
+ // FinishTransition().
+ snapuserd_helper->StartTransition();
+ }
+
+ LoadSelinuxPolicy(policy);
+
+ if (snapuserd_helper) {
+ // Before enforcing, finish the pending snapuserd transition.
+ snapuserd_helper->FinishTransition();
+ snapuserd_helper = nullptr;
+ }
+
+ SelinuxSetEnforcement();
// We're in the kernel domain and want to transition to the init domain. File systems that
// store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here,
diff --git a/init/snapuserd_transition.cpp b/init/snapuserd_transition.cpp
new file mode 100644
index 0000000..19b5c57
--- /dev/null
+++ b/init/snapuserd_transition.cpp
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2020 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 "snapuserd_transition.h"
+
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+
+#include <filesystem>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <cutils/sockets.h>
+#include <libsnapshot/snapshot.h>
+#include <libsnapshot/snapuserd_client.h>
+#include <private/android_filesystem_config.h>
+#include <selinux/android.h>
+
+#include "block_dev_initializer.h"
+#include "service_utils.h"
+#include "util.h"
+
+namespace android {
+namespace init {
+
+using namespace std::string_literals;
+
+using android::base::unique_fd;
+using android::snapshot::SnapshotManager;
+using android::snapshot::SnapuserdClient;
+
+static constexpr char kSnapuserdPath[] = "/system/bin/snapuserd";
+static constexpr char kSnapuserdFirstStagePidVar[] = "FIRST_STAGE_SNAPUSERD_PID";
+static constexpr char kSnapuserdFirstStageFdVar[] = "FIRST_STAGE_SNAPUSERD_FD";
+static constexpr char kSnapuserdLabel[] = "u:object_r:snapuserd_exec:s0";
+static constexpr char kSnapuserdSocketLabel[] = "u:object_r:snapuserd_socket:s0";
+
+void LaunchFirstStageSnapuserd() {
+ SocketDescriptor socket_desc;
+ socket_desc.name = android::snapshot::kSnapuserdSocket;
+ socket_desc.type = SOCK_STREAM;
+ socket_desc.perm = 0660;
+ socket_desc.uid = AID_SYSTEM;
+ socket_desc.gid = AID_SYSTEM;
+
+ // We specify a label here even though it technically is not needed. During
+ // first_stage_mount there is no sepolicy loaded. Once sepolicy is loaded,
+ // we bypass the socket entirely.
+ auto socket = socket_desc.Create(kSnapuserdSocketLabel);
+ if (!socket.ok()) {
+ LOG(FATAL) << "Could not create snapuserd socket: " << socket.error();
+ }
+
+ pid_t pid = fork();
+ if (pid < 0) {
+ PLOG(FATAL) << "Cannot launch snapuserd; fork failed";
+ }
+ if (pid == 0) {
+ socket->Publish();
+ char arg0[] = "/system/bin/snapuserd";
+ char* const argv[] = {arg0, nullptr};
+ if (execv(arg0, argv) < 0) {
+ PLOG(FATAL) << "Cannot launch snapuserd; execv failed";
+ }
+ _exit(127);
+ }
+
+ setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
+
+ LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
+}
+
+std::optional<pid_t> GetSnapuserdFirstStagePid() {
+ const char* pid_str = getenv(kSnapuserdFirstStagePidVar);
+ if (!pid_str) {
+ return {};
+ }
+
+ int pid = 0;
+ if (!android::base::ParseInt(pid_str, &pid)) {
+ LOG(FATAL) << "Could not parse pid in environment, " << kSnapuserdFirstStagePidVar << "="
+ << pid_str;
+ }
+ return {pid};
+}
+
+static void RelabelLink(const std::string& link) {
+ selinux_android_restorecon(link.c_str(), 0);
+
+ std::string path;
+ if (android::base::Readlink(link, &path)) {
+ selinux_android_restorecon(path.c_str(), 0);
+ }
+}
+
+static void RelabelDeviceMapper() {
+ selinux_android_restorecon("/dev/device-mapper", 0);
+
+ std::error_code ec;
+ for (auto& iter : std::filesystem::directory_iterator("/dev/block", ec)) {
+ const auto& path = iter.path();
+ if (android::base::StartsWith(path.string(), "/dev/block/dm-")) {
+ selinux_android_restorecon(path.string().c_str(), 0);
+ }
+ }
+}
+
+static std::optional<int> GetRamdiskSnapuserdFd() {
+ const char* fd_str = getenv(kSnapuserdFirstStageFdVar);
+ if (!fd_str) {
+ return {};
+ }
+
+ int fd;
+ if (!android::base::ParseInt(fd_str, &fd)) {
+ LOG(FATAL) << "Could not parse fd in environment, " << kSnapuserdFirstStageFdVar << "="
+ << fd_str;
+ }
+ return {fd};
+}
+
+void RestoreconRamdiskSnapuserd(int fd) {
+ if (fsetxattr(fd, XATTR_NAME_SELINUX, kSnapuserdLabel, strlen(kSnapuserdLabel) + 1, 0) < 0) {
+ PLOG(FATAL) << "fsetxattr snapuserd failed";
+ }
+}
+
+SnapuserdSelinuxHelper::SnapuserdSelinuxHelper(std::unique_ptr<SnapshotManager>&& sm, pid_t old_pid)
+ : sm_(std::move(sm)), old_pid_(old_pid) {
+ // Only dm-user device names change during transitions, so the other
+ // devices are expected to be present.
+ sm_->SetUeventRegenCallback([this](const std::string& device) -> bool {
+ if (android::base::StartsWith(device, "/dev/dm-user/")) {
+ return block_dev_init_.InitDmUser(android::base::Basename(device));
+ }
+ return true;
+ });
+}
+
+void SnapuserdSelinuxHelper::StartTransition() {
+ LOG(INFO) << "Starting SELinux transition of snapuserd";
+
+ // The restorecon path reads from /system etc, so make sure any reads have
+ // been cached before proceeding.
+ auto handle = selinux_android_file_context_handle();
+ if (!handle) {
+ LOG(FATAL) << "Could not create SELinux file context handle";
+ }
+ selinux_android_set_sehandle(handle);
+
+ // We cannot access /system after the transition, so make sure init is
+ // pinned in memory.
+ if (mlockall(MCL_CURRENT) < 0) {
+ LOG(FATAL) << "mlockall failed";
+ }
+
+ argv_.emplace_back("snapuserd");
+ argv_.emplace_back("-no_socket");
+ if (!sm_->DetachSnapuserdForSelinux(&argv_)) {
+ LOG(FATAL) << "Could not perform selinux transition";
+ }
+
+ // Make sure the process is gone so we don't have any selinux audits.
+ KillFirstStageSnapuserd(old_pid_);
+}
+
+void SnapuserdSelinuxHelper::FinishTransition() {
+ RelabelLink("/dev/block/by-name/super");
+ RelabelDeviceMapper();
+
+ selinux_android_restorecon("/dev/null", 0);
+ selinux_android_restorecon("/dev/urandom", 0);
+ selinux_android_restorecon("/dev/kmsg", 0);
+ selinux_android_restorecon("/dev/dm-user", SELINUX_ANDROID_RESTORECON_RECURSE);
+
+ RelaunchFirstStageSnapuserd();
+
+ if (munlockall() < 0) {
+ PLOG(ERROR) << "munlockall failed";
+ }
+}
+
+void SnapuserdSelinuxHelper::RelaunchFirstStageSnapuserd() {
+ auto fd = GetRamdiskSnapuserdFd();
+ if (!fd) {
+ LOG(FATAL) << "Environment variable " << kSnapuserdFirstStageFdVar << " was not set!";
+ }
+ unsetenv(kSnapuserdFirstStageFdVar);
+
+ RestoreconRamdiskSnapuserd(fd.value());
+
+ pid_t pid = fork();
+ if (pid < 0) {
+ PLOG(FATAL) << "Fork to relaunch snapuserd failed";
+ }
+ if (pid > 0) {
+ // We don't need the descriptor anymore, and it should be closed to
+ // avoid leaking into subprocesses.
+ close(fd.value());
+
+ setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
+
+ LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
+ return;
+ }
+
+ // Make sure the descriptor is gone after we exec.
+ if (fcntl(fd.value(), F_SETFD, FD_CLOEXEC) < 0) {
+ PLOG(FATAL) << "fcntl FD_CLOEXEC failed for snapuserd fd";
+ }
+
+ std::vector<char*> argv;
+ for (auto& arg : argv_) {
+ argv.emplace_back(arg.data());
+ }
+ argv.emplace_back(nullptr);
+
+ int rv = syscall(SYS_execveat, fd.value(), "", reinterpret_cast<char* const*>(argv.data()),
+ nullptr, AT_EMPTY_PATH);
+ if (rv < 0) {
+ PLOG(FATAL) << "Failed to execveat() snapuserd";
+ }
+}
+
+std::unique_ptr<SnapuserdSelinuxHelper> SnapuserdSelinuxHelper::CreateIfNeeded() {
+ if (IsRecoveryMode()) {
+ return nullptr;
+ }
+
+ auto old_pid = GetSnapuserdFirstStagePid();
+ if (!old_pid) {
+ return nullptr;
+ }
+
+ auto sm = SnapshotManager::NewForFirstStageMount();
+ if (!sm) {
+ LOG(FATAL) << "Unable to create SnapshotManager";
+ }
+ return std::make_unique<SnapuserdSelinuxHelper>(std::move(sm), old_pid.value());
+}
+
+void KillFirstStageSnapuserd(pid_t pid) {
+ if (kill(pid, SIGTERM) < 0 && errno != ESRCH) {
+ LOG(ERROR) << "Kill snapuserd pid failed: " << pid;
+ } else {
+ LOG(INFO) << "Sent SIGTERM to snapuserd process " << pid;
+ }
+}
+
+void CleanupSnapuserdSocket() {
+ auto socket_path = ANDROID_SOCKET_DIR "/"s + android::snapshot::kSnapuserdSocket;
+ if (access(socket_path.c_str(), F_OK) != 0) {
+ return;
+ }
+
+ // Tell the daemon to stop accepting connections and to gracefully exit
+ // once all outstanding handlers have terminated.
+ if (auto client = SnapuserdClient::Connect(android::snapshot::kSnapuserdSocket, 3s)) {
+ client->DetachSnapuserd();
+ }
+
+ // Unlink the socket so we can create it again in second-stage.
+ if (unlink(socket_path.c_str()) < 0) {
+ PLOG(FATAL) << "unlink " << socket_path << " failed";
+ }
+}
+
+void SaveRamdiskPathToSnapuserd() {
+ int fd = open(kSnapuserdPath, O_PATH);
+ if (fd < 0) {
+ PLOG(FATAL) << "Unable to open snapuserd: " << kSnapuserdPath;
+ }
+
+ auto value = std::to_string(fd);
+ if (setenv(kSnapuserdFirstStageFdVar, value.c_str(), 1) < 0) {
+ PLOG(FATAL) << "setenv failed: " << kSnapuserdFirstStageFdVar << "=" << value;
+ }
+}
+
+bool IsFirstStageSnapuserdRunning() {
+ return GetSnapuserdFirstStagePid().has_value();
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/snapuserd_transition.h b/init/snapuserd_transition.h
new file mode 100644
index 0000000..a5ab652
--- /dev/null
+++ b/init/snapuserd_transition.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 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 <sys/types.h>
+
+#include <optional>
+#include <string>
+#include <vector>
+
+#include <libsnapshot/snapshot.h>
+
+#include "block_dev_initializer.h"
+
+namespace android {
+namespace init {
+
+// Fork and exec a new copy of snapuserd.
+void LaunchFirstStageSnapuserd();
+
+class SnapuserdSelinuxHelper final {
+ using SnapshotManager = android::snapshot::SnapshotManager;
+
+ public:
+ SnapuserdSelinuxHelper(std::unique_ptr<SnapshotManager>&& sm, pid_t old_pid);
+
+ void StartTransition();
+ void FinishTransition();
+
+ // Return a helper for facilitating the selinux transition of snapuserd.
+ // If snapuserd is not in use, null is returned. StartTransition() should
+ // be called after reading policy. FinishTransition() should be called
+ // after loading policy. In between, no reads of /system or other dynamic
+ // partitions are possible.
+ static std::unique_ptr<SnapuserdSelinuxHelper> CreateIfNeeded();
+
+ private:
+ void RelaunchFirstStageSnapuserd();
+ void ExecSnapuserd();
+
+ std::unique_ptr<SnapshotManager> sm_;
+ BlockDevInitializer block_dev_init_;
+ pid_t old_pid_;
+ std::vector<std::string> argv_;
+};
+
+// Remove /dev/socket/snapuserd. This ensures that (1) the existing snapuserd
+// will receive no new requests, and (2) the next copy we transition to can
+// own the socket.
+void CleanupSnapuserdSocket();
+
+// Kill an instance of snapuserd given a pid.
+void KillFirstStageSnapuserd(pid_t pid);
+
+// Save an open fd to /system/bin (in the ramdisk) into an environment. This is
+// used to later execveat() snapuserd.
+void SaveRamdiskPathToSnapuserd();
+
+// Returns true if first-stage snapuserd is running.
+bool IsFirstStageSnapuserdRunning();
+
+// Return the pid of the first-stage instances of snapuserd, if it was started.
+std::optional<pid_t> GetSnapuserdFirstStagePid();
+
+// Save an open fd to /system/bin (in the ramdisk) into an environment. This is
+// used to later execveat() snapuserd.
+void SaveRamdiskPathToSnapuserd();
+
+// Returns true if first-stage snapuserd is running.
+bool IsFirstStageSnapuserdRunning();
+
+} // namespace init
+} // namespace android
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index cf809f1..d46aeab 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -210,9 +210,6 @@
"uevent.cpp",
],
},
- bionic: {
- header_libs: ["bionic_libc_platform_headers"],
- },
android_arm: {
sanitize: {
diff --git a/libcutils/memory.cpp b/libcutils/memory.cpp
index f526520..5a410c2 100644
--- a/libcutils/memory.cpp
+++ b/libcutils/memory.cpp
@@ -18,19 +18,18 @@
#include <log/log.h>
-#ifdef __BIONIC__
-#include <bionic/malloc.h>
+#if !defined(__APPLE__)
+#include <malloc.h>
#endif
void process_disable_memory_mitigations() {
bool success = false;
#ifdef __BIONIC__
- // TODO(b/158870657) is fixed and scudo is used globally, we can assert when an
- // an error is returned.
-
- success = android_mallopt(M_DISABLE_MEMORY_MITIGATIONS, nullptr, 0);
+ success = mallopt(M_BIONIC_DISABLE_MEMORY_MITIGATIONS, 0);
#endif
+ // TODO: if b/158870657 is fixed and scudo is used globally,
+ // we can assert on failure rather than just log.
if (success) {
ALOGI("Disabled memory mitigations for process.");
} else {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 4478bea..049301d 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -934,6 +934,9 @@
write /proc/sys/vm/dirty_expire_centisecs 200
write /proc/sys/vm/dirty_background_ratio 5
+on property:sys.boot_completed=1 && property:init.mount_debugfs=1
+ umount /sys/kernel/debug
+
on boot
# basic network init
ifup lo
@@ -1202,6 +1205,10 @@
on property:sys.boot_completed=1 && property:sys.init.userspace_reboot.in_progress=1
setprop sys.init.userspace_reboot.in_progress ""
+on early-init && property:init.mount_debugfs=1
+ mount debugfs debugfs /sys/kernel/debug
+ chmod 0755 /sys/kernel/debug
+
# Migrate tasks again in case kernel threads are created during boot
on property:sys.boot_completed=1
copy_per_line /dev/cpuctl/tasks /dev/cpuctl/system/tasks
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index a1e9b12..64a64d2 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -48,6 +48,7 @@
/dev/pmsg0 0222 root log
/dev/dma_heap/system 0444 system system
/dev/dma_heap/system-uncached 0444 system system
+/dev/dma_heap/system-secure 0444 system system
# kms driver for drm based gpu
/dev/dri/* 0666 root graphics
diff --git a/trusty/confirmationui/fuzz/Android.bp b/trusty/confirmationui/fuzz/Android.bp
index 0819c21..635966f 100644
--- a/trusty/confirmationui/fuzz/Android.bp
+++ b/trusty/confirmationui/fuzz/Android.bp
@@ -16,4 +16,8 @@
name: "trusty_confirmationui_fuzzer",
defaults: ["trusty_fuzzer_defaults"],
srcs: ["fuzz.cpp"],
+
+ // The initial corpus for this fuzzer was derived by dumping bytes from
+ // ConfirmationUI VTS.
+ corpus: ["corpus/*"],
}
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-2ekYc2 b/trusty/confirmationui/fuzz/corpus/confirmationui-2ekYc2
new file mode 100644
index 0000000..53fe0c9
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-2ekYc2
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-5yTG3f b/trusty/confirmationui/fuzz/corpus/confirmationui-5yTG3f
new file mode 100644
index 0000000..d627b01
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-5yTG3f
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-6l8Soq b/trusty/confirmationui/fuzz/corpus/confirmationui-6l8Soq
new file mode 100644
index 0000000..bda80fd
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-6l8Soq
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-7kFpGO b/trusty/confirmationui/fuzz/corpus/confirmationui-7kFpGO
new file mode 100644
index 0000000..5adf905
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-7kFpGO
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-92m2f3 b/trusty/confirmationui/fuzz/corpus/confirmationui-92m2f3
new file mode 100644
index 0000000..5adf905
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-92m2f3
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-ALYIzO b/trusty/confirmationui/fuzz/corpus/confirmationui-ALYIzO
new file mode 100644
index 0000000..5adf905
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-ALYIzO
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-AcIMhR b/trusty/confirmationui/fuzz/corpus/confirmationui-AcIMhR
new file mode 100644
index 0000000..f5854f8
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-AcIMhR
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-AieaIi b/trusty/confirmationui/fuzz/corpus/confirmationui-AieaIi
new file mode 100644
index 0000000..5adf905
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-AieaIi
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-BdqX5j b/trusty/confirmationui/fuzz/corpus/confirmationui-BdqX5j
new file mode 100644
index 0000000..5adf905
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-BdqX5j
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-JBPIGs b/trusty/confirmationui/fuzz/corpus/confirmationui-JBPIGs
new file mode 100644
index 0000000..5adf905
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-JBPIGs
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-MWHw4T b/trusty/confirmationui/fuzz/corpus/confirmationui-MWHw4T
new file mode 100644
index 0000000..0dc6e91
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-MWHw4T
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-TZzVLO b/trusty/confirmationui/fuzz/corpus/confirmationui-TZzVLO
new file mode 100644
index 0000000..927d64d
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-TZzVLO
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-WwdA3B b/trusty/confirmationui/fuzz/corpus/confirmationui-WwdA3B
new file mode 100644
index 0000000..5adf905
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-WwdA3B
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-globJV b/trusty/confirmationui/fuzz/corpus/confirmationui-globJV
new file mode 100644
index 0000000..5adf905
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-globJV
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-hzUgjD b/trusty/confirmationui/fuzz/corpus/confirmationui-hzUgjD
new file mode 100644
index 0000000..87870ca
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-hzUgjD
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-jXC78o b/trusty/confirmationui/fuzz/corpus/confirmationui-jXC78o
new file mode 100644
index 0000000..0b274bf
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-jXC78o
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-kykxni b/trusty/confirmationui/fuzz/corpus/confirmationui-kykxni
new file mode 100644
index 0000000..5adf905
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-kykxni
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-npHe8t b/trusty/confirmationui/fuzz/corpus/confirmationui-npHe8t
new file mode 100644
index 0000000..87870ca
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-npHe8t
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-rPgnyI b/trusty/confirmationui/fuzz/corpus/confirmationui-rPgnyI
new file mode 100644
index 0000000..87870ca
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-rPgnyI
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-uCJ1Me b/trusty/confirmationui/fuzz/corpus/confirmationui-uCJ1Me
new file mode 100644
index 0000000..5adf905
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-uCJ1Me
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-wAQEjK b/trusty/confirmationui/fuzz/corpus/confirmationui-wAQEjK
new file mode 100644
index 0000000..5adf905
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-wAQEjK
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-xjtOks b/trusty/confirmationui/fuzz/corpus/confirmationui-xjtOks
new file mode 100644
index 0000000..b4a1c49
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-xjtOks
Binary files differ
diff --git a/trusty/confirmationui/fuzz/corpus/confirmationui-zKFIjN b/trusty/confirmationui/fuzz/corpus/confirmationui-zKFIjN
new file mode 100644
index 0000000..5adf905
--- /dev/null
+++ b/trusty/confirmationui/fuzz/corpus/confirmationui-zKFIjN
Binary files differ
diff --git a/trusty/confirmationui/fuzz/fuzz.cpp b/trusty/confirmationui/fuzz/fuzz.cpp
index aa132e8..df2517c 100644
--- a/trusty/confirmationui/fuzz/fuzz.cpp
+++ b/trusty/confirmationui/fuzz/fuzz.cpp
@@ -14,10 +14,7 @@
* limitations under the License.
*/
-#undef NDEBUG
-
-#include <assert.h>
-#include <log/log.h>
+#include <iostream>
#include <stdlib.h>
#include <trusty/coverage/coverage.h>
#include <trusty/fuzz/counters.h>
@@ -30,6 +27,7 @@
#define TIPC_DEV "/dev/trusty-ipc-dev0"
#define CONFIRMATIONUI_PORT "com.android.trusty.confirmationui"
+#define CONFIRMATIONUI_MODULE_NAME "confirmationui.syms.elf"
/* ConfirmationUI TA's UUID is 7dee2364-c036-425b-b086-df0f6c233c1b */
static struct uuid confirmationui_uuid = {
@@ -39,16 +37,30 @@
{0xb0, 0x86, 0xdf, 0x0f, 0x6c, 0x23, 0x3c, 0x1b},
};
-static CoverageRecord record(TIPC_DEV, &confirmationui_uuid);
+/* The format of the packets is as following:
+ * 16 bits (uint16_t, header) + payload bytes
+ * The 16 bits header spicify the number of bytes of payload (header excluded).
+ */
+struct data_packet {
+ uint16_t header;
+ uint8_t payload[];
+};
+
+static CoverageRecord record(TIPC_DEV, &confirmationui_uuid, CONFIRMATIONUI_MODULE_NAME);
extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) {
auto ret = record.Open();
- assert(ret.ok());
+ if (!ret.ok()) {
+ std::cerr << ret.error() << std::endl;
+ exit(-1);
+ }
return 0;
}
+/* Each corpus contains one or more data packets. */
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
static uint8_t buf[TIPC_MAX_MSG_SIZE];
+ size_t data_idx = 0;
ExtraCounters counters(&record);
counters.Reset();
@@ -59,16 +71,22 @@
android::trusty::fuzz::Abort();
}
- /* Write message to confirmationui server */
- ret = ta.Write(data, size);
- if (!ret.ok()) {
- return -1;
- }
+ while (data_idx < size) {
+ struct data_packet* data_packet_ptr = (struct data_packet*)&data[data_idx];
+ size_t payload_size = data_packet_ptr->header;
+ data_idx += data_packet_ptr->header + sizeof(data_packet_ptr->header);
- /* Read message from confirmationui server */
- ret = ta.Read(&buf, sizeof(buf));
- if (!ret.ok()) {
- return -1;
+ /* Write message to confirmationui server */
+ ret = ta.Write(data_packet_ptr->payload, payload_size);
+ if (!ret.ok()) {
+ return -1;
+ }
+
+ /* Read message from confirmationui server */
+ ret = ta.Read(&buf, sizeof(buf));
+ if (!ret.ok()) {
+ return -1;
+ }
}
return 0;
diff --git a/trusty/coverage/Android.bp b/trusty/coverage/Android.bp
index 6038d44..daa6f03 100644
--- a/trusty/coverage/Android.bp
+++ b/trusty/coverage/Android.bp
@@ -28,6 +28,7 @@
shared_libs: [
"libbase",
"liblog",
+ "libdmabufheap",
],
}
@@ -43,6 +44,7 @@
shared_libs: [
"libbase",
"liblog",
+ "libdmabufheap",
],
require_root: true,
}
diff --git a/trusty/coverage/coverage.cpp b/trusty/coverage/coverage.cpp
index f383dd1..5eccdc5 100644
--- a/trusty/coverage/coverage.cpp
+++ b/trusty/coverage/coverage.cpp
@@ -16,10 +16,12 @@
#define LOG_TAG "coverage"
+#include <BufferAllocator/BufferAllocator.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <assert.h>
+#include <log/log.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/uio.h>
@@ -37,6 +39,8 @@
using android::base::ErrnoError;
using android::base::Error;
using std::string;
+using std::to_string;
+using std::unique_ptr;
static inline uintptr_t RoundPageUp(uintptr_t val) {
return (val + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
@@ -46,12 +50,29 @@
: tipc_dev_(std::move(tipc_dev)),
coverage_srv_fd_(-1),
uuid_(*uuid),
+ sancov_filename_(),
+ record_len_(0),
+ shm_(NULL),
+ shm_len_(0) {}
+
+CoverageRecord::CoverageRecord(string tipc_dev, struct uuid* uuid, string module_name)
+ : tipc_dev_(std::move(tipc_dev)),
+ coverage_srv_fd_(-1),
+ uuid_(*uuid),
+ sancov_filename_(module_name + "." + to_string(getpid()) + ".sancov"),
record_len_(0),
shm_(NULL),
shm_len_(0) {}
CoverageRecord::~CoverageRecord() {
if (shm_) {
+ if (sancov_filename_) {
+ auto res = SaveSancovFile(*sancov_filename_);
+ if (!res.ok()) {
+ ALOGE("Could not write sancov file for module: %s\n", sancov_filename_->c_str());
+ }
+ }
+
munmap((void*)shm_, shm_len_);
}
}
@@ -114,24 +135,23 @@
record_len_ = resp.open_args.record_len;
shm_len_ = RoundPageUp(record_len_);
- fd = memfd_create("trusty-coverage", 0);
+ BufferAllocator allocator;
+
+ fd = allocator.Alloc("system", shm_len_);
if (fd < 0) {
- return ErrnoError() << "failed to create memfd: ";
+ return ErrnoError() << "failed to create dmabuf of size " << shm_len_
+ << " err code: " << fd;
}
- unique_fd memfd(fd);
+ unique_fd dma_buf(fd);
- if (ftruncate(memfd, shm_len_) < 0) {
- return ErrnoError() << "failed to resize memfd: ";
- }
-
- void* shm = mmap(0, shm_len_, PROT_READ | PROT_WRITE, MAP_SHARED, memfd, 0);
+ void* shm = mmap(0, shm_len_, PROT_READ | PROT_WRITE, MAP_SHARED, dma_buf, 0);
if (shm == MAP_FAILED) {
return ErrnoError() << "failed to map memfd: ";
}
req.hdr.cmd = COVERAGE_CLIENT_CMD_SHARE_RECORD;
req.share_record_args.shm_len = shm_len_;
- ret = Rpc(&req, memfd, &resp);
+ ret = Rpc(&req, dma_buf, &resp);
if (!ret.ok()) {
return Error() << "failed to send shared memory: ";
}
diff --git a/trusty/coverage/include/trusty/coverage/coverage.h b/trusty/coverage/include/trusty/coverage/coverage.h
index b6d46eb..5da68da 100644
--- a/trusty/coverage/include/trusty/coverage/coverage.h
+++ b/trusty/coverage/include/trusty/coverage/coverage.h
@@ -16,6 +16,7 @@
#pragma once
+#include <optional>
#include <string>
#include <android-base/result.h>
@@ -32,7 +33,18 @@
class CoverageRecord {
public:
+ /**
+ * Create a coverage record interface. Coverage will not be written to a
+ * sancov output file on completion.
+ */
CoverageRecord(std::string tipc_dev, struct uuid* uuid);
+
+ /**
+ * Create a coverage record interface. On destruction, write this coverage
+ * to the given sancov filename.
+ */
+ CoverageRecord(std::string tipc_dev, struct uuid* uuid, std::string module_name);
+
~CoverageRecord();
Result<void> Open();
void ResetFullRecord();
@@ -58,6 +70,7 @@
std::string tipc_dev_;
unique_fd coverage_srv_fd_;
struct uuid uuid_;
+ std::optional<std::string> sancov_filename_;
size_t record_len_;
volatile void* shm_;
size_t shm_len_;
diff --git a/trusty/fuzz/counters.cpp b/trusty/fuzz/counters.cpp
index 8c79475..1e863ac 100644
--- a/trusty/fuzz/counters.cpp
+++ b/trusty/fuzz/counters.cpp
@@ -21,6 +21,7 @@
#include <trusty/fuzz/counters.h>
#include <android-base/logging.h>
+#include <log/log.h>
#include <trusty/coverage/coverage.h>
#include <trusty/coverage/tipc.h>
@@ -32,7 +33,8 @@
* We don't know how many counters the coverage record will contain. So, eyeball
* the size of this section.
*/
-__attribute__((section("__libfuzzer_extra_counters"))) volatile uint8_t counters[PAGE_SIZE];
+static const size_t kMaxNumCounters = 0x4000;
+__attribute__((section("__libfuzzer_extra_counters"))) volatile uint8_t counters[kMaxNumCounters];
namespace android {
namespace trusty {
@@ -62,8 +64,16 @@
volatile uint8_t* end = NULL;
record_->GetRawCounts(&begin, &end);
+ if (!begin || !end) {
+ ALOGE("Could not get raw counts from coverage record\n");
+ return;
+ }
size_t num_counters = end - begin;
+ if (num_counters > kMaxNumCounters) {
+ ALOGE("Too many counters (%zu) to fit in the extra counters section!\n", num_counters);
+ num_counters = kMaxNumCounters;
+ }
for (size_t i = 0; i < num_counters; i++) {
*(counters + i) = *(begin + i);
}
diff --git a/trusty/fuzz/test/fuzz.cpp b/trusty/fuzz/test/fuzz.cpp
index 28bb3f7..e7913db 100644
--- a/trusty/fuzz/test/fuzz.cpp
+++ b/trusty/fuzz/test/fuzz.cpp
@@ -14,15 +14,12 @@
* limitations under the License.
*/
-#undef NDEBUG
-
-#include <assert.h>
-#include <log/log.h>
#include <stdlib.h>
#include <trusty/coverage/coverage.h>
#include <trusty/fuzz/counters.h>
#include <trusty/fuzz/utils.h>
#include <unistd.h>
+#include <iostream>
using android::trusty::coverage::CoverageRecord;
using android::trusty::fuzz::ExtraCounters;
@@ -43,7 +40,10 @@
extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) {
auto ret = record.Open();
- assert(ret.ok());
+ if (!ret.ok()) {
+ std::cerr << ret.error() << std::endl;
+ exit(-1);
+ }
return 0;
}
diff --git a/trusty/gatekeeper/fuzz/fuzz.cpp b/trusty/gatekeeper/fuzz/fuzz.cpp
index c0e8abb..7bfd7d1 100644
--- a/trusty/gatekeeper/fuzz/fuzz.cpp
+++ b/trusty/gatekeeper/fuzz/fuzz.cpp
@@ -14,15 +14,12 @@
* limitations under the License.
*/
-#undef NDEBUG
-
-#include <assert.h>
-#include <log/log.h>
#include <stdlib.h>
#include <trusty/coverage/coverage.h>
#include <trusty/fuzz/counters.h>
#include <trusty/fuzz/utils.h>
#include <unistd.h>
+#include <iostream>
using android::trusty::coverage::CoverageRecord;
using android::trusty::fuzz::ExtraCounters;
@@ -30,6 +27,7 @@
#define TIPC_DEV "/dev/trusty-ipc-dev0"
#define GATEKEEPER_PORT "com.android.trusty.gatekeeper"
+#define GATEKEEPER_MODULE_NAME "gatekeeper.syms.elf"
/* Gatekeeper TA's UUID is 38ba0cdc-df0e-11e4-9869-233fb6ae4795 */
static struct uuid gatekeeper_uuid = {
@@ -39,11 +37,14 @@
{0x98, 0x69, 0x23, 0x3f, 0xb6, 0xae, 0x47, 0x95},
};
-static CoverageRecord record(TIPC_DEV, &gatekeeper_uuid);
+static CoverageRecord record(TIPC_DEV, &gatekeeper_uuid, GATEKEEPER_MODULE_NAME);
extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) {
auto ret = record.Open();
- assert(ret.ok());
+ if (!ret.ok()) {
+ std::cerr << ret.error() << std::endl;
+ exit(-1);
+ }
return 0;
}
diff --git a/trusty/keymaster/fuzz/Android.bp b/trusty/keymaster/fuzz/Android.bp
new file mode 100644
index 0000000..da9f9ec
--- /dev/null
+++ b/trusty/keymaster/fuzz/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2020 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.
+
+cc_fuzz {
+ name: "trusty_keymaster_fuzzer",
+ defaults: ["trusty_fuzzer_defaults"],
+ srcs: ["fuzz.cpp"],
+}
diff --git a/trusty/keymaster/fuzz/fuzz.cpp b/trusty/keymaster/fuzz/fuzz.cpp
new file mode 100644
index 0000000..4ac97bb
--- /dev/null
+++ b/trusty/keymaster/fuzz/fuzz.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 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 <stdlib.h>
+#include <trusty/coverage/coverage.h>
+#include <trusty/fuzz/counters.h>
+#include <trusty/fuzz/utils.h>
+#include <unistd.h>
+#include <iostream>
+
+using android::trusty::coverage::CoverageRecord;
+using android::trusty::fuzz::ExtraCounters;
+using android::trusty::fuzz::TrustyApp;
+
+#define TIPC_DEV "/dev/trusty-ipc-dev0"
+#define KEYMASTER_PORT "com.android.trusty.keymaster"
+#define KEYMASTER_MODULE_FILENAME "keymaster.syms.elf"
+
+/* Keymaster TA's UUID is 5f902ace-5e5c-4cd8-ae54-87b88c22ddaf */
+static struct uuid keymaster_uuid = {
+ 0x5f902ace,
+ 0x5e5c,
+ 0x4cd8,
+ {0xae, 0x54, 0x87, 0xb8, 0x8c, 0x22, 0xdd, 0xaf},
+};
+
+static CoverageRecord record(TIPC_DEV, &keymaster_uuid, KEYMASTER_MODULE_FILENAME);
+
+extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) {
+ auto ret = record.Open();
+ if (!ret.ok()) {
+ std::cerr << ret.error() << std::endl;
+ exit(-1);
+ }
+ return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ static uint8_t buf[TIPC_MAX_MSG_SIZE];
+
+ ExtraCounters counters(&record);
+ counters.Reset();
+
+ android::trusty::fuzz::TrustyApp ta(TIPC_DEV, KEYMASTER_PORT);
+ auto ret = ta.Connect();
+ if (!ret.ok()) {
+ android::trusty::fuzz::Abort();
+ }
+
+ /* Send message to test server */
+ ret = ta.Write(data, size);
+ if (!ret.ok()) {
+ return -1;
+ }
+
+ /* Read message from test server */
+ ret = ta.Read(&buf, sizeof(buf));
+ if (!ret.ok()) {
+ return -1;
+ }
+
+ return 0;
+}