Merge "Fix preload partition failure behavior" am: 6259714f90

Change-Id: I53eaec63fb7b7c3932e7d06ab3e9ffec6836bb69
diff --git a/libavb/avb_slot_verify.c b/libavb/avb_slot_verify.c
index f107cf0..fc4c564 100644
--- a/libavb/avb_slot_verify.c
+++ b/libavb/avb_slot_verify.c
@@ -105,11 +105,11 @@
     }
 
     if (*out_image_buf != NULL) {
+      *out_image_preloaded = true;
       if (part_num_read != image_size) {
         avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL);
         return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
       }
-      *out_image_preloaded = true;
     }
   }
 
diff --git a/test/avb_slot_verify_unittest.cc b/test/avb_slot_verify_unittest.cc
index c516d24..680ea27 100644
--- a/test/avb_slot_verify_unittest.cc
+++ b/test/avb_slot_verify_unittest.cc
@@ -831,6 +831,64 @@
   avb_slot_verify_data_free(slot_data);
 }
 
+TEST_F(AvbSlotVerifyTest, SmallPreallocatedPreloadedPartitionFailGracefully) {
+  const size_t boot_partition_size = 16 * 1024 * 1024;
+  const size_t boot_image_size = 5 * 1024 * 1024;
+  // Generate vbmeta based on this boot image.
+  base::FilePath boot_path = GenerateImage("boot_a.img", boot_image_size);
+
+  // Preload smaller image than expected on the stack
+  // libavb should not attempt to free this buffer.
+  const size_t fake_preload_image_size = 1024;
+  uint8_t fake_preload_buf[fake_preload_image_size];
+
+  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()));
+
+  EXPECT_COMMAND(0,
+                 "./avbtool erase_footer"
+                 " --image %s",
+                 boot_path.value().c_str());
+
+  ops_.set_expected_public_key(
+      PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem")));
+  ops_.enable_get_preloaded_partition();
+  EXPECT_TRUE(ops_.preload_preallocated_partition(
+      "boot_a", fake_preload_buf, fake_preload_image_size));
+
+  AvbSlotVerifyData* slot_data = NULL;
+  const char* requested_partitions[] = {"boot", NULL};
+  EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_IO,
+            avb_slot_verify(ops_.avb_ops(),
+                            requested_partitions,
+                            "_a",
+                            AVB_SLOT_VERIFY_FLAGS_NONE,
+                            AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
+                            &slot_data));
+  EXPECT_EQ(nullptr, slot_data);
+}
+
 TEST_F(AvbSlotVerifyTest, HashDescriptorInVBMetaCorruptBoot) {
   size_t boot_partition_size = 16 * 1024 * 1024;
   base::FilePath boot_path = GenerateImage("boot_a.img", 5 * 1024 * 1024);
diff --git a/test/fake_avb_ops.cc b/test/fake_avb_ops.cc
index 6e8ab8c..0f4db5a 100644
--- a/test/fake_avb_ops.cc
+++ b/test/fake_avb_ops.cc
@@ -87,6 +87,18 @@
   return true;
 }
 
+bool FakeAvbOps::preload_preallocated_partition(const std::string& partition,
+                                                uint8_t* buffer,
+                                                size_t size) {
+  if (preallocated_preloaded_partitions_.count(partition) > 0) {
+    fprintf(stderr, "Partition '%s' already preloaded\n", partition.c_str());
+    return false;
+  }
+
+  preallocated_preloaded_partitions_[partition] = std::make_pair(buffer, size);
+  return true;
+}
+
 AvbIOResult FakeAvbOps::read_from_partition(const char* partition,
                                             int64_t offset,
                                             size_t num_bytes,
@@ -160,6 +172,15 @@
   if (hidden_partitions_.find(partition) != hidden_partitions_.end()) {
     return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
   }
+
+  std::map<std::string, std::pair<uint8_t*, size_t>>::iterator prealloc_it =
+      preallocated_preloaded_partitions_.find(std::string(partition));
+  if (prealloc_it != preallocated_preloaded_partitions_.end()) {
+    *out_pointer = prealloc_it->second.first;
+    *out_num_bytes_preloaded = std::min(prealloc_it->second.second, num_bytes);
+    return AVB_IO_RESULT_OK;
+  }
+
   std::map<std::string, uint8_t*>::iterator it =
       preloaded_partitions_.find(std::string(partition));
   if (it == preloaded_partitions_.end()) {
@@ -173,11 +194,8 @@
   if (result != AVB_IO_RESULT_OK) {
     return result;
   }
-  if (size != num_bytes) {
-    return AVB_IO_RESULT_ERROR_IO;
-  }
 
-  *out_num_bytes_preloaded = num_bytes;
+  *out_num_bytes_preloaded = std::min(static_cast<size_t>(size), num_bytes);
   *out_pointer = it->second;
   return AVB_IO_RESULT_OK;
 }
diff --git a/test/fake_avb_ops.h b/test/fake_avb_ops.h
index 2cc12d8..5dea5bd 100644
--- a/test/fake_avb_ops.h
+++ b/test/fake_avb_ops.h
@@ -211,6 +211,10 @@
   bool preload_partition(const std::string& partition,
                          const base::FilePath& path);
 
+  bool preload_preallocated_partition(const std::string& partition,
+                                      uint8_t* buffer,
+                                      size_t size);
+
   // Gets the partition names that were passed to the
   // read_from_partition() operation.
   std::set<std::string> get_partition_names_read_from();
@@ -315,6 +319,8 @@
 
   std::set<std::string> partition_names_read_from_;
   std::map<std::string, uint8_t*> preloaded_partitions_;
+  std::map<std::string, std::pair<uint8_t*, size_t>>
+      preallocated_preloaded_partitions_;
   std::set<std::string> hidden_partitions_;
 
   std::map<std::string, std::string> stored_values_;