libfs_avb: Allow overriding the slot suffix.

There is no easy way to override fs_mgr_get_slot_suffix for testing or
for simulating slot switches. It relies on global properties, and
since fstab is usually a static library, linked multiple times, we can't
just stick a global variable in fs_mgr_slotselect.

libfs_avb already takes slot suffix arguments in various places. This CL
extends that by adding arguments to AvbHandle and FsManagerAvbOps.

Bug: N/A
Test: snapshotctl
Change-Id: Ide7f052b38249d6bc79a6a2c124baf8ca08bcc3b
This commit is contained in:
David Anderson 2023-05-12 10:09:23 -07:00
parent 1cf0e90409
commit 0ff0eeed77
6 changed files with 48 additions and 14 deletions

View file

@ -108,8 +108,8 @@ static AvbIOResult get_size_of_partition(AvbOps* ops ATTRIBUTE_UNUSED,
// Converts a partition name (with ab_suffix) to the corresponding mount point.
// e.g., "system_a" => "/system",
// e.g., "vendor_a" => "/vendor",
static std::string DeriveMountPoint(const std::string& partition_name) {
const std::string ab_suffix = fs_mgr_get_slot_suffix();
static std::string DeriveMountPoint(const std::string& partition_name,
const std::string& ab_suffix) {
std::string mount_point(partition_name);
auto found = partition_name.rfind(ab_suffix);
if (found != std::string::npos) {
@ -119,7 +119,7 @@ static std::string DeriveMountPoint(const std::string& partition_name) {
return "/" + mount_point;
}
FsManagerAvbOps::FsManagerAvbOps() {
FsManagerAvbOps::FsManagerAvbOps(const std::string& slot_suffix) {
// We only need to provide the implementation of read_from_partition()
// operation since that's all what is being used by the avb_slot_verify().
// Other I/O operations are only required in bootloader but not in
@ -135,6 +135,11 @@ FsManagerAvbOps::FsManagerAvbOps() {
// Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps.
avb_ops_.user_data = this;
slot_suffix_ = slot_suffix;
if (slot_suffix_.empty()) {
slot_suffix_ = fs_mgr_get_slot_suffix();
}
}
// Given a partition name (with ab_suffix), e.g., system_a, returns the corresponding
@ -149,7 +154,7 @@ std::string FsManagerAvbOps::GetLogicalPath(const std::string& partition_name) {
return "";
}
const auto mount_point = DeriveMountPoint(partition_name);
const auto mount_point = DeriveMountPoint(partition_name, slot_suffix_);
if (mount_point.empty()) return "";
auto fstab_entry = GetEntryForMountPoint(&fstab_, mount_point);

View file

@ -48,7 +48,7 @@ namespace fs_mgr {
//
class FsManagerAvbOps {
public:
FsManagerAvbOps();
explicit FsManagerAvbOps(const std::string& slot_suffix = {});
static FsManagerAvbOps* GetInstanceFromAvbOps(AvbOps* ops) {
return reinterpret_cast<FsManagerAvbOps*>(ops->user_data);
@ -66,6 +66,7 @@ class FsManagerAvbOps {
std::string GetPartitionPath(const char* partition_name);
AvbOps avb_ops_;
Fstab fstab_;
std::string slot_suffix_;
};
} // namespace fs_mgr

View file

@ -182,6 +182,11 @@ bool AvbVerifier::VerifyVbmetaImages(const std::vector<VBMetaData>& vbmeta_image
// class AvbHandle
// ---------------
AvbHandle::AvbHandle() : status_(AvbHandleStatus::kUninitialized) {
slot_suffix_ = fs_mgr_get_slot_suffix();
other_slot_suffix_ = fs_mgr_get_other_slot_suffix();
}
AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(
const std::string& partition_name, const std::string& ab_suffix,
const std::string& ab_other_suffix, const std::string& expected_public_key_path,
@ -194,6 +199,9 @@ AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(
return nullptr;
}
avb_handle->slot_suffix_ = ab_suffix;
avb_handle->other_slot_suffix_ = ab_other_suffix;
std::string expected_key_blob;
if (!expected_public_key_path.empty()) {
if (access(expected_public_key_path.c_str(), F_OK) != 0) {
@ -373,9 +381,14 @@ AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const FstabEntry& fstab_entry,
return avb_handle;
}
AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta() {
AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const std::string& slot_suffix) {
// Loads inline vbmeta images, starting from /vbmeta.
return LoadAndVerifyVbmeta("vbmeta", fs_mgr_get_slot_suffix(), fs_mgr_get_other_slot_suffix(),
auto suffix = slot_suffix;
if (suffix.empty()) {
suffix = fs_mgr_get_slot_suffix();
}
auto other_suffix = android::fs_mgr::OtherSlotSuffix(suffix);
return LoadAndVerifyVbmeta("vbmeta", suffix, other_suffix,
{} /* expected_public_key, already checked by bootloader */,
HashAlgorithm::kSHA256,
IsAvbPermissive(), /* allow_verification_error */
@ -399,7 +412,7 @@ AvbUniquePtr AvbHandle::Open() {
? AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR
: AVB_SLOT_VERIFY_FLAGS_NONE;
AvbSlotVerifyResult verify_result =
avb_ops.AvbSlotVerify(fs_mgr_get_slot_suffix(), flags, &avb_handle->vbmeta_images_);
avb_ops.AvbSlotVerify(avb_handle->slot_suffix_, flags, &avb_handle->vbmeta_images_);
// Only allow the following verify results:
// - AVB_SLOT_VERIFY_RESULT_OK.
@ -492,7 +505,7 @@ AvbHashtreeResult AvbHandle::SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait
}
if (!LoadAvbHashtreeToEnableVerity(fstab_entry, wait_for_verity_dev, vbmeta_images_,
fs_mgr_get_slot_suffix(), fs_mgr_get_other_slot_suffix())) {
slot_suffix_, other_slot_suffix_)) {
return AvbHashtreeResult::kFail;
}
@ -526,8 +539,8 @@ std::string AvbHandle::GetSecurityPatchLevel(const FstabEntry& fstab_entry) cons
if (vbmeta_images_.size() < 1) {
return "";
}
std::string avb_partition_name = DeriveAvbPartitionName(fstab_entry, fs_mgr_get_slot_suffix(),
fs_mgr_get_other_slot_suffix());
std::string avb_partition_name =
DeriveAvbPartitionName(fstab_entry, slot_suffix_, other_slot_suffix_);
auto avb_prop_name = "com.android.build." + avb_partition_name + ".security_patch";
return GetAvbPropertyDescriptor(avb_prop_name, vbmeta_images_);
}

View file

@ -83,8 +83,8 @@ class AvbHandle {
// is verified and can be trusted.
//
// TODO(bowgotsai): remove Open() and switch to LoadAndVerifyVbmeta().
static AvbUniquePtr Open(); // loads inline vbmeta, via libavb.
static AvbUniquePtr LoadAndVerifyVbmeta(); // loads inline vbmeta.
static AvbUniquePtr Open(); // loads inline vbmeta, via libavb.
static AvbUniquePtr LoadAndVerifyVbmeta(const std::string& slot_suffix = {});
// 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.
@ -137,12 +137,14 @@ class AvbHandle {
AvbHandle& operator=(AvbHandle&&) noexcept = delete; // no move assignment
private:
AvbHandle() : status_(AvbHandleStatus::kUninitialized) {}
AvbHandle();
std::vector<VBMetaData> vbmeta_images_;
VBMetaInfo vbmeta_info_; // A summary info for vbmeta_images_.
AvbHandleStatus status_;
std::string avb_version_;
std::string slot_suffix_;
std::string other_slot_suffix_;
};
} // namespace fs_mgr

View file

@ -145,5 +145,8 @@ void ImportKernelCmdline(const std::function<void(std::string, std::string)>& fn
// Otherwise returns false and |*out| is not modified.
bool GetKernelCmdline(const std::string& key, std::string* out);
// Return the "other" slot for the given slot suffix.
std::string OtherSlotSuffix(const std::string& suffix);
} // namespace fs_mgr
} // namespace android

View file

@ -74,3 +74,13 @@ bool fs_mgr_update_for_slotselect(Fstab* fstab) {
}
return true;
}
namespace android {
namespace fs_mgr {
std::string OtherSlotSuffix(const std::string& suffix) {
return other_suffix(suffix);
}
} // namespace fs_mgr
} // namespace android