• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <array>
20 #include <list>
21 #include <map>
22 #include <set>
23 #include <tuple>
24 #include <vector>
25 
26 #include <android-base/file.h>
27 #include <android-base/logging.h>
28 #include <android-base/properties.h>
29 #include <android-base/result.h>
30 #include <android-base/stringprintf.h>
31 #include <android-base/unique_fd.h>
32 #include <fs_avb/fs_avb_util.h>
33 #include <fs_mgr/roots.h>
34 #include <fstab/fstab.h>
35 #include <gtest/gtest.h>
36 #include <libavb/libavb.h>
37 #include <libavb_user/avb_ops_user.h>
38 #include <libdm/dm.h>
39 #include <log/log.h>
40 
41 #include "gsi_validation_utils.h"
42 
43 using android::base::Error;
44 using android::base::Result;
45 
46 // 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)47 static bool CalculateZeroDigest(const ShaHasher &hasher, size_t size,
48                                 const void *salt, int32_t block_length,
49                                 uint8_t *digest) {
50   const std::vector<uint8_t> buffer(size, 0);
51   return hasher.CalculateDigest(buffer.data(), size, salt, block_length,
52                                 digest);
53 }
54 
55 // Logical structure of a hashtree:
56 //
57 // Level 2:                        [    root     ]
58 //                                /               \
59 // Level 1:              [entry_0]                 [entry_1]
60 //                      /   ...   \                   ...   \
61 // Level 0:   [entry_0_0]   ...   [entry_0_127]       ...   [entry_1_127]
62 //             /  ...  \           /   ...   \               /   ...   \
63 // Data:    blk_0 ... blk_127  blk_16256 ... blk_16383  blk_32640 ... blk_32767
64 //
65 // The digest of a data block or a hash block in level N is stored in level
66 // N + 1.
67 // The function VerifyHashtree allocates a HashtreeLevel for each level. It
68 // calculates the digests of the blocks in lower level and fills them in
69 // calculating_hash_block. When calculating_hash_block is full, it is compared
70 // with the hash block at comparing_tree_offset in the image. After comparison,
71 // calculating_hash_block is cleared and reused for the next hash block.
72 //
73 //                   comparing_tree_offset
74 //                   |
75 //                   v
76 // [<--------------------    level_size    -------------------->]
77 // [entry_0_0]  ...  [entry_0_127           ]  ...  [entry_1_127]
78 //
79 //                   [calculating_hash_block]
80 //                         ^
81 //                         |
82 //                         calculating_offset
83 struct HashtreeLevel {
84   // Offset of an expected hash block to compare, relative to the beginning of
85   // the hashtree in the image file.
86   uint64_t comparing_tree_offset;
87   // Size of this level, in bytes.
88   const uint64_t level_size;
89   // Offset of a digest in calculating_hash_block.
90   size_t calculating_offset;
91   // The hash block containing the digests calculated from the lower level.
92   std::vector<uint8_t> calculating_hash_block;
93 
HashtreeLevelHashtreeLevel94   HashtreeLevel(uint64_t lv_offset, uint64_t lv_size, size_t hash_block_size)
95       : comparing_tree_offset(lv_offset),
96         level_size(lv_size),
97         calculating_offset(0),
98         calculating_hash_block(hash_block_size) {}
99 };
100 
101 // Calculates and verifies the image's hashtree.
102 //
103 // Arguments:
104 //   image_fd: The raw image file.
105 //   image_size, data_block_size, hash_block_size, tree_offset, tree_size: The
106 //       fields in AvbHashtreeDescriptor.
107 //   salt: The binary value of the salt in FsAvbHashtreeDescriptor.
108 //   hasher: The ShaHasher object.
109 //   root_digest: The binary value of the root_digest in
110 //       FsAvbHashtreeDescriptor.
111 //
112 // Returns:
113 //   An empty string if the function succeeds.
114 //   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)115 static std::string VerifyHashtree(int image_fd, uint64_t image_size,
116                                   const std::vector<uint8_t> &salt,
117                                   uint32_t data_block_size,
118                                   uint32_t hash_block_size,
119                                   uint64_t tree_offset, uint64_t tree_size,
120                                   const ShaHasher &hasher,
121                                   const std::vector<uint8_t> &root_digest) {
122   uint32_t digest_size = hasher.GetDigestSize();
123   uint32_t padded_digest_size = 1;
124   while (padded_digest_size < digest_size) {
125     padded_digest_size *= 2;
126   }
127 
128   if (image_size % data_block_size != 0) {
129     return "Image size is not a multiple of data block size";
130   }
131 
132   uint64_t data_block_count = image_size / data_block_size;
133   uint32_t digests_per_block = hash_block_size / padded_digest_size;
134 
135   // Initialize HashtreeLevel in bottom-up order.
136   std::list<HashtreeLevel> levels;
137   {
138     uint64_t hash_block_count = 0;
139     uint32_t level_block_count = data_block_count;
140     // Calculate the hashtree until the root hash is reached.
141     while (level_block_count > 1) {
142       uint32_t next_level_block_count =
143           (level_block_count + digests_per_block - 1) / digests_per_block;
144       hash_block_count += next_level_block_count;
145       // comparing_tree_offset will be initialized later.
146       levels.emplace_back(0 /* comparing_tree_offset */,
147                           next_level_block_count * hash_block_size,
148                           hash_block_size);
149       level_block_count = next_level_block_count;
150     }
151     if (hash_block_count * hash_block_size != tree_size) {
152       return "Block count and tree size mismatch";
153     }
154     // Append the root digest. Its level_size is unused.
155     levels.emplace_back(0 /* comparing_tree_offset */, 0 /* level_size */,
156                         digest_size);
157 
158     // Initialize comparing_tree_offset of each level
159     for (auto level = std::prev(levels.end()); level != levels.begin();
160          level--) {
161       std::prev(level)->comparing_tree_offset =
162           level->comparing_tree_offset + level->level_size;
163     }
164   }
165 
166   std::vector<uint8_t> padded_zero_digest(padded_digest_size, 0);
167   if (!CalculateZeroDigest(hasher, data_block_size, salt.data(), salt.size(),
168                            padded_zero_digest.data())) {
169     return "CalculateZeroDigest fails";
170   }
171 
172   std::vector<uint8_t> data_block(data_block_size);
173   std::vector<uint8_t> tree_block(hash_block_size);
174   for (uint64_t image_offset = 0; image_offset < image_size;
175        image_offset += data_block_size) {
176     ssize_t read_size = TEMP_FAILURE_RETRY(
177         pread64(image_fd, data_block.data(), data_block.size(), image_offset));
178     if (read_size != data_block.size()) {
179       return android::base::StringPrintf(
180           "Fail to read data block at offset %llu",
181           (unsigned long long)image_offset);
182     }
183 
184     bool is_last_data = (image_offset + data_block.size() == image_size);
185     // The block to be digested
186     std::vector<uint8_t> *current_block = &data_block;
187     for (auto level = levels.begin(); true; level++) {
188       uint8_t *current_digest =
189           level->calculating_hash_block.data() + level->calculating_offset;
190       if (!hasher.CalculateDigest(current_block->data(), current_block->size(),
191                                   salt.data(), salt.size(), current_digest)) {
192         return "CalculateDigest fails";
193       }
194       // Stop at root digest
195       if (std::next(level) == levels.end()) {
196         break;
197       }
198 
199       // Pad the digest
200       memset(current_digest + digest_size, 0, padded_digest_size - digest_size);
201       level->calculating_offset += padded_digest_size;
202       // Pad the last hash block of this level
203       if (is_last_data) {
204         memset(
205             level->calculating_hash_block.data() + level->calculating_offset, 0,
206             level->calculating_hash_block.size() - level->calculating_offset);
207       } else if (level->calculating_offset <
208                  level->calculating_hash_block.size()) {
209         // Stop at this level if the hash block is not full, continue to read
210         // more data_blocks from the outside loop for digest calculation
211         break;
212       }
213       // Verify the full hash block
214       // current_block may point to tree_block. Since the following pread64
215       // changes tree_block, do not read current_block in the rest of this
216       // code block.
217       current_block = nullptr;
218       read_size = TEMP_FAILURE_RETRY(
219           pread64(image_fd, tree_block.data(), tree_block.size(),
220                   tree_offset + level->comparing_tree_offset));
221       if (read_size != tree_block.size()) {
222         return android::base::StringPrintf(
223             "Fail to read tree block at offset %llu",
224             (unsigned long long)tree_offset + level->comparing_tree_offset);
225       }
226 
227       for (uint32_t offset = 0; offset < tree_block.size();
228            offset += padded_digest_size) {
229         // If the digest in the hashtree is equal to the digest of zero block,
230         // it indicates the corresponding data block is in DONT_CARE chunk in
231         // sparse image. The block should not be verified.
232         if (level == levels.begin() &&
233             memcmp(tree_block.data() + offset, padded_zero_digest.data(),
234                    padded_digest_size) == 0) {
235           continue;
236         }
237         if (memcmp(tree_block.data() + offset,
238                    level->calculating_hash_block.data() + offset,
239                    padded_digest_size) != 0) {
240           return android::base::StringPrintf(
241               "Hash blocks mismatch, block offset = %llu, digest offset = %u",
242               (unsigned long long)tree_offset + level->comparing_tree_offset,
243               offset);
244         }
245       }
246 
247       level->calculating_offset = 0;
248       level->comparing_tree_offset += hash_block_size;
249       if (level->comparing_tree_offset > tree_size) {
250         return "Tree offset is out of bound";
251       }
252       // Prepare for next/upper level, to calculate the digest of this
253       // hash_block for comparison
254       current_block = &tree_block;
255     }
256   }
257 
258   if (levels.back().calculating_hash_block != root_digest) {
259     return "Root digests mismatch";
260   }
261   return "";
262 }
263 
264 // Gets the system partition's AvbHashtreeDescriptor and device file path.
265 //
266 // Arguments:
267 //  out_verify_result: The result of vbmeta verification.
268 //  out_system_path: The system's device file path.
269 //
270 // Returns:
271 //   The pointer to the system's AvbHashtreeDescriptor.
272 //   nullptr if any operation fails.
273 static std::unique_ptr<android::fs_mgr::FsAvbHashtreeDescriptor>
GetSystemHashtreeDescriptor(android::fs_mgr::VBMetaVerifyResult * out_verify_result,std::string * out_system_path)274 GetSystemHashtreeDescriptor(
275     android::fs_mgr::VBMetaVerifyResult *out_verify_result,
276     std::string *out_system_path) {
277   android::fs_mgr::Fstab default_fstab;
278   bool ok = ReadDefaultFstab(&default_fstab);
279   if (!ok) {
280     ALOGE("ReadDefaultFstab fails");
281     return nullptr;
282   }
283   android::fs_mgr::FstabEntry *system_fstab_entry =
284       GetEntryForPath(&default_fstab, "/system");
285   if (system_fstab_entry == nullptr) {
286     ALOGE("GetEntryForPath fails");
287     return nullptr;
288   }
289 
290   ok = fs_mgr_update_logical_partition(system_fstab_entry);
291   if (!ok) {
292     ALOGE("fs_mgr_update_logical_partition fails");
293     return nullptr;
294   }
295 
296   CHECK(out_system_path != nullptr);
297   *out_system_path = system_fstab_entry->blk_device;
298 
299   std::string out_public_key_data;
300   std::string out_avb_partition_name;
301   std::unique_ptr<android::fs_mgr::VBMetaData> vbmeta =
302       android::fs_mgr::LoadAndVerifyVbmeta(
303           *system_fstab_entry, "" /* expected_key_blob */, &out_public_key_data,
304           &out_avb_partition_name, out_verify_result);
305   if (vbmeta == nullptr) {
306     ALOGE("LoadAndVerifyVbmeta fails");
307     return nullptr;
308   }
309 
310   if (out_public_key_data.empty()) {
311     ALOGE("The GSI image is not signed");
312     return nullptr;
313   }
314 
315   if (!ValidatePublicKeyBlob(out_public_key_data)) {
316     ALOGE("The GSI image is not signed by an official key");
317     return nullptr;
318   }
319 
320   std::unique_ptr<android::fs_mgr::FsAvbHashtreeDescriptor> descriptor =
321       android::fs_mgr::GetHashtreeDescriptor("system", std::move(*vbmeta));
322   if (descriptor == nullptr) {
323     ALOGE("GetHashtreeDescriptor fails");
324     return nullptr;
325   }
326 
327   return descriptor;
328 }
329 
330 // Loads contents and metadata of logical system partition, calculates
331 // the hashtree, and compares with the metadata.
TEST(AvbTest,SystemHashtree)332 TEST(AvbTest, SystemHashtree) {
333   android::fs_mgr::VBMetaVerifyResult verify_result;
334   std::string system_path;
335   std::unique_ptr<android::fs_mgr::FsAvbHashtreeDescriptor> descriptor =
336       GetSystemHashtreeDescriptor(&verify_result, &system_path);
337   ASSERT_TRUE(descriptor);
338 
339   ALOGI("System partition is %s", system_path.c_str());
340 
341   // TODO: Skip assertion when running with non-compliance configuration.
342   EXPECT_EQ(verify_result, android::fs_mgr::VBMetaVerifyResult::kSuccess);
343   EXPECT_NE(verify_result,
344             android::fs_mgr::VBMetaVerifyResult::kErrorVerification)
345       << "The system image is not an officially signed GSI.";
346 
347   const std::string &salt_str = descriptor->salt;
348   const std::string &expected_digest_str = descriptor->root_digest;
349 
350   android::base::unique_fd fd(open(system_path.c_str(), O_RDONLY));
351   ASSERT_GE(fd, 0) << "Fail to open system partition. Try 'adb root'.";
352 
353   const std::string hash_algorithm(
354       reinterpret_cast<const char *>(descriptor->hash_algorithm));
355   ALOGI("hash_algorithm = %s", hash_algorithm.c_str());
356 
357   std::unique_ptr<ShaHasher> hasher = CreateShaHasher(hash_algorithm);
358   ASSERT_TRUE(hasher);
359 
360   std::vector<uint8_t> salt, expected_digest;
361   bool ok = HexToBytes(salt_str, &salt);
362   ASSERT_TRUE(ok) << "Invalid salt in descriptor: " << salt_str;
363   ok = HexToBytes(expected_digest_str, &expected_digest);
364   ASSERT_TRUE(ok) << "Invalid digest in descriptor: " << expected_digest_str;
365   ASSERT_EQ(expected_digest.size(), hasher->GetDigestSize());
366 
367   ALOGI("image_size = %llu", (unsigned long long)descriptor->image_size);
368   ALOGI("data_block_size = %u", descriptor->data_block_size);
369   ALOGI("hash_block_size = %u", descriptor->hash_block_size);
370   ALOGI("tree_offset = %llu", (unsigned long long)descriptor->tree_offset);
371   ALOGI("tree_size = %llu", (unsigned long long)descriptor->tree_size);
372 
373   std::string error_message = VerifyHashtree(
374       fd, descriptor->image_size, salt, descriptor->data_block_size,
375       descriptor->hash_block_size, descriptor->tree_offset,
376       descriptor->tree_size, *hasher, expected_digest);
377   ASSERT_EQ(error_message, "");
378 }
379 
380 // Finds the next word consisting of non-whitespace characters in a string.
381 //
382 // Arguments:
383 //   str: The string to be searched for the next word.
384 //   pos: The starting position to search for the next word.
385 //        This function sets it to the past-the-end position of the word.
386 //
387 // Returns:
388 //   The starting position of the word.
389 //   If there is no next word, this function does not change pos and returns
390 //   std::string::npos.
NextWord(const std::string & str,size_t * pos)391 static size_t NextWord(const std::string &str, size_t *pos) {
392   const char *whitespaces = " \t\r\n";
393   size_t start = str.find_first_not_of(whitespaces, *pos);
394   if (start == std::string::npos) {
395     return start;
396   }
397   *pos = str.find_first_of(whitespaces, start);
398   if (*pos == std::string::npos) {
399     *pos = str.size();
400   }
401   return start;
402 }
403 
404 // Compares device mapper table with system hashtree descriptor.
TEST(AvbTest,SystemDescriptor)405 TEST(AvbTest, SystemDescriptor) {
406   // Get system hashtree descriptor.
407 
408   android::fs_mgr::VBMetaVerifyResult verify_result;
409   std::string system_path;
410   std::unique_ptr<android::fs_mgr::FsAvbHashtreeDescriptor> descriptor =
411       GetSystemHashtreeDescriptor(&verify_result, &system_path);
412   ASSERT_TRUE(descriptor);
413 
414   // TODO: Assert when running with compliance configuration.
415   // The SystemHashtree function asserts verify_result.
416   if (verify_result != android::fs_mgr::VBMetaVerifyResult::kSuccess) {
417     ALOGW("The system image is not an officially signed GSI.");
418   }
419 
420   // Get device mapper table.
421   android::dm::DeviceMapper &device_mapper =
422       android::dm::DeviceMapper::Instance();
423   std::vector<android::dm::DeviceMapper::TargetInfo> table;
424   bool ok = device_mapper.GetTableInfo("system-verity", &table);
425   ASSERT_TRUE(ok) << "GetTableInfo fails";
426   ASSERT_EQ(table.size(), 1);
427   const android::dm::DeviceMapper::TargetInfo &target = table[0];
428   // Sample output:
429   // Device mapper table for system-verity:
430   // 0-1783288: verity, 1 253:0 253:0 4096 4096 222911 222911 sha1
431   // 6b2b46715a2d27c53cc7f91fe63ce798ff1f3df7
432   // 65bc99ca8e97379d4f7adc66664941acc0a8e682 10 restart_on_corruption
433   // ignore_zero_blocks use_fec_from_device 253:0 fec_blocks 224668 fec_start
434   // 224668 fec_roots 2
435   ALOGI("Device mapper table for system-verity:\n%llu-%llu: %s, %s",
436         target.spec.sector_start, target.spec.sector_start + target.spec.length,
437         target.spec.target_type, target.data.c_str());
438   EXPECT_EQ(strcmp(target.spec.target_type, "verity"), 0);
439 
440   // Compare the target's positional parameters with the descriptor. Reference:
441   // https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity#mapping-table-for-verity-target
442   std::array<std::string, 10> descriptor_values = {
443       std::to_string(descriptor->dm_verity_version),
444       "",  // skip data_dev
445       "",  // skip hash_dev
446       std::to_string(descriptor->data_block_size),
447       std::to_string(descriptor->hash_block_size),
448       std::to_string(descriptor->image_size /
449                      descriptor->data_block_size),  // #blocks
450       std::to_string(descriptor->image_size /
451                      descriptor->data_block_size),  // hash_start
452       reinterpret_cast<const char *>(descriptor->hash_algorithm),
453       descriptor->root_digest,
454       descriptor->salt,
455   };
456 
457   size_t next_pos = 0;
458   for (const std::string &descriptor_value : descriptor_values) {
459     size_t begin_pos = NextWord(target.data, &next_pos);
460     ASSERT_NE(begin_pos, std::string::npos);
461     if (!descriptor_value.empty()) {
462       EXPECT_EQ(target.data.compare(begin_pos, next_pos - begin_pos,
463                                     descriptor_value),
464                 0);
465     }
466   }
467 
468   // Compare the target's optional parameters with the descriptor.
469   unsigned long opt_param_count;
470   {
471     size_t begin_pos = NextWord(target.data, &next_pos);
472     ASSERT_NE(begin_pos, std::string::npos);
473     opt_param_count =
474         std::stoul(target.data.substr(begin_pos, next_pos - begin_pos));
475   }
476   // https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity#optional-parameters
477   std::set<std::string> opt_params = {
478       "check_at_most_once",
479       "ignore_corruption",
480       "ignore_zero_blocks",
481       "restart_on_corruption",
482   };
483   // https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity#optional-fec-forward-error-correction-parameters
484   std::map<std::string, std::string> opt_fec_params = {
485       {"fec_blocks", ""},
486       {"fec_roots", ""},
487       {"fec_start", ""},
488       {"use_fec_from_device", ""},
489   };
490 
491   for (unsigned long i = 0; i < opt_param_count; i++) {
492     size_t begin_pos = NextWord(target.data, &next_pos);
493     ASSERT_NE(begin_pos, std::string::npos);
494     const std::string param_name(target.data, begin_pos, next_pos - begin_pos);
495     if (opt_fec_params.count(param_name)) {
496       i++;
497       ASSERT_LT(i, opt_param_count);
498       begin_pos = NextWord(target.data, &next_pos);
499       ASSERT_NE(begin_pos, std::string::npos);
500       opt_fec_params[param_name] =
501           target.data.substr(begin_pos, next_pos - begin_pos);
502     } else {
503       ASSERT_NE(opt_params.count(param_name), 0)
504           << "Unknown dm-verity target parameter: " << param_name;
505     }
506   }
507 
508   EXPECT_EQ(opt_fec_params["fec_roots"],
509             std::to_string(descriptor->fec_num_roots));
510   EXPECT_EQ(
511       opt_fec_params["fec_blocks"],
512       std::to_string(descriptor->fec_offset / descriptor->data_block_size));
513   EXPECT_EQ(
514       opt_fec_params["fec_start"],
515       std::to_string(descriptor->fec_offset / descriptor->data_block_size));
516   // skip use_fec_from_device
517 
518   ASSERT_EQ(NextWord(target.data, &next_pos), std::string::npos);
519 }
520 
VerifyHashAlgorithm(const AvbHashtreeDescriptor * descriptor)521 static void VerifyHashAlgorithm(const AvbHashtreeDescriptor* descriptor) {
522   AvbHashtreeDescriptor hashtree_descriptor;
523   ASSERT_TRUE(avb_hashtree_descriptor_validate_and_byteswap(
524       descriptor, &hashtree_descriptor))
525       << "hash tree descriptor is invalid.";
526 
527   auto partition_name_ptr = reinterpret_cast<const uint8_t*>(descriptor) +
528                             sizeof(AvbHashtreeDescriptor);
529   std::string partition_name(
530       partition_name_ptr,
531       partition_name_ptr + hashtree_descriptor.partition_name_len);
532 
533   if (avb_strcmp(
534           reinterpret_cast<const char*>(hashtree_descriptor.hash_algorithm),
535           "sha1") == 0) {
536     FAIL() << "The hash tree algorithm cannot be SHA1 for partition "
537            << partition_name;
538   }
539 }
540 
541 // In VTS, a boot-debug.img or vendor_boot-debug.img, which is not release
542 // key signed, will be used. In this case, The AvbSlotVerifyResult returned
543 // from libavb->avb_slot_verify() might be the following non-fatal errors.
544 // We should allow them in VTS because it might not be
545 // AVB_SLOT_VERIFY_RESULT_OK.
CheckAvbSlotVerifyResult(AvbSlotVerifyResult result)546 static bool CheckAvbSlotVerifyResult(AvbSlotVerifyResult result) {
547   switch (result) {
548     case AVB_SLOT_VERIFY_RESULT_OK:
549     case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
550     case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
551     case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
552       return true;
553 
554     case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
555     case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
556     case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
557     case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
558     case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
559       return false;
560   }
561 
562   return false;
563 }
564 
LoadAndVerifyAvbSlotDataForCurrentSlot(AvbSlotVerifyData ** avb_slot_data)565 static void LoadAndVerifyAvbSlotDataForCurrentSlot(
566     AvbSlotVerifyData** avb_slot_data) {
567   // Use an empty suffix string for non-A/B devices.
568   std::string suffix;
569   if (android::base::GetBoolProperty("ro.build.ab_update", false)) {
570     suffix = android::base::GetProperty("ro.boot.slot_suffix", "");
571     ASSERT_TRUE(!suffix.empty()) << "Failed to get suffix for the current slot";
572   }
573 
574   const char* requested_partitions[] = {nullptr};
575 
576   // AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is needed for boot-debug.img
577   // or vendor_boot-debug.img, which is not releae key signed.
578   auto avb_ops = avb_ops_user_new();
579   auto verify_result =
580       avb_slot_verify(avb_ops, requested_partitions, suffix.c_str(),
581                       AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR,
582                       AVB_HASHTREE_ERROR_MODE_EIO, avb_slot_data);
583   ASSERT_TRUE(CheckAvbSlotVerifyResult(verify_result))
584       << "Failed to verify avb slot data " << verify_result;
585 }
586 
587 // Check the correct hashtree algorithm is used.
TEST(AvbTest,HashtreeAlgorithm)588 TEST(AvbTest, HashtreeAlgorithm) {
589   constexpr auto S_API_LEVEL = 31;
590 
591   uint32_t board_api_level = GetBoardApiLevel();
592   GTEST_LOG_(INFO) << "Board API level is " << board_api_level;
593   if (board_api_level < S_API_LEVEL) {
594     GTEST_LOG_(INFO)
595         << "Exempt from avb hash tree test due to old starting API level";
596     return;
597   }
598 
599   // Note we don't iterate the entries in fstab; because we don't know if a
600   // partition uses hashtree or not.
601   AvbSlotVerifyData* avb_slot_data;
602   LoadAndVerifyAvbSlotDataForCurrentSlot(&avb_slot_data);
603   ASSERT_NE(nullptr, avb_slot_data) << "Failed to load avb slot verify data";
604   std::unique_ptr<AvbSlotVerifyData, decltype(&avb_slot_verify_data_free)>
605       scope_guard(avb_slot_data, avb_slot_verify_data_free);
606 
607   // Iterate over the loaded vbmeta structs
608   for (size_t i = 0; i < avb_slot_data->num_vbmeta_images; i++) {
609     std::string partition_name = avb_slot_data->vbmeta_images[i].partition_name;
610     const auto& vbmeta_image = avb_slot_data->vbmeta_images[i];
611 
612     size_t num_descriptors;
613     auto descriptors = avb_descriptor_get_all(
614         vbmeta_image.vbmeta_data, vbmeta_image.vbmeta_size, &num_descriptors);
615     // Iterate over the hashtree descriptors
616     for (size_t n = 0; n < num_descriptors; n++) {
617       if (avb_be64toh(descriptors[n]->tag) != AVB_DESCRIPTOR_TAG_HASHTREE) {
618         continue;
619       }
620 
621       VerifyHashAlgorithm(
622           reinterpret_cast<const AvbHashtreeDescriptor*>(descriptors[n]));
623     }
624   }
625 }
626