GkiComplianceV2: Check |.os_version| and |.recovery_dtbo_[size|offset]|

.os_version mustn't be defined for Android T+ GKI, instead these value
should be defined in vbmeta for consistency.

.recovery_dtbo_size & .recovery_dtbo_offset mustn't be defined for the
'boot' partition image, because 'boot' is obviously not 'recovery'.

Also adjust some code for consistency:
  GetBootHeaderVersion(boot_image->data())
  => boot_image->header_version()
And harden reinterpret_cast<> to static_cast<>.

Bug: 211741246
Test: atest vts_gki_compliance_test
Change-Id: I7c12bc77cb27277521407e253347fac702f13372
diff --git a/avb/vts_gki_compliance_test.cpp b/avb/vts_gki_compliance_test.cpp
index e3f59cd..2835922 100644
--- a/avb/vts_gki_compliance_test.cpp
+++ b/avb/vts_gki_compliance_test.cpp
@@ -40,17 +40,15 @@
   return "/dev/block/by-name/" + name + fs_mgr_get_slot_suffix();
 }
 
-uint32_t GetBootHeaderVersion(const void *data) {
-  return reinterpret_cast<const boot_img_hdr_v0 *>(data)->header_version;
-}
-
 class GkiBootImage {
  public:
   GkiBootImage(const uint8_t *data, size_t size) : data_(data, data + size) {}
 
-  const uint8_t *data() const { return data_.data(); }
+  static uint32_t GetBootHeaderVersion(const void *data) {
+    return static_cast<const boot_img_hdr_v0 *>(data)->header_version;
+  }
 
-  size_t size() const { return data_.size(); }
+  uint32_t header_version() const { return GetBootHeaderVersion(data()); }
 
   uint32_t kernel_pages() const { return GetNumberOfPages(kernel_size()); }
 
@@ -66,6 +64,7 @@
   }
 
   virtual uint32_t page_size() const = 0;
+  virtual uint32_t os_version() const = 0;
   virtual uint32_t kernel_size() const = 0;
   virtual uint32_t ramdisk_size() const = 0;
   virtual uint32_t signature_size() const = 0;
@@ -144,6 +143,10 @@
   virtual ~GkiBootImage() = default;
 
  protected:
+  const uint8_t *data() const { return data_.data(); }
+
+  size_t size() const { return data_.size(); }
+
   std::vector<uint8_t> Slice(size_t offset, size_t length) const {
     const auto begin_offset = std::clamp<size_t>(offset, 0, size());
     const auto end_offset =
@@ -169,6 +172,8 @@
 
   uint32_t page_size() const override { return boot_header()->page_size; }
 
+  uint32_t os_version() const override { return boot_header()->os_version; }
+
   uint32_t kernel_size() const override { return boot_header()->kernel_size; }
 
   uint32_t ramdisk_size() const override { return boot_header()->ramdisk_size; }
@@ -185,6 +190,14 @@
     }
     return size() - signature_size();
   }
