Generate verity config.
am: 3a4dfac2bc

Change-Id: Ieed6401900ddbf63f870475a6ebecad87c19eeba
diff --git a/Android.mk b/Android.mk
index ba66d67..4d306c4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -626,10 +626,11 @@
 # server-side code. This is used for delta_generator and unittests but not
 # for any client code.
 ue_libpayload_generator_exported_static_libraries := \
+    libavb \
+    libbrotli \
     libbsdiff \
     libdivsufsort \
     libdivsufsort64 \
-    libbrotli \
     liblzma \
     libpayload_consumer \
     libpuffdiff \
@@ -661,6 +662,7 @@
     payload_generator/inplace_generator.cc \
     payload_generator/mapfile_filesystem.cc \
     payload_generator/payload_file.cc \
+    payload_generator/payload_generation_config_android.cc \
     payload_generator/payload_generation_config.cc \
     payload_generator/payload_signer.cc \
     payload_generator/raw_filesystem.cc \
@@ -680,6 +682,7 @@
 LOCAL_LDFLAGS := $(ue_common_ldflags)
 LOCAL_C_INCLUDES := $(ue_common_c_includes)
 LOCAL_STATIC_LIBRARIES := \
+    libavb \
     libbsdiff \
     libdivsufsort \
     libdivsufsort64 \
@@ -709,6 +712,7 @@
 LOCAL_LDFLAGS := $(ue_common_ldflags)
 LOCAL_C_INCLUDES := $(ue_common_c_includes)
 LOCAL_STATIC_LIBRARIES := \
+    libavb \
     libbsdiff \
     libdivsufsort \
     libdivsufsort64 \
@@ -743,6 +747,7 @@
 LOCAL_LDFLAGS := $(ue_common_ldflags)
 LOCAL_C_INCLUDES := $(ue_common_c_includes)
 LOCAL_STATIC_LIBRARIES := \
+    libavb_host_sysdeps \
     libpayload_consumer \
     libpayload_generator \
     $(ue_common_static_libraries) \
diff --git a/payload_consumer/payload_constants.cc b/payload_consumer/payload_constants.cc
index 6e7cd00..dacd9fb 100644
--- a/payload_consumer/payload_constants.cc
+++ b/payload_consumer/payload_constants.cc
@@ -30,6 +30,7 @@
 const uint32_t kOpSrcHashMinorPayloadVersion = 3;
 const uint32_t kBrotliBsdiffMinorPayloadVersion = 4;
 const uint32_t kPuffdiffMinorPayloadVersion = 5;
+const uint32_t kVerityMinorPayloadVersion = 6;
 
 const uint64_t kMinSupportedMajorPayloadVersion = 1;
 const uint64_t kMaxSupportedMajorPayloadVersion = 2;
diff --git a/payload_consumer/payload_constants.h b/payload_consumer/payload_constants.h
index 0833484..7f76898 100644
--- a/payload_consumer/payload_constants.h
+++ b/payload_consumer/payload_constants.h
@@ -53,6 +53,9 @@
 // The minor version that allows PUFFDIFF operation.
 extern const uint32_t kPuffdiffMinorPayloadVersion;
 
+// The minor version that allows Verity hash tree and FEC generation.
+extern const uint32_t kVerityMinorPayloadVersion;
+
 // The minimum and maximum supported minor version.
 extern const uint32_t kMinSupportedMinorPayloadVersion;
 extern const uint32_t kMaxSupportedMinorPayloadVersion;
diff --git a/payload_generator/delta_diff_utils.cc b/payload_generator/delta_diff_utils.cc
index 75d1016..9d14474 100644
--- a/payload_generator/delta_diff_utils.cc
+++ b/payload_generator/delta_diff_utils.cc
@@ -299,6 +299,17 @@
   ExtentRanges old_visited_blocks;
   ExtentRanges new_visited_blocks;
 
+  // If verity is enabled, mark those blocks as visited to skip generating
+  // operations for them.
+  if (version.minor >= kVerityMinorPayloadVersion &&
+      !new_part.verity.IsEmpty()) {
+    LOG(INFO) << "Skipping verity hash tree blocks: "
+              << ExtentsToString({new_part.verity.hash_tree_extent});
+    new_visited_blocks.AddExtent(new_part.verity.hash_tree_extent);
+    // TODO(senj): Enable this when we have FEC support.
+    // new_visited_blocks.AddExtent(new_part.verity.fec_extent);
+  }
+
   TEST_AND_RETURN_FALSE(DeltaMovedAndZeroBlocks(
       aops,
       old_part.path,
diff --git a/payload_generator/delta_diff_utils_unittest.cc b/payload_generator/delta_diff_utils_unittest.cc
index a83cea2..07aa3a8 100644
--- a/payload_generator/delta_diff_utils_unittest.cc
+++ b/payload_generator/delta_diff_utils_unittest.cc
@@ -161,6 +161,28 @@
   ExtentRanges new_visited_blocks_;
 };
 
+TEST_F(DeltaDiffUtilsTest, SkipVerityExtentsTest) {
+  new_part_.verity.hash_tree_extent = ExtentForRange(20, 30);
+
+  BlobFileWriter blob_file(blob_fd_, &blob_size_);
+  EXPECT_TRUE(diff_utils::DeltaReadPartition(
+      &aops_,
+      old_part_,
+      new_part_,
+      -1,
+      -1,
+      PayloadVersion(kMaxSupportedMajorPayloadVersion,
+                     kVerityMinorPayloadVersion),
+      &blob_file));
+  for (const auto& aop : aops_) {
+    new_visited_blocks_.AddRepeatedExtents(aop.op.dst_extents());
+  }
+  for (const auto& extent : new_visited_blocks_.extent_set()) {
+    EXPECT_FALSE(ExtentRanges::ExtentsOverlap(
+        extent, new_part_.verity.hash_tree_extent));
+  }
+}
+
 TEST_F(DeltaDiffUtilsTest, MoveSmallTest) {
   brillo::Blob data_blob(block_size_);
   test_utils::FillWithData(&data_blob);
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index b842f33..eecb345 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -589,6 +589,9 @@
 
   payload_config.max_timestamp = FLAGS_max_timestamp;
 
+  if (payload_config.version.minor >= kVerityMinorPayloadVersion)
+    CHECK(payload_config.target.LoadVerityConfig());
+
   LOG(INFO) << "Generating " << (payload_config.is_delta ? "delta" : "full")
             << " update";
 
diff --git a/payload_generator/payload_file.cc b/payload_generator/payload_file.cc
index d5c59ce..0ffd3e2 100644
--- a/payload_generator/payload_file.cc
+++ b/payload_generator/payload_file.cc
@@ -20,6 +20,7 @@
 
 #include <algorithm>
 #include <map>
+#include <utility>
 
 #include <base/strings/stringprintf.h>
 
@@ -91,6 +92,7 @@
   part.name = new_conf.name;
   part.aops = aops;
   part.postinstall = new_conf.postinstall;
+  part.verity = new_conf.verity;
   // Initialize the PartitionInfo objects if present.
   if (!old_conf.path.empty())
     TEST_AND_RETURN_FALSE(diff_utils::InitializePartitionInfo(old_conf,
@@ -144,6 +146,22 @@
           partition->set_filesystem_type(part.postinstall.filesystem_type);
         partition->set_postinstall_optional(part.postinstall.optional);
       }
+      if (!part.verity.IsEmpty()) {
+        if (part.verity.hash_tree_extent.num_blocks() != 0) {
+          *partition->mutable_hash_tree_data_extent() =
+              part.verity.hash_tree_data_extent;
+          *partition->mutable_hash_tree_extent() = part.verity.hash_tree_extent;
+          partition->set_hash_tree_algorithm(part.verity.hash_tree_algorithm);
+          if (!part.verity.hash_tree_salt.empty())
+            partition->set_hash_tree_salt(part.verity.hash_tree_salt.data(),
+                                          part.verity.hash_tree_salt.size());
+        }
+        if (part.verity.fec_extent.num_blocks() != 0) {
+          *partition->mutable_fec_data_extent() = part.verity.fec_data_extent;
+          *partition->mutable_fec_extent() = part.verity.fec_extent;
+          partition->set_fec_roots(part.verity.fec_roots);
+        }
+      }
       for (const AnnotatedOperation& aop : part.aops) {
         *partition->add_operations() = aop.op;
       }
diff --git a/payload_generator/payload_file.h b/payload_generator/payload_file.h
index 7cc792a..9dc80a7 100644
--- a/payload_generator/payload_file.h
+++ b/payload_generator/payload_file.h
@@ -95,6 +95,7 @@
     PartitionInfo new_info;
 
     PostInstallConfig postinstall;
+    VerityConfig verity;
   };
 
   std::vector<Partition> part_vec_;
diff --git a/payload_generator/payload_generation_config.cc b/payload_generator/payload_generation_config.cc
index 5fe56b5..c49fdb5 100644
--- a/payload_generator/payload_generation_config.cc
+++ b/payload_generator/payload_generation_config.cc
@@ -33,6 +33,13 @@
   return !run && path.empty() && filesystem_type.empty() && !optional;
 }
 
+bool VerityConfig::IsEmpty() const {
+  return hash_tree_data_extent.num_blocks() == 0 &&
+         hash_tree_extent.num_blocks() == 0 && hash_tree_algorithm.empty() &&
+         hash_tree_salt.empty() && fec_data_extent.num_blocks() == 0 &&
+         fec_extent.num_blocks() == 0 && fec_roots == 0;
+}
+
 bool PartitionConfig::ValidateExists() const {
   TEST_AND_RETURN_FALSE(!path.empty());
   TEST_AND_RETURN_FALSE(utils::FileExists(path.c_str()));
@@ -136,7 +143,8 @@
                         minor == kSourceMinorPayloadVersion ||
                         minor == kOpSrcHashMinorPayloadVersion ||
                         minor == kBrotliBsdiffMinorPayloadVersion ||
-                        minor == kPuffdiffMinorPayloadVersion);
+                        minor == kPuffdiffMinorPayloadVersion ||
+                        minor == kVerityMinorPayloadVersion);
   return true;
 }
 
