Merge "libfs_avb: support rollback protection for Live GSI"
am: 084d3b9124
Change-Id: Ib6ee19040dc0249a37ee7d8c8772a159c6922464
This commit is contained in:
commit
5d1bb2a41f
7 changed files with 252 additions and 46 deletions
|
@ -34,6 +34,19 @@ using android::base::unique_fd;
|
|||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
std::string GetAvbPropertyDescriptor(const std::string& key,
|
||||
const std::vector<VBMetaData>& vbmeta_images) {
|
||||
size_t value_size;
|
||||
for (const auto& vbmeta : vbmeta_images) {
|
||||
const char* value = avb_property_lookup(vbmeta.data(), vbmeta.size(), key.data(),
|
||||
key.size(), &value_size);
|
||||
if (value != nullptr) {
|
||||
return {value, value_size};
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// Constructs dm-verity arguments for sending DM_TABLE_LOAD ioctl to kernel.
|
||||
// See the following link for more details:
|
||||
// https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity
|
||||
|
|
|
@ -37,6 +37,9 @@ struct ChainInfo {
|
|||
: partition_name(chain_partition_name), public_key_blob(chain_public_key_blob) {}
|
||||
};
|
||||
|
||||
std::string GetAvbPropertyDescriptor(const std::string& key,
|
||||
const std::vector<VBMetaData>& vbmeta_images);
|
||||
|
||||
// AvbHashtreeDescriptor to dm-verity table setup.
|
||||
std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
|
||||
const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images);
|
||||
|
|
|
@ -263,6 +263,69 @@ AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(
|
|||
return avb_handle;
|
||||
}
|
||||
|
||||
AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const FstabEntry& fstab_entry) {
|
||||
if (fstab_entry.avb_key.empty()) {
|
||||
LERROR << "avb_key=/path/to/key is missing for " << fstab_entry.mount_point;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Binds allow_verification_error and rollback_protection to device unlock state.
|
||||
bool allow_verification_error = IsDeviceUnlocked();
|
||||
bool rollback_protection = !allow_verification_error;
|
||||
|
||||
std::string expected_key_blob;
|
||||
if (!ReadFileToString(fstab_entry.avb_key, &expected_key_blob)) {
|
||||
if (!allow_verification_error) {
|
||||
LERROR << "Failed to load avb_key: " << fstab_entry.avb_key
|
||||
<< " for mount point: " << fstab_entry.mount_point;
|
||||
return nullptr;
|
||||
}
|
||||
LWARNING << "Allowing no expected key blob when verification error is permitted";
|
||||
expected_key_blob.clear();
|
||||
}
|
||||
|
||||
bool verification_disabled = false;
|
||||
VBMetaVerifyResult verify_result = VBMetaVerifyResult::kError;
|
||||
std::unique_ptr<VBMetaData> vbmeta = LoadAndVerifyVbmetaByPath(
|
||||
fstab_entry.blk_device, "" /* partition_name, no need for a standalone path */,
|
||||
expected_key_blob, allow_verification_error, rollback_protection,
|
||||
false /* not is_chained_vbmeta */, nullptr /* out_public_key_data */,
|
||||
&verification_disabled, &verify_result);
|
||||
|
||||
if (!vbmeta) {
|
||||
LERROR << "Failed to load vbmeta: " << fstab_entry.blk_device;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AvbUniquePtr avb_handle(new AvbHandle());
|
||||
if (!avb_handle) {
|
||||
LERROR << "Failed to allocate AvbHandle";
|
||||
return nullptr;
|
||||
}
|
||||
avb_handle->vbmeta_images_.emplace_back(std::move(*vbmeta));
|
||||
|
||||
switch (verify_result) {
|
||||
case VBMetaVerifyResult::kSuccess:
|
||||
avb_handle->status_ = AvbHandleStatus::kSuccess;
|
||||
break;
|
||||
case VBMetaVerifyResult::kErrorVerification:
|
||||
avb_handle->status_ = AvbHandleStatus::kVerificationError;
|
||||
break;
|
||||
default:
|
||||
LERROR << "LoadAndVerifyVbmetaByPath failed, result: " << verify_result;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (verification_disabled) {
|
||||
LINFO << "AVB verification disabled on: " << fstab_entry.mount_point;
|
||||
avb_handle->status_ = AvbHandleStatus::kVerificationDisabled;
|
||||
}
|
||||
|
||||
LINFO << "Returning avb_handle for '" << fstab_entry.mount_point
|
||||
<< "' with status: " << avb_handle->status_;
|
||||
return avb_handle;
|
||||
}
|
||||
|
||||
AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta() {
|
||||
// Loads inline vbmeta images, starting from /vbmeta.
|
||||
return LoadAndVerifyVbmeta("vbmeta", fs_mgr_get_slot_suffix(), fs_mgr_get_other_slot_suffix(),
|
||||
|
@ -358,52 +421,12 @@ AvbUniquePtr AvbHandle::Open() {
|
|||
|
||||
AvbHashtreeResult AvbHandle::SetUpStandaloneAvbHashtree(FstabEntry* fstab_entry,
|
||||
bool wait_for_verity_dev) {
|
||||
if (fstab_entry->avb_key.empty()) {
|
||||
LERROR << "avb_key=/path/to/key is missing for " << fstab_entry->mount_point;
|
||||
auto avb_handle = LoadAndVerifyVbmeta(*fstab_entry);
|
||||
if (!avb_handle) {
|
||||
return AvbHashtreeResult::kFail;
|
||||
}
|
||||
|
||||
// Binds allow_verification_error and rollback_protection to device unlock state.
|
||||
bool allow_verification_error = IsDeviceUnlocked();
|
||||
bool rollback_protection = !allow_verification_error;
|
||||
|
||||
std::string expected_key_blob;
|
||||
if (!ReadFileToString(fstab_entry->avb_key, &expected_key_blob)) {
|
||||
if (!allow_verification_error) {
|
||||
LERROR << "Failed to load avb_key: " << fstab_entry->avb_key
|
||||
<< " for mount point: " << fstab_entry->mount_point;
|
||||
return AvbHashtreeResult::kFail;
|
||||
}
|
||||
LWARNING << "Allowing no expected key blob when verification error is permitted";
|
||||
expected_key_blob.clear();
|
||||
}
|
||||
|
||||
bool verification_disabled = false;
|
||||
std::unique_ptr<VBMetaData> vbmeta = LoadAndVerifyVbmetaByPath(
|
||||
fstab_entry->blk_device, "" /* partition_name, no need for a standalone path */,
|
||||
expected_key_blob, allow_verification_error, rollback_protection,
|
||||
false /* not is_chained_vbmeta */, nullptr /* out_public_key_data */,
|
||||
&verification_disabled, nullptr /* out_verify_result */);
|
||||
|
||||
if (!vbmeta) {
|
||||
LERROR << "Failed to load vbmeta: " << fstab_entry->blk_device;
|
||||
return AvbHashtreeResult::kFail;
|
||||
}
|
||||
|
||||
if (verification_disabled) {
|
||||
LINFO << "AVB verification disabled on: " << fstab_entry->mount_point;
|
||||
return AvbHashtreeResult::kDisabled;
|
||||
}
|
||||
|
||||
// Puts the vbmeta into a vector, for LoadAvbHashtreeToEnableVerity() to use.
|
||||
std::vector<VBMetaData> vbmeta_images;
|
||||
vbmeta_images.emplace_back(std::move(*vbmeta));
|
||||
if (!LoadAvbHashtreeToEnableVerity(fstab_entry, wait_for_verity_dev, vbmeta_images,
|
||||
fs_mgr_get_slot_suffix(), fs_mgr_get_other_slot_suffix())) {
|
||||
return AvbHashtreeResult::kFail;
|
||||
}
|
||||
|
||||
return AvbHashtreeResult::kSuccess;
|
||||
return avb_handle->SetUpAvbHashtree(fstab_entry, wait_for_verity_dev);
|
||||
}
|
||||
|
||||
AvbHashtreeResult AvbHandle::SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait_for_verity_dev) {
|
||||
|
@ -425,5 +448,19 @@ AvbHashtreeResult AvbHandle::SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait
|
|||
return AvbHashtreeResult::kSuccess;
|
||||
}
|
||||
|
||||
std::string AvbHandle::GetSecurityPatchLevel(const FstabEntry& fstab_entry) const {
|
||||
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());
|
||||
auto avb_prop_name = "com.android.build." + avb_partition_name + ".security_patch";
|
||||
return GetAvbPropertyDescriptor(avb_prop_name, vbmeta_images_);
|
||||
}
|
||||
|
||||
bool AvbHandle::IsDeviceUnlocked() {
|
||||
return android::fs_mgr::IsDeviceUnlocked();
|
||||
}
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
||||
|
|
|
@ -85,6 +85,8 @@ 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.
|
||||
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,
|
||||
|
@ -108,6 +110,10 @@ class AvbHandle {
|
|||
static AvbHashtreeResult SetUpStandaloneAvbHashtree(FstabEntry* fstab_entry,
|
||||
bool wait_for_verity_dev = true);
|
||||
|
||||
static bool IsDeviceUnlocked();
|
||||
|
||||
std::string GetSecurityPatchLevel(const FstabEntry& fstab_entry) const;
|
||||
|
||||
const std::string& avb_version() const { return avb_version_; }
|
||||
const VBMetaInfo& vbmeta_info() const { return vbmeta_info_; }
|
||||
AvbHandleStatus status() const { return status_; }
|
||||
|
|
|
@ -30,6 +30,7 @@ using android::fs_mgr::AvbPartitionToDevicePatition;
|
|||
using android::fs_mgr::DeriveAvbPartitionName;
|
||||
using android::fs_mgr::FstabEntry;
|
||||
using android::fs_mgr::GetAvbFooter;
|
||||
using android::fs_mgr::GetAvbPropertyDescriptor;
|
||||
using android::fs_mgr::GetChainPartitionInfo;
|
||||
using android::fs_mgr::GetTotalSize;
|
||||
using android::fs_mgr::LoadAndVerifyVbmetaByPartition;
|
||||
|
@ -268,6 +269,67 @@ TEST_F(AvbUtilTest, GetAvbFooterInsufficientSize) {
|
|||
EXPECT_EQ(nullptr, footer);
|
||||
}
|
||||
|
||||
TEST_F(AvbUtilTest, GetAvbPropertyDescriptor_Basic) {
|
||||
// Makes a vbmeta.img with some properties.
|
||||
GenerateVBMetaImage("vbmeta.img", "SHA256_RSA4096", 0, data_dir_.Append("testkey_rsa4096.pem"),
|
||||
{}, /* include_descriptor_image_paths */
|
||||
{}, /* chain_partitions */
|
||||
"--prop foo:android "
|
||||
"--prop bar:treble "
|
||||
"--internal_release_string \"unit test\" ");
|
||||
auto vbmeta = LoadVBMetaData("vbmeta.img");
|
||||
|
||||
// Puts the vbmeta into a vector, for GetAvbPropertyDescriptor to use.
|
||||
std::vector<VBMetaData> vbmeta_images;
|
||||
vbmeta_images.emplace_back(std::move(vbmeta));
|
||||
|
||||
EXPECT_EQ("android", GetAvbPropertyDescriptor("foo", vbmeta_images));
|
||||
EXPECT_EQ("treble", GetAvbPropertyDescriptor("bar", vbmeta_images));
|
||||
EXPECT_EQ("", GetAvbPropertyDescriptor("non-existent", vbmeta_images));
|
||||
}
|
||||
|
||||
TEST_F(AvbUtilTest, GetAvbPropertyDescriptor_SecurityPatchLevel) {
|
||||
// Generates a raw boot.img
|
||||
const size_t boot_image_size = 5 * 1024 * 1024;
|
||||
const size_t boot_partition_size = 10 * 1024 * 1024;
|
||||
base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
|
||||
// Adds AVB Hash Footer.
|
||||
AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
|
||||
data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
|
||||
"--internal_release_string \"unit test\"");
|
||||
|
||||
// Generates a raw system.img, use a smaller size to speed-up unit test.
|
||||
const size_t system_image_size = 10 * 1024 * 1024;
|
||||
const size_t system_partition_size = 15 * 1024 * 1024;
|
||||
base::FilePath system_path = GenerateImage("system.img", system_image_size);
|
||||
// Adds AVB Hashtree Footer.
|
||||
AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
|
||||
data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
|
||||
"--prop com.android.build.system.security_patch:2019-04-05 "
|
||||
"--internal_release_string \"unit test\"");
|
||||
|
||||
// Generates chain partition descriptors.
|
||||
base::FilePath rsa4096_public_key =
|
||||
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
|
||||
|
||||
// Makes a vbmeta.img including the 'system' chained descriptor.
|
||||
GenerateVBMetaImage("vbmeta.img", "SHA256_RSA4096", 0, data_dir_.Append("testkey_rsa4096.pem"),
|
||||
{boot_path}, /* include_descriptor_image_paths */
|
||||
{{"system", 3, rsa4096_public_key}}, /* chain_partitions */
|
||||
"--internal_release_string \"unit test\"");
|
||||
|
||||
auto vbmeta = LoadVBMetaData("vbmeta.img");
|
||||
auto system_vbmeta = ExtractAndLoadVBMetaData(system_path, "system-vbmeta.img");
|
||||
|
||||
// Puts the vbmeta into a vector, for GetAvbPropertyDescriptor to use.
|
||||
std::vector<VBMetaData> vbmeta_images;
|
||||
vbmeta_images.emplace_back(std::move(vbmeta));
|
||||
vbmeta_images.emplace_back(std::move(system_vbmeta));
|
||||
|
||||
EXPECT_EQ("2019-04-05",
|
||||
GetAvbPropertyDescriptor("com.android.build.system.security_patch", vbmeta_images));
|
||||
}
|
||||
|
||||
TEST_F(AvbUtilTest, GetVBMetaHeader) {
|
||||
// Generates a raw boot.img
|
||||
const size_t image_size = 5 * 1024 * 1024;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
#include <android-base/properties.h>
|
||||
#include <fs_avb/fs_avb.h>
|
||||
#include <fs_avb/fs_avb_util.h>
|
||||
#include <fstab/fstab.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
@ -22,6 +23,8 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using android::fs_mgr::AvbHandle;
|
||||
using android::fs_mgr::AvbHandleStatus;
|
||||
using android::fs_mgr::Fstab;
|
||||
using android::fs_mgr::FstabEntry;
|
||||
using android::fs_mgr::VBMetaData;
|
||||
|
@ -31,7 +34,7 @@ namespace fs_avb_device_test {
|
|||
|
||||
// system vbmeta might not be at the end of /system when dynamic partition is
|
||||
// enabled. Therefore, disable it by default.
|
||||
TEST(PublicFsAvbDeviceTest, DISABLED_LoadAndVerifyVbmeta_SystemVbmeta) {
|
||||
TEST(FsAvbUtilTest, DISABLED_LoadAndVerifyVbmeta_SystemVbmeta) {
|
||||
Fstab fstab;
|
||||
EXPECT_TRUE(ReadDefaultFstab(&fstab));
|
||||
|
||||
|
@ -51,7 +54,7 @@ TEST(PublicFsAvbDeviceTest, DISABLED_LoadAndVerifyVbmeta_SystemVbmeta) {
|
|||
EXPECT_NE("", out_public_key_data);
|
||||
}
|
||||
|
||||
TEST(PublicFsAvbDeviceTest, GetHashtreeDescriptor_SystemOther) {
|
||||
TEST(FsAvbUtilTest, GetHashtreeDescriptor_SystemOther) {
|
||||
// Non-A/B device doesn't have system_other partition.
|
||||
if (fs_mgr_get_slot_suffix() == "") return;
|
||||
|
||||
|
@ -90,4 +93,55 @@ TEST(PublicFsAvbDeviceTest, GetHashtreeDescriptor_SystemOther) {
|
|||
EXPECT_NE(nullptr, hashtree_desc);
|
||||
}
|
||||
|
||||
TEST(AvbHandleTest, LoadAndVerifyVbmeta_SystemOther) {
|
||||
// Non-A/B device doesn't have system_other partition.
|
||||
if (fs_mgr_get_slot_suffix() == "") return;
|
||||
|
||||
// Skip running this test if system_other is a logical partition.
|
||||
// Note that system_other is still a physical partition on "retrofit" devices.
|
||||
if (android::base::GetBoolProperty("ro.boot.dynamic_partitions", false) &&
|
||||
!android::base::GetBoolProperty("ro.boot.dynamic_partitions_retrofit", false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Fstab fstab;
|
||||
EXPECT_TRUE(ReadFstabFromFile("/system/etc/fstab.postinstall", &fstab));
|
||||
|
||||
// It should have two lines in the fstab, the first for logical system_other,
|
||||
// the other for physical system_other.
|
||||
EXPECT_EQ(2UL, fstab.size());
|
||||
|
||||
// Use the 2nd fstab entry, which is for physical system_other partition.
|
||||
FstabEntry* system_other_entry = &fstab[1];
|
||||
// Assign the default key if it's not specified in the fstab.
|
||||
if (system_other_entry->avb_key.empty()) {
|
||||
system_other_entry->avb_key = "/system/etc/security/avb/system_other.avbpubkey";
|
||||
}
|
||||
auto avb_handle = AvbHandle::LoadAndVerifyVbmeta(*system_other_entry);
|
||||
EXPECT_NE(nullptr, avb_handle) << "Failed to load system_other vbmeta. Try 'adb root'?";
|
||||
EXPECT_EQ(AvbHandleStatus::kSuccess, avb_handle->status());
|
||||
}
|
||||
|
||||
TEST(AvbHandleTest, GetSecurityPatchLevel) {
|
||||
Fstab fstab;
|
||||
EXPECT_TRUE(ReadDefaultFstab(&fstab));
|
||||
|
||||
auto avb_handle = AvbHandle::LoadAndVerifyVbmeta();
|
||||
EXPECT_NE(nullptr, avb_handle) << "Failed to load inline vbmeta. Try 'adb root'?";
|
||||
EXPECT_EQ(AvbHandleStatus::kSuccess, avb_handle->status());
|
||||
|
||||
// Gets security patch level with format: YYYY-MM-DD (e.g., 2019-04-05).
|
||||
FstabEntry* system_entry = GetEntryForMountPoint(&fstab, "/system");
|
||||
EXPECT_NE(nullptr, system_entry);
|
||||
EXPECT_EQ(10UL, avb_handle->GetSecurityPatchLevel(*system_entry).length());
|
||||
|
||||
FstabEntry* vendor_entry = GetEntryForMountPoint(&fstab, "/vendor");
|
||||
EXPECT_NE(nullptr, vendor_entry);
|
||||
EXPECT_EQ(10UL, avb_handle->GetSecurityPatchLevel(*vendor_entry).length());
|
||||
|
||||
FstabEntry* product_entry = GetEntryForMountPoint(&fstab, "/product");
|
||||
EXPECT_NE(nullptr, product_entry);
|
||||
EXPECT_EQ(10UL, avb_handle->GetSecurityPatchLevel(*product_entry).length());
|
||||
}
|
||||
|
||||
} // namespace fs_avb_device_test
|
||||
|
|
|
@ -189,6 +189,29 @@ static bool GetRootEntry(FstabEntry* root_entry) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool IsStandaloneImageRollback(const AvbHandle& builtin_vbmeta,
|
||||
const AvbHandle& standalone_vbmeta,
|
||||
const FstabEntry& fstab_entry) {
|
||||
std::string old_spl = builtin_vbmeta.GetSecurityPatchLevel(fstab_entry);
|
||||
std::string new_spl = standalone_vbmeta.GetSecurityPatchLevel(fstab_entry);
|
||||
|
||||
bool rollbacked = false;
|
||||
if (old_spl.empty() || new_spl.empty() || new_spl < old_spl) {
|
||||
rollbacked = true;
|
||||
}
|
||||
|
||||
if (rollbacked) {
|
||||
LOG(ERROR) << "Image rollback detected for " << fstab_entry.mount_point
|
||||
<< ", SPL switches from '" << old_spl << "' to '" << new_spl << "'";
|
||||
if (AvbHandle::IsDeviceUnlocked()) {
|
||||
LOG(INFO) << "Allowing rollbacked standalone image when the device is unlocked";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return rollbacked;
|
||||
}
|
||||
|
||||
// Class Definitions
|
||||
// -----------------
|
||||
FirstStageMount::FirstStageMount(Fstab fstab)
|
||||
|
@ -746,7 +769,15 @@ bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) {
|
|||
<< fstab_entry->mount_point;
|
||||
return true; // Returns true to mount the partition directly.
|
||||
} else {
|
||||
hashtree_result = AvbHandle::SetUpStandaloneAvbHashtree(
|
||||
auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(*fstab_entry);
|
||||
if (!avb_standalone_handle) {
|
||||
LOG(ERROR) << "Failed to load offline vbmeta for " << fstab_entry->mount_point;
|
||||
return false;
|
||||
}
|
||||
if (IsStandaloneImageRollback(*avb_handle_, *avb_standalone_handle, *fstab_entry)) {
|
||||
return false;
|
||||
}
|
||||
hashtree_result = avb_standalone_handle->SetUpAvbHashtree(
|
||||
fstab_entry, false /* wait_for_verity_dev */);
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue