Merge "libfs_avb: support rollback protection for Live GSI"

am: 084d3b9124

Change-Id: Ib6ee19040dc0249a37ee7d8c8772a159c6922464
This commit is contained in:
Bowgo Tsai 2019-02-22 08:35:16 -08:00 committed by android-build-merger
commit 5d1bb2a41f
7 changed files with 252 additions and 46 deletions

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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_; }

View file

@ -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;

View file

@ -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

View file

@ -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 {