@@ -199,8 +207,9 @@
         TEST_AND_RETURN_FALSE(part.ValidateExists());
         TEST_AND_RETURN_FALSE(part.size % block_size == 0);
       }
-      // Source partition should not have postinstall.
+      // Source partition should not have postinstall or verity config.
       TEST_AND_RETURN_FALSE(part.postinstall.IsEmpty());
+      TEST_AND_RETURN_FALSE(part.verity.IsEmpty());
     }
 
     // If new_image_info is present, old_image_info must be present.
@@ -220,6 +229,8 @@
       TEST_AND_RETURN_FALSE(rootfs_partition_size >= part.size);
     if (version.major == kChromeOSMajorPayloadVersion)
       TEST_AND_RETURN_FALSE(part.postinstall.IsEmpty());
+    if (version.minor < kVerityMinorPayloadVersion)
+      TEST_AND_RETURN_FALSE(part.verity.IsEmpty());
   }
 
   TEST_AND_RETURN_FALSE(hard_chunk_size == -1 ||
diff --git a/payload_generator/payload_generation_config.h b/payload_generator/payload_generation_config.h
index 358a76d..38e7b10 100644
--- a/payload_generator/payload_generation_config.h
+++ b/payload_generator/payload_generation_config.h
@@ -24,6 +24,7 @@
 #include <vector>
 
 #include <brillo/key_value_store.h>
+#include <brillo/secure_blob.h>
 
 #include "update_engine/payload_consumer/payload_constants.h"
 #include "update_engine/payload_generator/filesystem_interface.h"
@@ -51,6 +52,34 @@
   bool optional = false;
 };
 
+// Data will be written to the payload and used for hash tree and FEC generation
+// at device update time.
+struct VerityConfig {
+  // Whether the verity config is empty.
+  bool IsEmpty() const;
+
+  // The extent for data covered by verity hash tree.
+  Extent hash_tree_data_extent;
+
+  // The extent to store verity hash tree.
+  Extent hash_tree_extent;
+
+  // The hash algorithm used in verity hash tree.
+  std::string hash_tree_algorithm;
+
+  // The salt used for verity hash tree.
+  brillo::Blob hash_tree_salt;
+
+  // The extent for data covered by FEC.
+  Extent fec_data_extent;
+
+  // The extent to store FEC.
+  Extent fec_extent;
+
+  // The number of FEC roots.
+  uint32_t fec_roots = 0;
+};
+
 struct PartitionConfig {
   explicit PartitionConfig(std::string name) : name(name) {}
 
@@ -86,6 +115,7 @@
   std::string name;
 
   PostInstallConfig postinstall;
+  VerityConfig verity;
 };
 
 // The ImageConfig struct describes a pair of binaries kernel and rootfs and the
@@ -104,6 +134,9 @@
   // Load postinstall config from a key value store.
   bool LoadPostInstallConfig(const brillo::KeyValueStore& store);
 
+  // Load verity config by parsing the partition images.
+  bool LoadVerityConfig();
+
   // Returns whether the |image_info| field is empty.
   bool ImageInfoIsEmpty() const;
 
