first_stage_mount: reading all avb_keys before chroot
Avb keys used to verify a partition are stored in the first-stage ramdisk. However, after /system is mounted, init will chroot into it. This makes those keys inaccessible for later mounts, e.g., /vendor or /product. This change retains avb keys by reading all of them before chroot into /system. Note that it is intentional to perform public matching for both preload_avb_key_blobs and fstab_entry.avb_keys in libfs_avb. As 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. Bug: 147585411 Test: specify avb_keys for a partition and checks the keys are preloaded Test: atest libfs_avb_test Test: atest libfs_avb_internal_test Change-Id: I6bd490c4215480db2937cdfc3fea0d616e224a91
This commit is contained in:
parent
ab65ef22a5
commit
e0f5c10691
3 changed files with 97 additions and 15 deletions
|
|
@ -266,8 +266,10 @@ AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(
|
|||
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 @@ AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const FstabEntry& fstab_entry) {
|
|||
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) {
|
||||
|
|
|
|||
|
|
@ -85,8 +85,15 @@ class AvbHandle {
|
|||
// 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,
|
||||
|
|
|
|||
|
|
@ -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 @@ class FirstStageMount {
|
|||
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 @@ class FirstStageMount {
|
|||
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 @@ bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_sa
|
|||
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 @@ bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) {
|
|||
<< 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.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue