Fix a bug that would cause OoB read.
Fix a bug when allow verification error and image size is smaller
than size in hash descriptor. The hash operation would read over
the image buffer.
Tests: Fuzzing errors before the change. Added test case
LoadSmallerPartitionIfAllowingVerificationError that would segment
fault before the change and pass after the change.
Bug: b/133258814
diff --git a/libavb/avb_slot_verify.c b/libavb/avb_slot_verify.c
index 8cfd80d..0ce881d 100644
--- a/libavb/avb_slot_verify.c
+++ b/libavb/avb_slot_verify.c
@@ -390,16 +390,22 @@
// used later.
AvbSHA256Ctx sha256_ctx;
AvbSHA512Ctx sha512_ctx;
+ size_t image_size_to_hash = hash_desc.image_size;
+ // If we allow verification error and the whole partition is smaller than
+ // image size in hash descriptor, we just hash the whole partition.
+ if (image_size_to_hash > image_size) {
+ image_size_to_hash = image_size;
+ }
if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) {
avb_sha256_init(&sha256_ctx);
avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len);
- avb_sha256_update(&sha256_ctx, image_buf, hash_desc.image_size);
+ avb_sha256_update(&sha256_ctx, image_buf, image_size_to_hash);
digest = avb_sha256_final(&sha256_ctx);
digest_len = AVB_SHA256_DIGEST_SIZE;
} else if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha512") == 0) {
avb_sha512_init(&sha512_ctx);
avb_sha512_update(&sha512_ctx, desc_salt, hash_desc.salt_len);
- avb_sha512_update(&sha512_ctx, image_buf, hash_desc.image_size);
+ avb_sha512_update(&sha512_ctx, image_buf, image_size_to_hash);
digest = avb_sha512_final(&sha512_ctx);
digest_len = AVB_SHA512_DIGEST_SIZE;
} else {
diff --git a/test/avb_slot_verify_unittest.cc b/test/avb_slot_verify_unittest.cc
index e03c37e..d27e6e0 100644
--- a/test/avb_slot_verify_unittest.cc
+++ b/test/avb_slot_verify_unittest.cc
@@ -478,6 +478,74 @@
avb_slot_verify_data_free(slot_data);
}
+TEST_F(AvbSlotVerifyTest, LoadSmallerPartitionIfAllowingVerificationError) {
+ const size_t boot_partition_size = 16 * 1024 * 1024;
+ const size_t boot_image_size = 5 * 1024 * 1024;
+ const size_t new_boot_image_size = 1 * 1024 * 1024;
+ base::FilePath boot_path = GenerateImage("boot_a.img", boot_image_size);
+
+ // If we're allowing verification errors then check that the whole
+ // partition is loaded. This is needed because in this mode for
+ // example the "boot" partition might be flashed with another
+ // boot.img that is larger than what the HashDescriptor in vbmeta
+ // says.
+ EXPECT_COMMAND(
+ 0,
+ "./avbtool add_hash_footer"
+ " --image %s"
+ " --rollback_index 0"
+ " --partition_name boot"
+ " --partition_size %zd"
+ " --kernel_cmdline 'cmdline in hash footer $(ANDROID_SYSTEM_PARTUUID)'"
+ " --salt deadbeef"
+ " --internal_release_string \"\"",
+ boot_path.value().c_str(),
+ boot_partition_size);
+
+ GenerateVBMetaImage(
+ "vbmeta_a.img",
+ "SHA256_RSA2048",
+ 4,
+ base::FilePath("test/data/testkey_rsa2048.pem"),
+ base::StringPrintf(
+ "--include_descriptors_from_image %s"
+ " --kernel_cmdline 'cmdline in vbmeta $(ANDROID_BOOT_PARTUUID)'"
+ " --internal_release_string \"\"",
+ boot_path.value().c_str()));
+
+ // Now replace the boot partition with something bigger and
+ // different. Because FakeOps's get_size_of_partition() operation
+ // just returns the file size it means that this is what is returned
+ // by get_size_of_partition().
+ //
+ // Also make sure this image will return a different digest by using
+ // a non-standard starting byte. This is to force avb_slot_verify()
+ // to return ERROR_VERIFICATION below.
+ GenerateImage("boot_a.img", new_boot_image_size, 1 /* start_byte */);
+
+ ops_.set_expected_public_key(
+ PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem")));
+
+ AvbSlotVerifyData* slot_data = NULL;
+ const char* requested_partitions[] = {"boot", NULL};
+ EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION,
+ avb_slot_verify(ops_.avb_ops(),
+ requested_partitions,
+ "_a",
+ AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR,
+ AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
+ &slot_data));
+ EXPECT_NE(nullptr, slot_data);
+
+ // Check that the loaded partition is actually
+ // |new_boot_image_size|.
+ EXPECT_EQ(size_t(1), slot_data->num_loaded_partitions);
+ EXPECT_EQ("boot",
+ std::string(slot_data->loaded_partitions[0].partition_name));
+ EXPECT_EQ(new_boot_image_size, slot_data->loaded_partitions[0].data_size);
+ avb_slot_verify_data_free(slot_data);
+}
+
TEST_F(AvbSlotVerifyTest, HashDescriptorInVBMeta) {
const size_t boot_partition_size = 16 * 1024 * 1024;
const size_t boot_image_size = 5 * 1024 * 1024;