diff --git a/payload_generator/payload_generation_config_android.cc b/payload_generator/payload_generation_config_android.cc
new file mode 100644
index 0000000..5ffd11e
--- /dev/null
+++ b/payload_generator/payload_generation_config_android.cc
@@ -0,0 +1,96 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/payload_generator/payload_generation_config.h"
+
+#include <base/logging.h>
+#include <brillo/secure_blob.h>
+#include <libavb/libavb.h>
+
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+
+namespace chromeos_update_engine {
+
+namespace {
+bool AvbDescriptorCallback(const AvbDescriptor* descriptor, void* user_data) {
+  PartitionConfig* part = static_cast<PartitionConfig*>(user_data);
+  AvbDescriptor desc;
+  TEST_AND_RETURN_FALSE(
+      avb_descriptor_validate_and_byteswap(descriptor, &desc));
+  if (desc.tag != AVB_DESCRIPTOR_TAG_HASHTREE)
+    return true;
+
+  AvbHashtreeDescriptor hashtree;
+  TEST_AND_RETURN_FALSE(avb_hashtree_descriptor_validate_and_byteswap(
+      reinterpret_cast<const AvbHashtreeDescriptor*>(descriptor), &hashtree));
+  // We only support version 1 right now, will need to introduce a new
+  // payload minor version to support new dm verity version.
+  TEST_AND_RETURN_FALSE(hashtree.dm_verity_version == 1);
+  part->verity.hash_tree_algorithm =
+      reinterpret_cast<const char*>(hashtree.hash_algorithm);
+
+  const uint8_t* salt = reinterpret_cast<const uint8_t*>(descriptor) +
+                        sizeof(AvbHashtreeDescriptor) +
+                        hashtree.partition_name_len;
+  part->verity.hash_tree_salt.assign(salt, salt + hashtree.salt_len);
+
+  TEST_AND_RETURN_FALSE(hashtree.data_block_size ==
+                        part->fs_interface->GetBlockSize());
+  part->verity.hash_tree_data_extent =
+      ExtentForBytes(hashtree.data_block_size, 0, hashtree.image_size);
+
+  TEST_AND_RETURN_FALSE(hashtree.hash_block_size ==
+                        part->fs_interface->GetBlockSize());
+  part->verity.hash_tree_extent = ExtentForBytes(
+      hashtree.hash_block_size, hashtree.tree_offset, hashtree.tree_size);
+
+  part->verity.fec_data_extent =
+      ExtentForBytes(hashtree.data_block_size, 0, hashtree.fec_offset);
+  part->verity.fec_extent = ExtentForBytes(
+      hashtree.data_block_size, hashtree.fec_offset, hashtree.fec_size);
+  part->verity.fec_roots = hashtree.fec_num_roots;
+  return true;
+}
+}  // namespace
+
+bool ImageConfig::LoadVerityConfig() {
+  for (PartitionConfig& part : partitions) {
+    if (part.size < sizeof(AvbFooter))
+      continue;
+    uint64_t footer_offset = part.size - sizeof(AvbFooter);
+    brillo::Blob buffer;
+    TEST_AND_RETURN_FALSE(utils::ReadFileChunk(
+        part.path, footer_offset, sizeof(AvbFooter), &buffer));
+    if (memcmp(buffer.data(), AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN) != 0)
+      continue;
+    LOG(INFO) << "Parsing verity config from AVB footer for " << part.name;
+    AvbFooter footer;
+    TEST_AND_RETURN_FALSE(avb_footer_validate_and_byteswap(
+        reinterpret_cast<const AvbFooter*>(buffer.data()), &footer));
+    buffer.clear();
+
+    TEST_AND_RETURN_FALSE(footer.vbmeta_offset + sizeof(AvbVBMetaImageHeader) <=
+                          part.size);
+    TEST_AND_RETURN_FALSE(utils::ReadFileChunk(
+        part.path, footer.vbmeta_offset, footer.vbmeta_size, &buffer));
+    TEST_AND_RETURN_FALSE(avb_descriptor_foreach(
+        buffer.data(), buffer.size(), AvbDescriptorCallback, &part));
+  }
+  return true;
+}
+
+}  // namespace chromeos_update_engine
diff --git a/payload_generator/payload_generation_config_chromeos.cc b/payload_generator/payload_generation_config_chromeos.cc
new file mode 100644
index 0000000..bb05aff
--- /dev/null
+++ b/payload_generator/payload_generation_config_chromeos.cc
@@ -0,0 +1,25 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/payload_generator/payload_generation_config.h"
+
+namespace chromeos_update_engine {
+
+bool ImageConfig::LoadVerityConfig() {
+  return true;
+}
+
+}  // namespace chromeos_update_engine
diff --git a/update_engine.gyp b/update_engine.gyp
index 45b0a84..c90c018 100644
--- a/update_engine.gyp
+++ b/update_engine.gyp
@@ -411,6 +411,7 @@
         'payload_generator/inplace_generator.cc',
         'payload_generator/mapfile_filesystem.cc',
         'payload_generator/payload_file.cc',
+        'payload_generator/payload_generation_config_chromeos.cc',
         'payload_generator/payload_generation_config.cc',
         'payload_generator/payload_signer.cc',
         'payload_generator/raw_filesystem.cc',