Merge "first_stage_mount: reading all avb_keys before chroot" am: e6211eb978 am: 5ffc6801e3
Change-Id: Ie1b844f440d0f59097f4fa21752f913a4b614af3
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index 8770a6b..50de42c 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -266,8 +266,10 @@
return avb_handle;
}
-AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const FstabEntry& fstab_entry) {
- if (fstab_entry.avb_keys.empty()) {
+AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const FstabEntry& fstab_entry,
+ const std::vector<std::string>& preload_avb_key_blobs) {
+ // At least one of the following should be provided for public key matching.
+ if (preload_avb_key_blobs.empty() && fstab_entry.avb_keys.empty()) {
LERROR << "avb_keys=/path/to/key(s) is missing for " << fstab_entry.mount_point;
return nullptr;
}
@@ -309,18 +311,36 @@
return nullptr;
}
- // fstab_entry.avb_keys might be either a directory containing multiple keys,
- // or a string indicating multiple keys separated by ':'.
- std::vector<std::string> allowed_avb_keys;
- auto list_avb_keys_in_dir = ListFiles(fstab_entry.avb_keys);
- if (list_avb_keys_in_dir) {
- std::sort(list_avb_keys_in_dir->begin(), list_avb_keys_in_dir->end());
- allowed_avb_keys = *list_avb_keys_in_dir;
- } else {
- allowed_avb_keys = Split(fstab_entry.avb_keys, ":");
+ bool public_key_match = false;
+ // Performs key matching for preload_avb_key_blobs first, if it is present.
+ if (!public_key_data.empty() && !preload_avb_key_blobs.empty()) {
+ if (std::find(preload_avb_key_blobs.begin(), preload_avb_key_blobs.end(),
+ public_key_data) != preload_avb_key_blobs.end()) {
+ public_key_match = true;
+ }
+ }
+ // Performs key matching for fstab_entry.avb_keys if necessary.
+ // Note that it is intentional to match both preload_avb_key_blobs and fstab_entry.avb_keys.
+ // Some keys might only be availble before init chroots into /system, e.g., /avb/key1
+ // in the first-stage ramdisk, while other keys might only be available after the chroot,
+ // e.g., /system/etc/avb/key2.
+ if (!public_key_data.empty() && !public_key_match) {
+ // fstab_entry.avb_keys might be either a directory containing multiple keys,
+ // or a string indicating multiple keys separated by ':'.
+ std::vector<std::string> allowed_avb_keys;
+ auto list_avb_keys_in_dir = ListFiles(fstab_entry.avb_keys);
+ if (list_avb_keys_in_dir) {
+ std::sort(list_avb_keys_in_dir->begin(), list_avb_keys_in_dir->end());
+ allowed_avb_keys = *list_avb_keys_in_dir;
+ } else {
+ allowed_avb_keys = Split(fstab_entry.avb_keys, ":");
+ }
+ if (ValidatePublicKeyBlob(public_key_data, allowed_avb_keys)) {
+ public_key_match = true;
+ }
}
- if (!ValidatePublicKeyBlob(public_key_data, allowed_avb_keys)) {
+ if (!public_key_match) {
avb_handle->status_ = AvbHandleStatus::kVerificationError;
LWARNING << "Found unknown public key used to sign " << fstab_entry.mount_point;
if (!allow_verification_error) {
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index 521f2d5..4702e68 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -85,8 +85,15 @@
// TODO(bowgotsai): remove Open() and switch to LoadAndVerifyVbmeta().
static AvbUniquePtr Open(); // loads inline vbmeta, via libavb.
static AvbUniquePtr LoadAndVerifyVbmeta(); // loads inline vbmeta.
- static AvbUniquePtr LoadAndVerifyVbmeta(
- const FstabEntry& fstab_entry); // loads offline vbmeta.
+
+ // The caller can specify optional preload_avb_key_blobs for public key matching.
+ // This is mostly for init to preload AVB keys before chroot into /system.
+ // Both preload_avb_key_blobs and fstab_entry.avb_keys (file paths) will be used
+ // for public key matching.
+ static AvbUniquePtr LoadAndVerifyVbmeta( // loads offline vbmeta.
+ const FstabEntry& fstab_entry,
+ const std::vector<std::string>& preload_avb_key_blobs = {});
+
static AvbUniquePtr LoadAndVerifyVbmeta( // loads offline vbmeta.
const std::string& partition_name, const std::string& ab_suffix,
const std::string& ab_other_suffix, const std::string& expected_public_key,
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index d8c4843..21663e6 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -21,6 +21,7 @@
#include <unistd.h>
#include <chrono>
+#include <map>
#include <memory>
#include <set>
#include <string>
@@ -29,6 +30,7 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <fs_avb/fs_avb.h>
#include <fs_mgr.h>
@@ -45,7 +47,9 @@
#include "uevent_listener.h"
#include "util.h"
+using android::base::ReadFileToString;
using android::base::Split;
+using android::base::StringPrintf;
using android::base::Timer;
using android::fiemap::IImageManager;
using android::fs_mgr::AvbHandle;
@@ -95,6 +99,7 @@
void GetDmLinearMetadataDevice(std::set<std::string>* devices);
bool InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata);
void UseDsuIfPresent();
+ void PreloadAvbKeys();
ListenerAction UeventCallback(const Uevent& uevent, std::set<std::string>* required_devices);
@@ -110,6 +115,9 @@
std::string super_partition_name_;
std::unique_ptr<DeviceHandler> device_handler_;
UeventListener uevent_listener_;
+ // Reads all AVB keys before chroot into /system, as they might be used
+ // later when mounting other partitions, e.g., /vendor and /product.
+ std::map<std::string, std::vector<std::string>> preload_avb_key_blobs_;
};
class FirstStageMountVBootV1 : public FirstStageMount {
@@ -508,11 +516,57 @@
return mounted;
}
+void FirstStageMount::PreloadAvbKeys() {
+ for (const auto& entry : fstab_) {
+ // No need to cache the key content if it's empty, or is already cached.
+ if (entry.avb_keys.empty() || preload_avb_key_blobs_.count(entry.avb_keys)) {
+ continue;
+ }
+
+ // Determines all key paths first.
+ std::vector<std::string> key_paths;
+ if (is_dir(entry.avb_keys.c_str())) { // fstab_keys might be a dir, e.g., /avb.
+ const char* avb_key_dir = entry.avb_keys.c_str();
+ std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(avb_key_dir), closedir);
+ if (!dir) {
+ LOG(ERROR) << "Failed to opendir: " << dir;
+ continue;
+ }
+ // Gets all key pathes under the dir.
+ struct dirent* de;
+ while ((de = readdir(dir.get()))) {
+ if (de->d_type != DT_REG) continue;
+ std::string full_path = StringPrintf("%s/%s", avb_key_dir, de->d_name);
+ key_paths.emplace_back(std::move(full_path));
+ }
+ std::sort(key_paths.begin(), key_paths.end());
+ } else {
+ // avb_keys are key paths separated by ":", if it's not a dir.
+ key_paths = Split(entry.avb_keys, ":");
+ }
+
+ // Reads the key content then cache it.
+ std::vector<std::string> key_blobs;
+ for (const auto& path : key_paths) {
+ std::string key_value;
+ if (!ReadFileToString(path, &key_value)) {
+ continue;
+ }
+ key_blobs.emplace_back(std::move(key_value));
+ }
+
+ // Maps entry.avb_keys to actual key blobs.
+ preload_avb_key_blobs_[entry.avb_keys] = std::move(key_blobs);
+ }
+}
+
// If system is in the fstab then we're not a system-as-root device, and in
// this case, we mount system first then pivot to it. From that point on,
// we are effectively identical to a system-as-root device.
bool FirstStageMount::TrySwitchSystemAsRoot() {
UseDsuIfPresent();
+ // Preloading all AVB keys from the ramdisk before switching root to /system.
+ PreloadAvbKeys();
auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
return entry.mount_point == "/system";
@@ -776,7 +830,8 @@
<< fstab_entry->mount_point;
return true; // Returns true to mount the partition directly.
} else {
- auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(*fstab_entry);
+ auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(
+ *fstab_entry, preload_avb_key_blobs_[fstab_entry->avb_keys]);
if (!avb_standalone_handle) {
LOG(ERROR) << "Failed to load offline vbmeta for " << fstab_entry->mount_point;
// Fallbacks to built-in hashtree if fs_mgr_flags.avb is set.