+
+  uint32_t recovery_dtbo_size() const {
+    return boot_header()->recovery_dtbo_size;
+  }
+
+  uint64_t recovery_dtbo_offset() const {
+    return boot_header()->recovery_dtbo_offset;
+  }
 };
 
 class GkiBootImageV4 : public GkiBootImage {
@@ -199,6 +212,8 @@
 
   uint32_t page_size() const override { return kPageSize; }
 
+  uint32_t os_version() const override { return boot_header()->os_version; }
+
   uint32_t kernel_size() const override { return boot_header()->kernel_size; }
 
   uint32_t ramdisk_size() const override { return boot_header()->ramdisk_size; }
@@ -278,7 +293,7 @@
 
   std::unique_ptr<GkiBootImage> boot_image;
   const auto boot_header_version =
-      GetBootHeaderVersion(block_device_data.data());
+      GkiBootImage::GetBootHeaderVersion(block_device_data.data());
   if (boot_header_version == 4) {
     boot_image = std::make_unique<GkiBootImageV4>(
         reinterpret_cast<const uint8_t *>(block_device_data.data()),
@@ -360,7 +375,8 @@
   GTEST_LOG_(INFO) << TAG << ": " + name + ".fingerprint: "
                    << GetAvbProperty(name + ".fingerprint",
                                      *boot_signature_images);
-  GTEST_LOG_(INFO) << TAG << ": header version: " << boot_header_version
+  GTEST_LOG_(INFO) << TAG
+                   << ": header version: " << boot_image->header_version()
                    << ", kernel size: " << boot_image->kernel_size()
                    << ", ramdisk size: " << boot_image->ramdisk_size()
                    << ", signature size: " << boot_image->signature_size();
@@ -535,7 +551,7 @@
   if (kernel_level <= android::vintf::Level::S) {
     // R, S kernel
     // Legacy scheme, verify the GKI 2.0 boot.img against the "boot" descriptor.
-    EXPECT_EQ(4, GetBootHeaderVersion(boot_image->data()));
+    EXPECT_EQ(4, boot_image->header_version());
     EXPECT_EQ(1, boot_signature_images.size());
 
     std::unique_ptr<android::fs_mgr::FsAvbHashDescriptor>
@@ -548,6 +564,10 @@
                                                   *legacy_boot_descriptor));
   } else {
     // T+ kernel
+    EXPECT_EQ(0, boot_image->os_version())
+        << "OS version and security patch level should be defined in the "
+           "chained vbmeta image.";
+
     std::unique_ptr<android::fs_mgr::FsAvbHashDescriptor>
         generic_kernel_descriptor = android::fs_mgr::GetHashDescriptor(
             "generic_kernel", boot_signature_images);
@@ -555,7 +575,6 @@
         generic_ramdisk_descriptor = android::fs_mgr::GetHashDescriptor(
             "generic_ramdisk", boot_signature_images);
 
-    // TODO: Verify the header fields.
     ASSERT_NE(nullptr, generic_kernel_descriptor)
         << "Failed to load the 'generic_kernel' hash descriptor.";
     ASSERT_NO_FATAL_FAILURE(VerifyImageDescriptor(boot_image->GetKernel(),
@@ -565,7 +584,13 @@
       GTEST_LOG_(INFO) << "Retrofitted scheme, checking the ramdisk image from "
                           "the 'boot' partition.";
       auto ramdisk = boot_image->GetRamdisk();
-      if (GetBootHeaderVersion(boot_image->data()) == 2) {
+      if (boot_image->header_version() == 2) {
+        const auto *boot_image_v2 =
+            static_cast<const GkiBootImageV2 *>(boot_image.get());
+        EXPECT_EQ(0, boot_image_v2->recovery_dtbo_size())
+            << "'boot' partition mustn't include a recovery DTBO/ACPIO";
+        EXPECT_EQ(0, boot_image_v2->recovery_dtbo_offset())
+            << "'boot' partition mustn't include a recovery DTBO/ACPIO";
         // For [.begin() + offset, .end()) to be a well-defined range,
         // |.begin() + offset| must be within [.begin(), .end()], thus
         // |offset| must be within [0, ramdisk.size()].
@@ -580,7 +605,7 @@
       GTEST_LOG_(INFO) << "T+ verification scheme, the 'boot' partition must "
                           "contain only the generic kernel and the 'init_boot' "
                           "partition must contain only the generic ramdisk.";
-      EXPECT_EQ(4, GetBootHeaderVersion(boot_image->data()));
+      EXPECT_EQ(4, boot_image->header_version());
       EXPECT_EQ(1, boot_signature_images.size());
       EXPECT_EQ(0, boot_image->ramdisk_size())
           << "'boot' partition mustn't include a ramdisk image.";
@@ -589,10 +614,13 @@
       std::unique_ptr<GkiBootImage> init_boot_image =
           LoadAndVerifyGkiBootImage("init_boot", &init_boot_signature_images);
       ASSERT_NE(nullptr, init_boot_image);
-      EXPECT_EQ(4, GetBootHeaderVersion(init_boot_image->data()));
+      EXPECT_EQ(4, init_boot_image->header_version());
       EXPECT_EQ(1, init_boot_signature_images.size());
       EXPECT_EQ(0, init_boot_image->kernel_size())
           << "'init_boot' partition mustn't include a kernel image.";
+      EXPECT_EQ(0, init_boot_image->os_version())
+          << "OS version and security patch level should be defined in the "
+             "chained vbmeta image.";
 
       generic_ramdisk_descriptor = android::fs_mgr::GetHashDescriptor(
           "generic_ramdisk", init_boot_signature_images);