1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "VtsSecurityAvbTest"
18 
19 #include <sys/utsname.h>
20 #include <unistd.h>
21 
22 #include <array>
23 #include <list>
24 #include <map>
25 #include <set>
26 #include <tuple>
27 #include <vector>
28 
29 #include <android-base/file.h>
30 #include <android-base/logging.h>
31 #include <android-base/properties.h>
32 #include <android-base/result.h>
33 #include <android-base/stringprintf.h>
34 #include <android-base/unique_fd.h>
35 #include <bootimg.h>
36 #include <fs_avb/fs_avb_util.h>
37 #include <fs_mgr/roots.h>
38 #include <fstab/fstab.h>
39 #include <gtest/gtest.h>
40 #include <libavb/libavb.h>
41 #include <libavb_user/avb_ops_user.h>
42 #include <libdm/dm.h>
43 #include <log/log.h>
44 #include <openssl/sha.h>
45 
46 using android::base::Error;
47 using android::base::Result;
48 
HexDigitToByte(char c)49 static uint8_t HexDigitToByte(char c) {
50   if (c >= '0' && c <= '9') {
51     return c - '0';
52   }
53   if (c >= 'a' && c <= 'f') {
54     return c - 'a' + 10;
55   }
56   if (c >= 'A' && c <= 'Z') {
57     return c - 'A' + 10;
58   }
59   return 0xff;
60 }
61 
HexToBytes(const std::string & hex,std::vector<uint8_t> * bytes)62 static bool HexToBytes(const std::string &hex, std::vector<uint8_t> *bytes) {
63   if (hex.size() % 2 != 0) {
64     return false;
65   }
66   bytes->resize(hex.size() / 2);
67   for (unsigned i = 0; i < bytes->size(); i++) {
68     uint8_t hi = HexDigitToByte(hex[i * 2]);
69     uint8_t lo = HexDigitToByte(hex[i * 2 + 1]);
70     if (lo > 0xf || hi > 0xf) {
71       return false;
72     }
73     bytes->at(i) = (hi << 4) | lo;
74   }
75   return true;
76 }
77 
78 // The abstract class of SHA algorithms.
79 class ShaHasher {
80  protected:
81   const uint32_t digest_size_;
82 
ShaHasher(uint32_t digest_size)83   ShaHasher(uint32_t digest_size) : digest_size_(digest_size) {}
84 
85  public:
~ShaHasher()86   virtual ~ShaHasher() {}
87 
GetDigestSize() const88   uint32_t GetDigestSize() const { return digest_size_; }
89 
90   virtual bool CalculateDigest(const void *buffer, size_t size,
91                                const void *salt, uint32_t block_length,
92                                uint8_t *digest) const = 0;
93 };
94 
95 template <typename CTX_TYPE>
96 class ShaHasherImpl : public ShaHasher {
97  private:
98   typedef int (*InitFunc)(CTX_TYPE *);
99   typedef int (*UpdateFunc)(CTX_TYPE *sha, const void *data, size_t len);
100   typedef int (*FinalFunc)(uint8_t *md, CTX_TYPE *sha);
101 
102   const InitFunc init_func_;
103   const UpdateFunc update_func_;
104   const FinalFunc final_func_;
105 
106  public:
ShaHasherImpl(InitFunc init_func,UpdateFunc update_func,FinalFunc final_func,uint32_t digest_size)107   ShaHasherImpl(InitFunc init_func, UpdateFunc update_func,
108                 FinalFunc final_func, uint32_t digest_size)
109       : ShaHasher(digest_size),
110         init_func_(init_func),
111         update_func_(update_func),
112         final_func_(final_func) {}
113 
~ShaHasherImpl()114   ~ShaHasherImpl() {}
115 
CalculateDigest(const void * buffer,size_t size,const void * salt,uint32_t salt_length,uint8_t * digest) const116   bool CalculateDigest(const void *buffer, size_t size, const void *salt,
117                        uint32_t salt_length, uint8_t *digest) const {
118     CTX_TYPE ctx;
119     if (init_func_(&ctx) != 1) {
120       return false;
121     }
122     if (update_func_(&ctx, salt, salt_length) != 1) {
123       return false;
124     }
125     if (update_func_(&ctx, buffer, size) != 1) {
126       return false;
127     }
128     if (final_func_(digest, &ctx) != 1) {
129       return false;
130     }
131     return true;
132   }
133 };
134 
135 // Creates a hasher with the parameters corresponding to the algorithm name.
CreateShaHasher(const std::string & algorithm)136 static std::unique_ptr<ShaHasher> CreateShaHasher(
137     const std::string &algorithm) {
138   if (algorithm == "sha1") {
139     return std::make_unique<ShaHasherImpl<SHA_CTX>>(
140         SHA1_Init, SHA1_Update, SHA1_Final, SHA_DIGEST_LENGTH);
141   }
142   if (algorithm == "sha256") {
143     return std::make_unique<ShaHasherImpl<SHA256_CTX>>(
144         SHA256_Init, SHA256_Update, SHA256_Final, SHA256_DIGEST_LENGTH);
145   }
146   if (algorithm == "sha512") {
147     return std::make_unique<ShaHasherImpl<SHA512_CTX>>(
148         SHA512_Init, SHA512_Update, SHA512_Final, SHA512_DIGEST_LENGTH);
149   }
150   return nullptr;
151 }
152 
153 // Calculates the digest of a block filled with 0.
CalculateZeroDigest(const ShaHasher & hasher,size_t size,const void * salt,int32_t block_length,uint8_t * digest)154 static bool CalculateZeroDigest(const ShaHasher &hasher, size_t size,
155                                 const void *salt, int32_t block_length,
156                                 uint8_t *digest) {
157   const std::vector<uint8_t> buffer(size, 0);
158   return hasher.CalculateDigest(buffer.data(), size, salt, block_length,
159                                 digest);
160 }
161 
162 // Logical structure of a hashtree:
163 //
164 // Level 2:                        [    root     ]
165 //                                /               \
166 // Level 1:              [entry_0]                 [entry_1]
167 //                      /   ...   \                   ...   \
168 // Level 0:   [entry_0_0]   ...   [entry_0_127]       ...   [entry_1_127]
169 //             /  ...  \           /   ...   \               /   ...   \
170 // Data:    blk_0 ... blk_127  blk_16256 ... blk_16383  blk_32640 ... blk_32767
171 //
172 // The digest of a data block or a hash block in level N is stored in level
173 // N + 1.
174 // The function VerifyHashtree allocates a HashtreeLevel for each level. It
175 // calculates the digests of the blocks in lower level and fills them in
176 // calculating_hash_block. When calculating_hash_block is full, it is compared
177 // with the hash block at comparing_tree_offset in the image. After comparison,
178 // calculating_hash_block is cleared and reused for the next hash block.
179 //
180 //                   comparing_tree_offset
181 //                   |
182 //                   v
183 // [<--------------------    level_size    -------------------->]
184 // [entry_0_0]  ...  [entry_0_127           ]  ...  [entry_1_127]
185 //
186 //                   [calculating_hash_block]
187 //                         ^
188 //                         |
189 //                         calculating_offset
190 struct HashtreeLevel {
191   // Offset of an expected hash block to compare, relative to the beginning of
192   // the hashtree in the image file.
193   uint64_t comparing_tree_offset;
194   // Size of this level, in bytes.
195   const uint64_t level_size;
196   // Offset of a digest in calculating_hash_block.
197   size_t calculating_offset;
198   // The hash block containing the digests calculated from the lower level.
199   std::vector<uint8_t> calculating_hash_block;
200 
HashtreeLevelHashtreeLevel201   HashtreeLevel(uint64_t lv_offset, uint64_t lv_size, size_t hash_block_size)
202       : comparing_tree_offset(lv_offset),
203         level_size(lv_size),
204         calculating_offset(0),
205         calculating_hash_block(hash_block_size) {}
206 };
207 
208 // Calculates and verifies the image's hashtree.
209 //
210 // Arguments:
211 //   image_fd: The raw image file.
212 //   image_size, data_block_size, hash_block_size, tree_offset, tree_size: The
213 //       fields in AvbHashtreeDescriptor.
214 //   salt: The binary value of the salt in FsAvbHashtreeDescriptor.
215 //   hasher: The ShaHasher object.
216 //   root_digest: The binary value of the root_digest in
217 //       FsAvbHashtreeDescriptor.
218 //
219 // Returns:
220 //   An empty string if the function succeeds.
221 //   Otherwise it returns the error message.
VerifyHashtree(int image_fd,uint64_t image_size,const std::vector<uint8_t> & salt,uint32_t data_block_size,uint32_t hash_block_size,uint64_t tree_offset,uint64_t tree_size,const ShaHasher & hasher,const std::vector<uint8_t> & root_digest)222 static std::string VerifyHashtree(int image_fd, uint64_t image_size,
223                                   const std::vector<uint8_t> &salt,
224                                   uint32_t data_block_size,
225                                   uint32_t hash_block_size,
226                                   uint64_t tree_offset, uint64_t tree_size,
227                                   const ShaHasher &hasher,
228                                   const std::vector<uint8_t> &root_digest) {
229   uint32_t digest_size = hasher.GetDigestSize();
230   uint32_t padded_digest_size = 1;
231   while (padded_digest_size < digest_size) {
232     padded_digest_size *= 2;
233   }
234 
235   if (image_size % data_block_size != 0) {
236     return "Image size is not a multiple of data block size";
237   }
238 
239   uint64_t data_block_count = image_size / data_block_size;
240   uint32_t digests_per_block = hash_block_size / padded_digest_size;
241 
242   // Initialize HashtreeLevel in bottom-up order.
243   std::list<HashtreeLevel> levels;
244   {
245     uint64_t hash_block_count = 0;
246     uint32_t level_block_count = data_block_count;
247     // Calculate the hashtree until the root hash is reached.
248     while (level_block_count > 1) {
249       uint32_t next_level_block_count =
250           (level_block_count + digests_per_block - 1) / digests_per_block;
251       hash_block_count += next_level_block_count;
252       // comparing_tree_offset will be initialized later.
253       levels.emplace_back(0 /* comparing_tree_offset */,
254                           next_level_block_count * hash_block_size,
255                           hash_block_size);
256       level_block_count = next_level_block_count;
257     }
258     if (hash_block_count * hash_block_size != tree_size) {
259       return "Block count and tree size mismatch";
260     }
261     // Append the root digest. Its level_size is unused.
262     levels.emplace_back(0 /* comparing_tree_offset */, 0 /* level_size */,
263                         digest_size);
264 
265     // Initialize comparing_tree_offset of each level
266     for (auto level = std::prev(levels.end()); level != levels.begin();
267          level--) {
268       std::prev(level)->comparing_tree_offset =
269           level->comparing_tree_offset + level->level_size;
270     }
271   }
272 
273   std::vector<uint8_t> padded_zero_digest(padded_digest_size, 0);
274   if (!CalculateZeroDigest(hasher, data_block_size, salt.data(), salt.size(),
275                            padded_zero_digest.data())) {
276     return "CalculateZeroDigest fails";
277   }
278 
279   std::vector<uint8_t> data_block(data_block_size);
280   std::vector<uint8_t> tree_block(hash_block_size);
281   for (uint64_t image_offset = 0; image_offset < image_size;
282        image_offset += data_block_size) {
283     ssize_t read_size = TEMP_FAILURE_RETRY(
284         pread64(image_fd, data_block.data(), data_block.size(), image_offset));
285     if (read_size != data_block.size()) {
286       return android::base::StringPrintf(
287           "Fail to read data block at offset %llu",
288           (unsigned long long)image_offset);
289     }
290 
291     bool is_last_data = (image_offset + data_block.size() == image_size);
292     // The block to be digested
293     std::vector<uint8_t> *current_block = &data_block;
294     for (auto level = levels.begin(); true; level++) {
295       uint8_t *current_digest =
296           level->calculating_hash_block.data() + level->calculating_offset;
297       if (!hasher.CalculateDigest(current_block->data(), current_block->size(),
298                                   salt.data(), salt.size(), current_digest)) {
299         return "CalculateDigest fails";
300       }
301       // Stop at root digest
302       if (std::next(level) == levels.end()) {
303         break;
304       }
305 
306       // Pad the digest
307       memset(current_digest + digest_size, 0, padded_digest_size - digest_size);
308       level->calculating_offset += padded_digest_size;
309       // Pad the last hash block of this level
310       if (is_last_data) {
311         memset(
312             level->calculating_hash_block.data() + level->calculating_offset, 0,
313             level->calculating_hash_block.size() - level->calculating_offset);
314       } else if (level->calculating_offset <
315                  level->calculating_hash_block.size()) {
316         // Stop at this level if the hash block is not full, continue to read
317         // more data_blocks from the outside loop for digest calculation
318         break;
319       }
320       // Verify the full hash block
321       // current_block may point to tree_block. Since the following pread64
322       // changes tree_block, do not read current_block in the rest of this
323       // code block.
324       current_block = nullptr;
325       read_size = TEMP_FAILURE_RETRY(
326           pread64(image_fd, tree_block.data(), tree_block.size(),
327                   tree_offset + level->comparing_tree_offset));
328       if (read_size != tree_block.size()) {
329         return android::base::StringPrintf(
330             "Fail to read tree block at offset %llu",
331             (unsigned long long)tree_offset + level->comparing_tree_offset);
332       }
333 
334       for (uint32_t offset = 0; offset < tree_block.size();
335            offset += padded_digest_size) {
336         // If the digest in the hashtree is equal to the digest of zero block,
337         // it indicates the corresponding data block is in DONT_CARE chunk in
338         // sparse image. The block should not be verified.
339         if (level == levels.begin() &&
340             memcmp(tree_block.data() + offset, padded_zero_digest.data(),
341                    padded_digest_size) == 0) {
342           continue;
343         }
344         if (memcmp(tree_block.data() + offset,
345                    level->calculating_hash_block.data() + offset,
346                    padded_digest_size) != 0) {
347           return android::base::StringPrintf(
348               "Hash blocks mismatch, block offset = %llu, digest offset = %u",
349               (unsigned long long)tree_offset + level->comparing_tree_offset,
350               offset);
351         }
352       }
353 
354       level->calculating_offset = 0;
355       level->comparing_tree_offset += hash_block_size;
356       if (level->comparing_tree_offset > tree_size) {
357         return "Tree offset is out of bound";
358       }
359       // Prepare for next/upper level, to calculate the digest of this
360       // hash_block for comparison
361       current_block = &tree_block;
362     }
363   }
364 
365   if (levels.back().calculating_hash_block != root_digest) {
366     return "Root digests mismatch";
367   }
368   return "";
369 }
370 
371 // Converts descriptor.hash_algorithm to std::string.
GetHashAlgorithm(const AvbHashtreeDescriptor & descriptor)372 static std::string GetHashAlgorithm(const AvbHashtreeDescriptor &descriptor) {
373   return std::string(reinterpret_cast<const char *>(descriptor.hash_algorithm));
374 }
375 
376 // Converts descriptor.hash_algorithm to std::string.
GetHashAlgorithm(const AvbHashDescriptor & descriptor)377 static std::string GetHashAlgorithm(const AvbHashDescriptor &descriptor) {
378   return std::string(reinterpret_cast<const char *>(descriptor.hash_algorithm));
379 }
380 
381 // Checks whether the public key is an official GSI key or not.
ValidatePublicKeyBlob(const std::string & key_blob_to_validate)382 static bool ValidatePublicKeyBlob(const std::string &key_blob_to_validate) {
383   if (key_blob_to_validate.empty()) {
384     ALOGE("Failed to validate an empty key");
385     return false;
386   }
387 
388   std::string allowed_key_blob;
389   std::vector<std::string> allowed_key_paths = {
390       "/data/local/tmp/q-gsi.avbpubkey", "/data/local/tmp/r-gsi.avbpubkey",
391       "/data/local/tmp/s-gsi.avbpubkey", "/data/local/tmp/t-gsi.avbpubkey",
392       "/data/local/tmp/qcar-gsi.avbpubkey"};
393   for (const auto &path : allowed_key_paths) {
394     if (android::base::ReadFileToString(path, &allowed_key_blob)) {
395       if (key_blob_to_validate == allowed_key_blob) {
396         ALOGE("Found matching GSI key: %s", path.c_str());
397         return true;
398       }
399     }
400   }
401   return false;
402 }
403 
404 // Gets the system partition's AvbHashtreeDescriptor and device file path.
405 //
406 // Arguments:
407 //  out_verify_result: The result of vbmeta verification.
408 //  out_system_path: The system's device file path.
409 //
410 // Returns:
411 //   The pointer to the system's AvbHashtreeDescriptor.
412 //   nullptr if any operation fails.
413 static std::unique_ptr<android::fs_mgr::FsAvbHashtreeDescriptor>
GetSystemHashtreeDescriptor(android::fs_mgr::VBMetaVerifyResult * out_verify_result,std::string * out_system_path)414 GetSystemHashtreeDescriptor(
415     android::fs_mgr::VBMetaVerifyResult *out_verify_result,
416     std::string *out_system_path) {
417   android::fs_mgr::Fstab default_fstab;
418   bool ok = ReadDefaultFstab(&default_fstab);
419   if (!ok) {
420     ALOGE("ReadDefaultFstab fails");
421     return nullptr;
422   }
423   android::fs_mgr::FstabEntry *system_fstab_entry =
424       GetEntryForPath(&default_fstab, "/system");
425   if (system_fstab_entry == nullptr) {
426     ALOGE("GetEntryForPath fails");
427     return nullptr;
428   }
429 
430   ok = fs_mgr_update_logical_partition(system_fstab_entry);
431   if (!ok) {
432     ALOGE("fs_mgr_update_logical_partition fails");
433     return nullptr;
434   }
435 
436   CHECK(out_system_path != nullptr);
437   *out_system_path = system_fstab_entry->blk_device;
438 
439   std::string out_public_key_data;
440   std::string out_avb_partition_name;
441   std::unique_ptr<android::fs_mgr::VBMetaData> vbmeta =
442       android::fs_mgr::LoadAndVerifyVbmeta(
443           *system_fstab_entry, "" /* expected_key_blob */, &out_public_key_data,
444           &out_avb_partition_name, out_verify_result);
445   if (vbmeta == nullptr) {
446     ALOGE("LoadAndVerifyVbmeta fails");
447     return nullptr;
448   }
449 
450   if (out_public_key_data.empty()) {
451     ALOGE("The GSI image is not signed");
452     return nullptr;
453   }
454 
455   if (!ValidatePublicKeyBlob(out_public_key_data)) {
456     ALOGE("The GSI image is not signed by an official key");
457     return nullptr;
458   }
459 
460   std::unique_ptr<android::fs_mgr::FsAvbHashtreeDescriptor> descriptor =
461       android::fs_mgr::GetHashtreeDescriptor("system", std::move(*vbmeta));
462   if (descriptor == nullptr) {
463     ALOGE("GetHashtreeDescriptor fails");
464     return nullptr;
465   }
466 
467   return descriptor;
468 }
469 
470 // Returns true iff the device has the specified feature.
DeviceSupportsFeature(const char * feature)471 bool DeviceSupportsFeature(const char *feature) {
472   bool device_supports_feature = false;
473   FILE *p = popen("pm list features", "re");
474   if (p) {
475     char *line = NULL;
476     size_t len = 0;
477     while (getline(&line, &len, p) > 0) {
478       if (strstr(line, feature)) {
479         device_supports_feature = true;
480         break;
481       }
482     }
483     pclose(p);
484   }
485   return device_supports_feature;
486 }
487 
488 const uint32_t kCurrentApiLevel = 10000;
489 
ReadApiLevelProps(const std::vector<std::string> & api_level_props)490 static uint32_t ReadApiLevelProps(
491     const std::vector<std::string> &api_level_props) {
492   uint32_t api_level = kCurrentApiLevel;
493   for (const auto &api_level_prop : api_level_props) {
494     api_level = android::base::GetUintProperty<uint32_t>(api_level_prop,
495                                                          kCurrentApiLevel);
496     if (api_level != kCurrentApiLevel) {
497       break;
498     }
499   }
500   return api_level;
501 }
502 
GetBoardApiLevel()503 static uint32_t GetBoardApiLevel() {
504   uint32_t device_api_level =
505       ReadApiLevelProps({"ro.product.first_api_level", "ro.build.version.sdk"});
506   uint32_t board_api_level =
507       ReadApiLevelProps({"ro.board.api_level", "ro.board.first_api_level",
508                          "ro.vendor.build.version.sdk"});
509   uint32_t api_level =
510       board_api_level < device_api_level ? board_api_level : device_api_level;
511   if (api_level == kCurrentApiLevel) {
512     ADD_FAILURE() << "Failed to determine board API level";
513     return 0;
514   }
515   return api_level;
516 }
517 
ShouldSkipGkiTest()518 bool ShouldSkipGkiTest() {
519   /* Skip for devices launched before Android R. */
520   constexpr auto R_API_LEVEL = 30;
521   uint32_t board_api_level = GetBoardApiLevel();
522   GTEST_LOG_(INFO) << "Board API level is " << board_api_level;
523   if (board_api_level < R_API_LEVEL) {
524     GTEST_LOG_(INFO) << "Exempt from GKI test due to old starting API level";
525     return true;
526   }
527 
528   /* Skip for form factors that do not mandate GKI yet */
529   const static bool tv_device =
530       DeviceSupportsFeature("android.software.leanback");
531   const static bool auto_device =
532       DeviceSupportsFeature("android.hardware.type.automotive");
533   if (tv_device || auto_device) {
534     GTEST_LOG_(INFO) << "Exempt from GKI test on TV/Auto devices";
535     return true;
536   }
537 
538   return false;
539 }
540 
541 // Returns a tuple of (version_major, version_minor and architecture).
GetKernelInfo()542 static Result<std::tuple<int, int, std::string>> GetKernelInfo() {
543   struct utsname buf;
544   int ret, kernel_version_major, kernel_version_minor;
545   ret = uname(&buf);
546   if (ret != 0) {
547     return Error() << "Failed to get kernel version.";
548   }
549 
550   char unused;
551   ret = sscanf(buf.release, "%d.%d%c", &kernel_version_major,
552                &kernel_version_minor, &unused);
553   if (ret < 2) {
554     return Error() << "Failed to parse kernel version.";
555   }
556 
557   return std::make_tuple(kernel_version_major, kernel_version_minor,
558                          buf.machine);
559 }
560 
ShouldSkipGkiComplianceV1()561 bool ShouldSkipGkiComplianceV1() {
562   auto kernel_info = GetKernelInfo();
563 
564   if (!kernel_info.ok()) {
565     ADD_FAILURE() << "Failed to get kernel info";
566     return true;
567   }
568 
569   const auto [kernel_version_major, kernel_version_minor, kernel_arch] =
570       (std::move(kernel_info).value());
571 
572   /* Skip for devices if the kernel version is not 5.4. */
573   if (kernel_version_major != 5 || kernel_version_minor != 4) {
574     GTEST_LOG_(INFO)
575         << "Exempt from GKI 1.0 test due to unmatched kernel version: "
576         << kernel_version_major << "." << kernel_version_minor;
577     return true;
578   }
579   /* Skip for non arm64 that do not mandate GKI yet. */
580   if (kernel_arch != "aarch64") {
581     GTEST_LOG_(INFO) << "Exempt from GKI test on non-arm64 devices";
582     return true;
583   }
584 
585   return false;
586 }
587 
ShouldSkipGkiComplianceV2()588 bool ShouldSkipGkiComplianceV2() {
589   auto kernel_info = GetKernelInfo();
590 
591   if (!kernel_info.ok()) {
592     ADD_FAILURE() << "Failed to get kernel info";
593     return true;
594   }
595 
596   const auto [kernel_version_major, kernel_version_minor, kernel_arch] =
597       (std::move(kernel_info).value());
598 
599   /* Skip for devices if the kernel version is not >= 5.10. */
600   if (kernel_version_major < 5 ||
601       (kernel_version_major == 5 && kernel_version_minor < 10)) {
602     GTEST_LOG_(INFO)
603         << "Exempt from GKI 2.0 test due to unmatched kernel version: "
604         << kernel_version_major << "." << kernel_version_minor;
605     return true;
606   }
607 
608   /* Skip for non arm64 that do not mandate GKI yet. */
609   if (kernel_arch != "aarch64") {
610     GTEST_LOG_(INFO) << "Exempt from GKI test on non-arm64 devices";
611     return true;
612   }
613 
614   return false;
615 }
616 
TEST(AvbTest,GkiComplianceV1)617 TEST(AvbTest, GkiComplianceV1) {
618   if (ShouldSkipGkiTest() || ShouldSkipGkiComplianceV1()) {
619     return;
620   }
621 
622   /* load vbmeta struct from boot, verify struct integrity */
623   std::string out_public_key_data;
624   android::fs_mgr::VBMetaVerifyResult out_verify_result;
625   std::string boot_path = "/dev/block/by-name/boot" + fs_mgr_get_slot_suffix();
626   std::unique_ptr<android::fs_mgr::VBMetaData> vbmeta =
627       android::fs_mgr::LoadAndVerifyVbmetaByPath(
628           boot_path, "boot", "" /* expected_key_blob */,
629           true /* allow verification error */, false /* rollback_protection */,
630           false /* is_chained_vbmeta */, &out_public_key_data,
631           nullptr /* out_verification_disabled */, &out_verify_result);
632 
633   ASSERT_TRUE(vbmeta) << "Verification of GKI vbmeta fails.";
634   ASSERT_FALSE(out_public_key_data.empty()) << "The GKI image is not signed.";
635   EXPECT_TRUE(ValidatePublicKeyBlob(out_public_key_data))
636       << "The GKI image is not signed by an official key.";
637   EXPECT_EQ(out_verify_result, android::fs_mgr::VBMetaVerifyResult::kSuccess)
638       << "Verification of the GKI vbmeta structure failed.";
639 
640   /* verify boot partition according to vbmeta structure */
641   std::unique_ptr<android::fs_mgr::FsAvbHashDescriptor> descriptor =
642       android::fs_mgr::GetHashDescriptor("boot", std::move(*vbmeta));
643   ASSERT_TRUE(descriptor)
644       << "Failed to load hash descriptor from boot.img vbmeta";
645   const std::string &salt_str = descriptor->salt;
646   const std::string &expected_digest_str = descriptor->digest;
647 
648   android::base::unique_fd fd(open(boot_path.c_str(), O_RDONLY));
649   ASSERT_GE(fd, 0) << "Fail to open boot partition. Try 'adb root'.";
650 
651   const std::string hash_algorithm(GetHashAlgorithm(*descriptor));
652   GTEST_LOG_(INFO) << "hash_algorithm = " << hash_algorithm;
653 
654   std::unique_ptr<ShaHasher> hasher = CreateShaHasher(hash_algorithm);
655   ASSERT_TRUE(hasher);
656 
657   std::vector<uint8_t> salt, expected_digest, out_digest;
658   bool ok = HexToBytes(salt_str, &salt);
659   ASSERT_TRUE(ok) << "Invalid salt in descriptor: " << salt_str;
660   ok = HexToBytes(expected_digest_str, &expected_digest);
661   ASSERT_TRUE(ok) << "Invalid digest in descriptor: " << expected_digest_str;
662   ASSERT_EQ(expected_digest.size(), hasher->GetDigestSize());
663 
664   std::vector<char> boot_partition_vector;
665   boot_partition_vector.resize(descriptor->image_size);
666   ASSERT_TRUE(android::base::ReadFully(fd, boot_partition_vector.data(),
667                                        descriptor->image_size))
668       << "Could not read boot partition to vector.";
669 
670   out_digest.resize(hasher->GetDigestSize());
671   ASSERT_TRUE(hasher->CalculateDigest(
672       boot_partition_vector.data(), descriptor->image_size,
673       salt.data(), descriptor->salt_len, out_digest.data()))
674       << "Unable to calculate boot image digest.";
675 
676   ASSERT_TRUE(out_digest.size() == expected_digest.size())
677       << "Calculated GKI boot digest size does not match expected digest size.";
678   ASSERT_TRUE(out_digest == expected_digest)
679       << "Calculated GKI boot digest does not match expected digest.";
680 }
681 
682 // Loads GKI compliance V2 images.
683 //
684 // Arguments:
685 //   out_boot_partition_vector: the boot.img content without boot_signature.
686 //       It consists of a boot header, a kernel and a ramdisk.
687 //   out_boot_signature_vector: the boot signature used to verify
688 //       out_boot_partition_vector.
689 //
LoadGkiComplianceV2Images(std::vector<uint8_t> * out_boot_partition_vector,std::vector<uint8_t> * out_boot_signature_vector)690 void LoadGkiComplianceV2Images(
691     std::vector<uint8_t> *out_boot_partition_vector,
692     std::vector<uint8_t> *out_boot_signature_vector) {
693   constexpr auto BOOT_HEADER_SIZE = 4096;
694   std::string boot_path = "/dev/block/by-name/boot" + fs_mgr_get_slot_suffix();
695 
696   // Read boot header first.
697   android::base::unique_fd fd(open(boot_path.c_str(), O_RDONLY));
698   ASSERT_GE(fd, 0) << "Fail to open boot partition. Try 'adb root'.";
699 
700   out_boot_partition_vector->resize(BOOT_HEADER_SIZE);
701   ASSERT_TRUE(android::base::ReadFully(fd, out_boot_partition_vector->data(),
702                                        BOOT_HEADER_SIZE))
703       << "Could not read boot partition header to vector.";
704 
705   boot_img_hdr_v4 *boot_header =
706       reinterpret_cast<boot_img_hdr_v4 *>(out_boot_partition_vector->data());
707   std::string boot_magic(reinterpret_cast<const char *>(boot_header->magic),
708                          BOOT_MAGIC_SIZE);
709   ASSERT_EQ(boot_magic, BOOT_MAGIC) << "Incorrect boot magic: " << boot_magic;
710 
711   GTEST_LOG_(INFO) << "kernel size: " << boot_header->kernel_size
712                    << ", ramdisk size: " << boot_header->ramdisk_size
713                    << ", signature size: " << boot_header->signature_size;
714 
715   // Now reads kernel and ramdisk.
716   uint32_t kernel_pages = (boot_header->kernel_size + 4096 - 1) / 4096;
717   uint32_t ramdisk_pages = (boot_header->ramdisk_size + 4096 - 1) / 4096;
718   uint32_t kernel_ramdisk_size = (kernel_pages + ramdisk_pages) * 4096;
719 
720   out_boot_partition_vector->resize(BOOT_HEADER_SIZE + kernel_ramdisk_size);
721   ASSERT_TRUE(android::base::ReadFully(
722       fd, out_boot_partition_vector->data() + BOOT_HEADER_SIZE,
723       kernel_ramdisk_size))
724       << "Could not read boot partition to vector.";
725 
726   // Reads boot_signature.
727   uint32_t signature_pages = (boot_header->signature_size + 4096 - 1) / 4096;
728   uint32_t signature_size_aligned = signature_pages * 4096;
729   out_boot_signature_vector->resize(signature_size_aligned);
730   ASSERT_TRUE(android::base::ReadFully(fd, out_boot_signature_vector->data(),
731                                        signature_size_aligned))
732       << "Could not read boot signature to vector.";
733 }
734 
735 // Verifies the GKI 2.0 boot.img against the boot signature.
736 //
737 // Arguments:
738 //   boot_partition_vector: the boot.img content without boot_signature.
739 //       It consists of a boot header, a kernel and a ramdisk.
740 //   boot_signature_vector: the boot signature used to verify
741 //       boot_partition_vector.
742 //
VerifyGkiComplianceV2Signature(const std::vector<uint8_t> & boot_partition_vector,const std::vector<uint8_t> & boot_signature_vector)743 void VerifyGkiComplianceV2Signature(
744     const std::vector<uint8_t> &boot_partition_vector,
745     const std::vector<uint8_t> &boot_signature_vector) {
746   size_t pk_len;
747   const uint8_t *pk_data;
748   ::AvbVBMetaVerifyResult vbmeta_ret;
749 
750   vbmeta_ret =
751       avb_vbmeta_image_verify(boot_signature_vector.data(),
752                               boot_signature_vector.size(), &pk_data, &pk_len);
753   ASSERT_EQ(vbmeta_ret, AVB_VBMETA_VERIFY_RESULT_OK)
754       << "Failed to verify boot_signature: " << vbmeta_ret;
755 
756   std::string out_public_key_data(reinterpret_cast<const char *>(pk_data),
757                                   pk_len);
758   ASSERT_FALSE(out_public_key_data.empty()) << "The GKI image is not signed.";
759   EXPECT_TRUE(ValidatePublicKeyBlob(out_public_key_data))
760       << "The GKI image is not signed by an official key.";
761 
762   android::fs_mgr::VBMetaData boot_signature(boot_signature_vector.data(),
763                                              boot_signature_vector.size(),
764                                              "boot_signature");
765 
766   std::unique_ptr<android::fs_mgr::FsAvbHashDescriptor> descriptor =
767       android::fs_mgr::GetHashDescriptor("boot", std::move(boot_signature));
768   ASSERT_TRUE(descriptor)
769       << "Failed to load hash descriptor from the boot signature";
770   ASSERT_EQ(boot_partition_vector.size(), descriptor->image_size);
771 
772   const std::string &salt_str = descriptor->salt;
773   const std::string &expected_digest_str = descriptor->digest;
774 
775   const std::string hash_algorithm(GetHashAlgorithm(*descriptor));
776   GTEST_LOG_(INFO) << "hash_algorithm = " << hash_algorithm;
777 
778   std::unique_ptr<ShaHasher> hasher = CreateShaHasher(hash_algorithm);
779   ASSERT_TRUE(hasher);
780 
781   std::vector<uint8_t> salt, expected_digest, out_digest;
782 
783   bool ok = HexToBytes(salt_str, &salt);
784   ASSERT_TRUE(ok) << "Invalid salt in descriptor: " << salt_str;
785   ok = HexToBytes(expected_digest_str, &expected_digest);
786   ASSERT_TRUE(ok) << "Invalid digest in descriptor: " << expected_digest_str;
787 
788   ASSERT_EQ(expected_digest.size(), hasher->GetDigestSize());
789   out_digest.resize(hasher->GetDigestSize());
790 
791   ASSERT_TRUE(hasher->CalculateDigest(boot_partition_vector.data(),
792                                       boot_partition_vector.size(), salt.data(),
793                                       descriptor->salt_len, out_digest.data()))
794       << "Unable to calculate boot image digest.";
795 
796   ASSERT_EQ(out_digest.size(), expected_digest.size())
797       << "Calculated GKI boot digest size does not match expected digest size.";
798 
799   ASSERT_EQ(out_digest, expected_digest)
800       << "Calculated GKI boot digest does not match expected digest.";
801 }
802 
TEST(AvbTest,GkiComplianceV2)803 TEST(AvbTest, GkiComplianceV2) {
804   if (ShouldSkipGkiTest() || ShouldSkipGkiComplianceV2()) {
805     return;
806   }
807 
808   std::vector<uint8_t> boot_partition_vector;
809   std::vector<uint8_t> boot_signature_vector;
810   ASSERT_NO_FATAL_FAILURE(LoadGkiComplianceV2Images(&boot_partition_vector,
811                                                     &boot_signature_vector));
812   VerifyGkiComplianceV2Signature(boot_partition_vector, boot_signature_vector);
813 }
814 
815 // Loads contents and metadata of logical system partition, calculates
816 // the hashtree, and compares with the metadata.
TEST(AvbTest,SystemHashtree)817 TEST(AvbTest, SystemHashtree) {
818   android::fs_mgr::VBMetaVerifyResult verify_result;
819   std::string system_path;
820   std::unique_ptr<android::fs_mgr::FsAvbHashtreeDescriptor> descriptor =
821       GetSystemHashtreeDescriptor(&verify_result, &system_path);
822   ASSERT_TRUE(descriptor);
823 
824   ALOGI("System partition is %s", system_path.c_str());
825 
826   // TODO: Skip assertion when running with non-compliance configuration.
827   EXPECT_EQ(verify_result, android::fs_mgr::VBMetaVerifyResult::kSuccess);
828   EXPECT_NE(verify_result,
829             android::fs_mgr::VBMetaVerifyResult::kErrorVerification)
830       << "The system image is not an officially signed GSI.";
831 
832   const std::string &salt_str = descriptor->salt;
833   const std::string &expected_digest_str = descriptor->root_digest;
834 
835   android::base::unique_fd fd(open(system_path.c_str(), O_RDONLY));
836   ASSERT_GE(fd, 0) << "Fail to open system partition. Try 'adb root'.";
837 
838   const std::string hash_algorithm(GetHashAlgorithm(*descriptor));
839   ALOGI("hash_algorithm = %s", hash_algorithm.c_str());
840 
841   std::unique_ptr<ShaHasher> hasher = CreateShaHasher(hash_algorithm);
842   ASSERT_TRUE(hasher);
843 
844   std::vector<uint8_t> salt, expected_digest;
845   bool ok = HexToBytes(salt_str, &salt);
846   ASSERT_TRUE(ok) << "Invalid salt in descriptor: " << salt_str;
847   ok = HexToBytes(expected_digest_str, &expected_digest);
848   ASSERT_TRUE(ok) << "Invalid digest in descriptor: " << expected_digest_str;
849   ASSERT_EQ(expected_digest.size(), hasher->GetDigestSize());
850 
851   ALOGI("image_size = %llu", (unsigned long long)descriptor->image_size);
852   ALOGI("data_block_size = %u", descriptor->data_block_size);
853   ALOGI("hash_block_size = %u", descriptor->hash_block_size);
854   ALOGI("tree_offset = %llu", (unsigned long long)descriptor->tree_offset);
855   ALOGI("tree_size = %llu", (unsigned long long)descriptor->tree_size);
856 
857   std::string error_message = VerifyHashtree(
858       fd, descriptor->image_size, salt, descriptor->data_block_size,
859       descriptor->hash_block_size, descriptor->tree_offset,
860       descriptor->tree_size, *hasher, expected_digest);
861   ASSERT_EQ(error_message, "");
862 }
863 
864 // Finds the next word consisting of non-whitespace characters in a string.
865 //
866 // Arguments:
867 //   str: The string to be searched for the next word.
868 //   pos: The starting position to search for the next word.
869 //        This function sets it to the past-the-end position of the word.
870 //
871 // Returns:
872 //   The starting position of the word.
873 //   If there is no next word, this function does not change pos and returns
874 //   std::string::npos.
NextWord(const std::string & str,size_t * pos)875 static size_t NextWord(const std::string &str, size_t *pos) {
876   const char *whitespaces = " \t\r\n";
877   size_t start = str.find_first_not_of(whitespaces, *pos);
878   if (start == std::string::npos) {
879     return start;
880   }
881   *pos = str.find_first_of(whitespaces, start);
882   if (*pos == std::string::npos) {
883     *pos = str.size();
884   }
885   return start;
886 }
887 
888 // Compares device mapper table with system hashtree descriptor.
TEST(AvbTest,SystemDescriptor)889 TEST(AvbTest, SystemDescriptor) {
890   // Get system hashtree descriptor.
891 
892   android::fs_mgr::VBMetaVerifyResult verify_result;
893   std::string system_path;
894   std::unique_ptr<android::fs_mgr::FsAvbHashtreeDescriptor> descriptor =
895       GetSystemHashtreeDescriptor(&verify_result, &system_path);
896   ASSERT_TRUE(descriptor);
897 
898   // TODO: Assert when running with compliance configuration.
899   // The SystemHashtree function asserts verify_result.
900   if (verify_result != android::fs_mgr::VBMetaVerifyResult::kSuccess) {
901     ALOGW("The system image is not an officially signed GSI.");
902   }
903 
904   // Get device mapper table.
905   android::dm::DeviceMapper &device_mapper =
906       android::dm::DeviceMapper::Instance();
907   std::vector<android::dm::DeviceMapper::TargetInfo> table;
908   bool ok = device_mapper.GetTableInfo("system-verity", &table);
909   ASSERT_TRUE(ok) << "GetTableInfo fails";
910   ASSERT_EQ(table.size(), 1);
911   const android::dm::DeviceMapper::TargetInfo &target = table[0];
912   // Sample output:
913   // Device mapper table for system-verity:
914   // 0-1783288: verity, 1 253:0 253:0 4096 4096 222911 222911 sha1
915   // 6b2b46715a2d27c53cc7f91fe63ce798ff1f3df7
916   // 65bc99ca8e97379d4f7adc66664941acc0a8e682 10 restart_on_corruption
917   // ignore_zero_blocks use_fec_from_device 253:0 fec_blocks 224668 fec_start
918   // 224668 fec_roots 2
919   ALOGI("Device mapper table for system-verity:\n%llu-%llu: %s, %s",
920         target.spec.sector_start, target.spec.sector_start + target.spec.length,
921         target.spec.target_type, target.data.c_str());
922   EXPECT_EQ(strcmp(target.spec.target_type, "verity"), 0);
923 
924   // Compare the target's positional parameters with the descriptor. Reference:
925   // https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity#mapping-table-for-verity-target
926   std::array<std::string, 10> descriptor_values = {
927       std::to_string(descriptor->dm_verity_version),
928       "",  // skip data_dev
929       "",  // skip hash_dev
930       std::to_string(descriptor->data_block_size),
931       std::to_string(descriptor->hash_block_size),
932       std::to_string(descriptor->image_size /
933                      descriptor->data_block_size),  // #blocks
934       std::to_string(descriptor->image_size /
935                      descriptor->data_block_size),  // hash_start
936       GetHashAlgorithm(*descriptor),
937       descriptor->root_digest,
938       descriptor->salt,
939   };
940 
941   size_t next_pos = 0;
942   for (const std::string &descriptor_value : descriptor_values) {
943     size_t begin_pos = NextWord(target.data, &next_pos);
944     ASSERT_NE(begin_pos, std::string::npos);
945     if (!descriptor_value.empty()) {
946       EXPECT_EQ(target.data.compare(begin_pos, next_pos - begin_pos,
947                                     descriptor_value),
948                 0);
949     }
950   }
951 
952   // Compare the target's optional parameters with the descriptor.
953   unsigned long opt_param_count;
954   {
955     size_t begin_pos = NextWord(target.data, &next_pos);
956     ASSERT_NE(begin_pos, std::string::npos);
957     opt_param_count =
958         std::stoul(target.data.substr(begin_pos, next_pos - begin_pos));
959   }
960   // https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity#optional-parameters
961   std::set<std::string> opt_params = {
962       "check_at_most_once",
963       "ignore_corruption",
964       "ignore_zero_blocks",
965       "restart_on_corruption",
966   };
967   // https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity#optional-fec-forward-error-correction-parameters
968   std::map<std::string, std::string> opt_fec_params = {
969       {"fec_blocks", ""},
970       {"fec_roots", ""},
971       {"fec_start", ""},
972       {"use_fec_from_device", ""},
973   };
974 
975   for (unsigned long i = 0; i < opt_param_count; i++) {
976     size_t begin_pos = NextWord(target.data, &next_pos);
977     ASSERT_NE(begin_pos, std::string::npos);
978     const std::string param_name(target.data, begin_pos, next_pos - begin_pos);
979     if (opt_fec_params.count(param_name)) {
980       i++;
981       ASSERT_LT(i, opt_param_count);
982       begin_pos = NextWord(target.data, &next_pos);
983       ASSERT_NE(begin_pos, std::string::npos);
984       opt_fec_params[param_name] =
985           target.data.substr(begin_pos, next_pos - begin_pos);
986     } else {
987       ASSERT_NE(opt_params.count(param_name), 0)
988           << "Unknown dm-verity target parameter: " << param_name;
989     }
990   }
991 
992   EXPECT_EQ(opt_fec_params["fec_roots"],
993             std::to_string(descriptor->fec_num_roots));
994   EXPECT_EQ(
995       opt_fec_params["fec_blocks"],
996       std::to_string(descriptor->fec_offset / descriptor->data_block_size));
997   EXPECT_EQ(
998       opt_fec_params["fec_start"],
999       std::to_string(descriptor->fec_offset / descriptor->data_block_size));
1000   // skip use_fec_from_device
1001 
1002   ASSERT_EQ(NextWord(target.data, &next_pos), std::string::npos);
1003 }
1004 
VerifyHashAlgorithm(const AvbHashtreeDescriptor * descriptor)1005 static void VerifyHashAlgorithm(const AvbHashtreeDescriptor* descriptor) {
1006   AvbHashtreeDescriptor hashtree_descriptor;
1007   ASSERT_TRUE(avb_hashtree_descriptor_validate_and_byteswap(
1008       descriptor, &hashtree_descriptor))
1009       << "hash tree descriptor is invalid.";
1010 
1011   auto partition_name_ptr = reinterpret_cast<const uint8_t*>(descriptor) +
1012                             sizeof(AvbHashtreeDescriptor);
1013   std::string partition_name(
1014       partition_name_ptr,
1015       partition_name_ptr + hashtree_descriptor.partition_name_len);
1016 
1017   if (avb_strcmp(
1018           reinterpret_cast<const char*>(hashtree_descriptor.hash_algorithm),
1019           "sha1") == 0) {
1020     FAIL() << "The hash tree algorithm cannot be SHA1 for partition "
1021            << partition_name;
1022   }
1023 }
1024 
1025 // In VTS, a boot-debug.img or vendor_boot-debug.img, which is not release
1026 // key signed, will be used. In this case, The AvbSlotVerifyResult returned
1027 // from libavb->avb_slot_verify() might be the following non-fatal errors.
1028 // We should allow them in VTS because it might not be
1029 // AVB_SLOT_VERIFY_RESULT_OK.
CheckAvbSlotVerifyResult(AvbSlotVerifyResult result)1030 static bool CheckAvbSlotVerifyResult(AvbSlotVerifyResult result) {
1031   switch (result) {
1032     case AVB_SLOT_VERIFY_RESULT_OK:
1033     case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
1034     case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
1035     case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
1036       return true;
1037 
1038     case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
1039     case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
1040     case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
1041     case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
1042     case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
1043       return false;
1044   }
1045 
1046   return false;
1047 }
1048 
LoadAndVerifyAvbSlotDataForCurrentSlot(AvbSlotVerifyData ** avb_slot_data)1049 static void LoadAndVerifyAvbSlotDataForCurrentSlot(
1050     AvbSlotVerifyData** avb_slot_data) {
1051   // Use an empty suffix string for non-A/B devices.
1052   std::string suffix;
1053   if (android::base::GetBoolProperty("ro.build.ab_update", false)) {
1054     suffix = android::base::GetProperty("ro.boot.slot_suffix", "");
1055     ASSERT_TRUE(!suffix.empty()) << "Failed to get suffix for the current slot";
1056   }
1057 
1058   const char* requested_partitions[] = {nullptr};
1059 
1060   // AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is needed for boot-debug.img
1061   // or vendor_boot-debug.img, which is not releae key signed.
1062   auto avb_ops = avb_ops_user_new();
1063   auto verify_result =
1064       avb_slot_verify(avb_ops, requested_partitions, suffix.c_str(),
1065                       AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR,
1066                       AVB_HASHTREE_ERROR_MODE_EIO, avb_slot_data);
1067   ASSERT_TRUE(CheckAvbSlotVerifyResult(verify_result))
1068       << "Failed to verify avb slot data " << verify_result;
1069 }
1070 
1071 // Check the correct hashtree algorithm is used.
TEST(AvbTest,HashtreeAlgorithm)1072 TEST(AvbTest, HashtreeAlgorithm) {
1073   constexpr auto S_API_LEVEL = 31;
1074 
1075   uint32_t board_api_level = GetBoardApiLevel();
1076   GTEST_LOG_(INFO) << "Board API level is " << board_api_level;
1077   if (board_api_level < S_API_LEVEL) {
1078     GTEST_LOG_(INFO)
1079         << "Exempt from avb hash tree test due to old starting API level";
1080     return;
1081   }
1082 
1083   // Note we don't iterate the entries in fstab; because we don't know if a
1084   // partition uses hashtree or not.
1085   AvbSlotVerifyData* avb_slot_data;
1086   LoadAndVerifyAvbSlotDataForCurrentSlot(&avb_slot_data);
1087   ASSERT_NE(nullptr, avb_slot_data) << "Failed to load avb slot verify data";
1088   std::unique_ptr<AvbSlotVerifyData, decltype(&avb_slot_verify_data_free)>
1089       scope_guard(avb_slot_data, avb_slot_verify_data_free);
1090 
1091   // Iterate over the loaded vbmeta structs
1092   for (size_t i = 0; i < avb_slot_data->num_vbmeta_images; i++) {
1093     std::string partition_name = avb_slot_data->vbmeta_images[i].partition_name;
1094     const auto& vbmeta_image = avb_slot_data->vbmeta_images[i];
1095 
1096     size_t num_descriptors;
1097     auto descriptors = avb_descriptor_get_all(
1098         vbmeta_image.vbmeta_data, vbmeta_image.vbmeta_size, &num_descriptors);
1099     // Iterate over the hashtree descriptors
1100     for (size_t n = 0; n < num_descriptors; n++) {
1101       if (avb_be64toh(descriptors[n]->tag) != AVB_DESCRIPTOR_TAG_HASHTREE) {
1102         continue;
1103       }
1104 
1105       VerifyHashAlgorithm(
1106           reinterpret_cast<const AvbHashtreeDescriptor*>(descriptors[n]));
1107     }
1108   }
1109 }
1110