init: early_mount: removing hard-coded paths

Current early mount has some hard-coded paths that are not easy to extend
when we switch verified boot to AVB (external/avb/libavb). This CL uses some
C++ containers to replace those fixed paths.

Bug: 33254008
Test: early mount /vendor with dm-verity on sailfish
Test: early mount /vendor without dm-verity on sailfish
Test: early mount /vendor with dm-verity on bullhead

Change-Id: I32a22fe486d7649e33bb23c9018ddc0428df6069
This commit is contained in:
Bowgo Tsai 2017-02-18 18:33:13 +08:00
parent 16f4fb9c4e
commit d4beed22e8
1 changed files with 115 additions and 113 deletions

View File

@ -52,6 +52,8 @@
#include <fstream>
#include <memory>
#include <set>
#include <vector>
#include "action.h"
#include "bootchart.h"
@ -700,6 +702,92 @@ static bool early_mount_one(struct fstab_rec* rec) {
return true;
}
// Creates devices with uevent->partition_name matching one in the in/out
// partition_names. Note that the partition_names MUST have A/B suffix
// when A/B is used. Found partitions will then be removed from the
// partition_names for caller to check which devices are NOT created.
static void early_device_init(std::set<std::string>* partition_names) {
if (partition_names->empty()) {
return;
}
device_init(nullptr, [=](uevent* uevent) -> coldboot_action_t {
if (!strncmp(uevent->subsystem, "firmware", 8)) {
return COLDBOOT_CONTINUE;
}
// we need platform devices to create symlinks
if (!strncmp(uevent->subsystem, "platform", 8)) {
return COLDBOOT_CREATE;
}
// Ignore everything that is not a block device
if (strncmp(uevent->subsystem, "block", 5)) {
return COLDBOOT_CONTINUE;
}
if (uevent->partition_name) {
// match partition names to create device nodes for partitions
// both partition_names and uevent->partition_name have A/B suffix when A/B is used
auto iter = partition_names->find(uevent->partition_name);
if (iter != partition_names->end()) {
LOG(VERBOSE) << "early_mount: found partition: " << *iter;
partition_names->erase(iter);
if (partition_names->empty()) {
return COLDBOOT_STOP; // found all partitions, stop coldboot
} else {
return COLDBOOT_CREATE; // create this device and continue to find others
}
}
}
// Not found a partition or find an unneeded partition, continue to find others
return COLDBOOT_CONTINUE;
});
}
static bool get_early_partitions(const std::vector<fstab_rec*>& early_fstab_recs,
std::set<std::string>* out_partitions, bool* out_need_verity) {
std::string meta_partition;
out_partitions->clear();
*out_need_verity = false;
for (auto fstab_rec : early_fstab_recs) {
// don't allow verifyatboot for early mounted partitions
if (fs_mgr_is_verifyatboot(fstab_rec)) {
LOG(ERROR) << "early_mount: partitions can't be verified at boot";
return false;
}
// check for verified partitions
if (fs_mgr_is_verified(fstab_rec)) {
*out_need_verity = true;
}
// check if verity metadata is on a separate partition and get partition
// name from the end of the ->verity_loc path. verity state is not partition
// specific, so there must be only 1 additional partition that carries
// verity state.
if (fstab_rec->verity_loc) {
if (!meta_partition.empty()) {
LOG(ERROR) << "early_mount: more than one meta partition found: " << meta_partition
<< ", " << basename(fstab_rec->verity_loc);
return false;
} else {
meta_partition = basename(fstab_rec->verity_loc);
}
}
}
// includes those early mount partitions and meta_partition (if any)
// note that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used
for (auto fstab_rec : early_fstab_recs) {
out_partitions->emplace(basename(fstab_rec->blk_device));
}
if (!meta_partition.empty()) {
out_partitions->emplace(std::move(meta_partition));
}
return true;
}
/* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
static bool early_mount() {
// first check if device tree fstab entries are compatible
@ -716,122 +804,36 @@ static bool early_mount() {
}
// find out fstab records for odm, system and vendor
// TODO: add std::map<std::string, fstab_rec*> so all required information about
// them can be gathered at once in a single loop
fstab_rec* odm_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/odm");
fstab_rec* system_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/system");
fstab_rec* vendor_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/vendor");
if (!odm_rec && !system_rec && !vendor_rec) {
// nothing to early mount
return true;
std::vector<fstab_rec*> early_fstab_recs;
for (auto mount_point : {"/odm", "/system", "/vendor"}) {
fstab_rec* fstab_rec = fs_mgr_get_entry_for_mount_point(tab.get(), mount_point);
if (fstab_rec != nullptr) {
early_fstab_recs.push_back(fstab_rec);
}
}
// don't allow verifyatboot for early mounted partitions
if ((odm_rec && fs_mgr_is_verifyatboot(odm_rec)) ||
(system_rec && fs_mgr_is_verifyatboot(system_rec)) ||
(vendor_rec && fs_mgr_is_verifyatboot(vendor_rec))) {
LOG(ERROR) << "Early mount partitions can't be verified at boot";
// nothing to early mount
if (early_fstab_recs.empty()) return true;
bool need_verity;
std::set<std::string> partition_names;
// partition_names MUST have A/B suffix when A/B is used
if (!get_early_partitions(early_fstab_recs, &partition_names, &need_verity)) {
return false;
}
// assume A/B device if we find 'slotselect' in any fstab entry
bool is_ab = ((odm_rec && fs_mgr_is_slotselect(odm_rec)) ||
(system_rec && fs_mgr_is_slotselect(system_rec)) ||
(vendor_rec && fs_mgr_is_slotselect(vendor_rec)));
// check for verified partitions
bool need_verity = ((odm_rec && fs_mgr_is_verified(odm_rec)) ||
(system_rec && fs_mgr_is_verified(system_rec)) ||
(vendor_rec && fs_mgr_is_verified(vendor_rec)));
// check if verity metadata is on a separate partition and get partition
// name from the end of the ->verity_loc path. verity state is not partition
// specific, so there must be only 1 additional partition that carries
// verity state.
std::string meta_partition;
if (odm_rec && odm_rec->verity_loc) {
meta_partition = basename(odm_rec->verity_loc);
} else if (system_rec && system_rec->verity_loc) {
meta_partition = basename(system_rec->verity_loc);
} else if (vendor_rec && vendor_rec->verity_loc) {
meta_partition = basename(vendor_rec->verity_loc);
}
bool found_odm = !odm_rec;
bool found_system = !system_rec;
bool found_vendor = !vendor_rec;
bool found_meta = meta_partition.empty();
int count_odm = 0, count_vendor = 0, count_system = 0;
bool success = false;
// create the devices we need..
device_init(nullptr, [&](uevent* uevent) -> coldboot_action_t {
if (!strncmp(uevent->subsystem, "firmware", 8)) {
return COLDBOOT_CONTINUE;
}
early_device_init(&partition_names);
// we need platform devices to create symlinks
if (!strncmp(uevent->subsystem, "platform", 8)) {
return COLDBOOT_CREATE;
}
// Ignore everything that is not a block device
if (strncmp(uevent->subsystem, "block", 5)) {
return COLDBOOT_CONTINUE;
}
coldboot_action_t ret;
bool create_this_node = false;
if (uevent->partition_name) {
// prefix match partition names so we create device nodes for
// A/B-ed partitions
if (!found_odm && !strncmp(uevent->partition_name, "odm", 3)) {
LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
// wait twice for A/B-ed partitions
count_odm++;
if (!is_ab || count_odm == 2) {
found_odm = true;
}
create_this_node = true;
} else if (!found_system && !strncmp(uevent->partition_name, "system", 6)) {
LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
count_system++;
if (!is_ab || count_system == 2) {
found_system = true;
}
create_this_node = true;
} else if (!found_vendor && !strncmp(uevent->partition_name, "vendor", 6)) {
LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
count_vendor++;
if (!is_ab || count_vendor == 2) {
found_vendor = true;
}
create_this_node = true;
} else if (!found_meta && (meta_partition == uevent->partition_name)) {
LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
found_meta = true;
create_this_node = true;
}
}
// if we found all other partitions already, create this
// node and stop coldboot. If this is a prefix matched
// partition, create device node and continue. For everything
// else skip the device node
if (found_meta && found_odm && found_system && found_vendor) {
ret = COLDBOOT_STOP;
} else if (create_this_node) {
ret = COLDBOOT_CREATE;
} else {
ret = COLDBOOT_CONTINUE;
}
return ret;
});
// early_device_init will remove found partitions from partition_names
// So if the partition_names is not empty here, means some partitions
// are not found
if (!partition_names.empty()) {
LOG(ERROR) << "early_mount: partition(s) not found: "
<< android::base::Join(partition_names, ", ");
goto done;
}
if (need_verity) {
// create /dev/device mapper
@ -839,10 +841,10 @@ static bool early_mount() {
[&](uevent* uevent) -> coldboot_action_t { return COLDBOOT_STOP; });
}
bool success = true;
if (odm_rec && !(success = early_mount_one(odm_rec))) goto done;
if (system_rec && !(success = early_mount_one(system_rec))) goto done;
if (vendor_rec && !(success = early_mount_one(vendor_rec))) goto done;
for (auto fstab_rec : early_fstab_recs) {
if (!early_mount_one(fstab_rec)) goto done;
}
success = true;
done:
device_close();