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