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 <vector>
27 
28 #include <android-base/file.h>
29 #include <android-base/logging.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 <libdm/dm.h>
38 #include <log/log.h>
39 #include <openssl/sha.h>
40 
HexDigitToByte(char c)41 static uint8_t HexDigitToByte(char c) {
42   if (c >= '0' && c <= '9') {
43     return c - '0';
44   }
45   if (c >= 'a' && c <= 'f') {
46     return c - 'a' + 10;
47   }
48   if (c >= 'A' && c <= 'Z') {
49     return c - 'A' + 10;
50   }
51   return 0xff;
52 }
53 
HexToBytes(const std::string & hex,std::vector<uint8_t> * bytes)54 static bool HexToBytes(const std::string &hex, std::vector<uint8_t> *bytes) {
55   if (hex.size() % 2 != 0) {
56     return false;
57   }
58   bytes->resize(hex.size() / 2);
59   for (unsigned i = 0; i < bytes->size(); i++) {
60     uint8_t hi = HexDigitToByte(hex[i * 2]);
61     uint8_t lo = HexDigitToByte(hex[i * 2 + 1]);
62     if (lo > 0xf || hi > 0xf) {
63       return false;
64     }
65     bytes->at(i) = (hi << 4) | lo;
66   }
67   return true;
68 }
69 
70 // The abstract class of SHA algorithms.
71 class ShaHasher {
72  protected:
73   const uint32_t digest_size_;
74 
ShaHasher(uint32_t digest_size)75   ShaHasher(uint32_t digest_size) : digest_size_(digest_size) {}
76 
77  public:
~ShaHasher()78   virtual ~ShaHasher() {}
79 
GetDigestSize() const80   uint32_t GetDigestSize() const { return digest_size_; }
81 
82   virtual bool CalculateDigest(const void *buffer, size_t size,
83                                const void *salt, uint32_t block_length,
84                                uint8_t *digest) const = 0;
85 };
86 
87 template <typename CTX_TYPE>
88 class ShaHasherImpl : public ShaHasher {
89  private:
90   typedef int (*InitFunc)(CTX_TYPE *);
91   typedef int (*UpdateFunc)(CTX_TYPE *sha, const void *data, size_t len);
92   typedef int (*FinalFunc)(uint8_t *md, CTX_TYPE *sha);
93 
94   const InitFunc init_func_;
95   const UpdateFunc update_func_;
96   const FinalFunc final_func_;
97 
98  public:
ShaHasherImpl(InitFunc init_func,UpdateFunc update_func,FinalFunc final_func,uint32_t digest_size)99   ShaHasherImpl(InitFunc init_func, UpdateFunc update_func,
100                 FinalFunc final_func, uint32_t digest_size)
101       : ShaHasher(digest_size),
102         init_func_(init_func),
103         update_func_(update_func),
104         final_func_(final_func) {}
105 
~ShaHasherImpl()106   ~ShaHasherImpl() {}
107 
CalculateDigest(const void * buffer,size_t size,const void * salt,uint32_t salt_length,uint8_t * digest) const108   bool CalculateDigest(const void *buffer, size_t size, const void *salt,
109                        uint32_t salt_length, uint8_t *digest) const {
110     CTX_TYPE ctx;
111     if (init_func_(&ctx) != 1) {
112       return false;
113     }
114     if (update_func_(&ctx, salt, salt_length) != 1) {
115       return false;
116     }
117     if (update_func_(&ctx, buffer, size) != 1) {
118       return false;
119     }
120     if (final_func_(digest, &ctx) != 1) {
121       return false;
122     }
123     return true;
124   }
125 };
126 
127 // Creates a hasher with the parameters corresponding to the algorithm name.
CreateShaHasher(const std::string & algorithm)128 static std::unique_ptr<ShaHasher> CreateShaHasher(
129     const std::string &algorithm) {
130   if (algorithm == "sha1") {
131     return std::make_unique<ShaHasherImpl<SHA_CTX>>(
132         SHA1_Init, SHA1_Update, SHA1_Final, SHA_DIGEST_LENGTH);
133   }
134   if (algorithm == "sha256") {
135     return std::make_unique<ShaHasherImpl<SHA256_CTX>>(
136         SHA256_Init, SHA256_Update, SHA256_Final, SHA256_DIGEST_LENGTH);
137   }
138   if (algorithm == "sha512") {
139     return std::make_unique<ShaHasherImpl<SHA512_CTX>>(
140         SHA512_Init, SHA512_Update, SHA512_Final, SHA512_DIGEST_LENGTH);
141   }
142   return nullptr;
143 }
144 
145 // 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)146 static bool CalculateZeroDigest(const ShaHasher &hasher, size_t size,
147                                 const void *salt, int32_t block_length,
148                                 uint8_t *digest) {
149   const std::vector<uint8_t> buffer(size, 0);
150   return hasher.CalculateDigest(buffer.data(), size, salt, block_length,
151                                 digest);
152 }
153 
154 // Logical structure of a hashtree:
155 //
156 // Level 2:                        [    root     ]
157 //                                /               \
158 // Level 1:              [entry_0]                 [entry_1]
159 //                      /   ...   \                   ...   \
160 // Level 0:   [entry_0_0]   ...   [entry_0_127]       ...   [entry_1_127]
161 //             /  ...  \           /   ...   \               /   ...   \
162 // Data:    blk_0 ... blk_127  blk_16256 ... blk_16383  blk_32640 ... blk_32767
163 //
164 // The digest of a data block or a hash block in level N is stored in level
165 // N + 1.
166 // The function VerifyHashtree allocates a HashtreeLevel for each level. It
167 // calculates the digests of the blocks in lower level and fills them in
168 // calculating_hash_block. When calculating_hash_block is full, it is compared
169 // with the hash block at comparing_tree_offset in the image. After comparison,
170 // calculating_hash_block is cleared and reused for the next hash block.
171 //
172 //                   comparing_tree_offset
173 //                   |
174 //                   v
175 // [<--------------------    level_size    -------------------->]
176 // [entry_0_0]  ...  [entry_0_127           ]  ...  [entry_1_127]
177 //
178 //                   [calculating_hash_block]
179 //                         ^
180 //                         |
181 //                         calculating_offset
182 struct HashtreeLevel {
183   // Offset of an expected hash block to compare, relative to the beginning of
184   // the hashtree in the image file.
185   uint64_t comparing_tree_offset;
186   // Size of this level, in bytes.
187   const uint64_t level_size;
188   // Offset of a digest in calculating_hash_block.
189   size_t calculating_offset;
190   // The hash block containing the digests calculated from the lower level.
191   std::vector<uint8_t> calculating_hash_block;
192 
HashtreeLevelHashtreeLevel193   HashtreeLevel(uint64_t lv_offset, uint64_t lv_size, size_t hash_block_size)
194       : comparing_tree_offset(lv_offset),
195         level_size(lv_size),
196         calculating_offset(0),
197         calculating_hash_block(hash_block_size) {}
198 };
199 
200 // Calculates and verifies the image's hashtree.
201 //
202 // Arguments:
203 //   image_fd: The raw image file.
204 //   image_size, data_block_size, hash_block_size, tree_offset, tree_size: The
205 //       fields in AvbHashtreeDescriptor.
206 //   salt: The binary value of the salt in FsAvbHashtreeDescriptor.
207 //   hasher: The ShaHasher object.
208 //   root_digest: The binary value of the root_digest in
209 //       FsAvbHashtreeDescriptor.
210 //
211 // Returns:
212 //   An empty string if the function succeeds.
213 //   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)214 static std::string VerifyHashtree(int image_fd, uint64_t image_size,
215                                   const std::vector<uint8_t> &salt,
216                                   uint32_t data_block_size,
217                                   uint32_t hash_block_size,
218                                   uint64_t tree_offset, uint64_t tree_size,
219                                   const ShaHasher &hasher,
220                                   const std::vector<uint8_t> &root_digest) {
221   uint32_t digest_size = hasher.GetDigestSize();
222   uint32_t padded_digest_size = 1;
223   while (padded_digest_size < digest_size) {
224     padded_digest_size *= 2;
225   }
226 
227   if (image_size % data_block_size != 0) {
228     return "Image size is not a multiple of data block size";
229   }
230 
231   uint64_t data_block_count = image_size / data_block_size;
232   uint32_t digests_per_block = hash_block_size / padded_digest_size;
233 
234   // Initialize HashtreeLevel in bottom-up order.
235   std::list<HashtreeLevel> levels;
236   {
237     uint64_t hash_block_count = 0;
238     uint32_t level_block_count = data_block_count;
239     // Calculate the hashtree until the root hash is reached.
240     while (level_block_count > 1) {
241       uint32_t next_level_block_count =
242           (level_block_count + digests_per_block - 1) / digests_per_block;
243       hash_block_count += next_level_block_count;
244       // comparing_tree_offset will be initialized later.
245       levels.emplace_back(0 /* comparing_tree_offset */,
246                           next_level_block_count * hash_block_size,
247                           hash_block_size);
248       level_block_count = next_level_block_count;
249     }
250     if (hash_block_count * hash_block_size != tree_size) {
251       return "Block count and tree size mismatch";
252     }
253     // Append the root digest. Its level_size is unused.
254     levels.emplace_back(0 /* comparing_tree_offset */, 0 /* level_size */,
255                         digest_size);
256 
257     // Initialize comparing_tree_offset of each level
258     for (auto level = std::prev(levels.end()); level != levels.begin();
259          level--) {
260       std::prev(level)->comparing_tree_offset =
261           level->comparing_tree_offset + level->level_size;
262     }
263   }
264 
265   std::vector<uint8_t> padded_zero_digest(padded_digest_size, 0);
266   if (!CalculateZeroDigest(hasher, data_block_size, salt.data(), salt.size(),
267                            padded_zero_digest.data())) {
268     return "CalculateZeroDigest fails";
269   }
270 
271   std::vector<uint8_t> data_block(data_block_size);
272   std::vector<uint8_t> tree_block(hash_block_size);
273   for (uint64_t image_offset = 0; image_offset < image_size;
274        image_offset += data_block_size) {
275     ssize_t read_size = TEMP_FAILURE_RETRY(
276         pread64(image_fd, data_block.data(), data_block.size(), image_offset));
277     if (read_size != data_block.size()) {
278       return android::base::StringPrintf(
279           "Fail to read data block at offset %llu",
280           (unsigned long long)image_offset);
281     }
282 
283     bool is_last_data = (image_offset + data_block.size() == image_size);
284     // The block to be digested
285     std::vector<uint8_t> *current_block = &data_block;
286     for (auto level = levels.begin(); true; level++) {
287       uint8_t *current_digest =
288           level->calculating_hash_block.data() + level->calculating_offset;
289       if (!hasher.CalculateDigest(current_block->data(), current_block->size(),
290                                   salt.data(), salt.size(), current_digest)) {
291         return "CalculateDigest fails";
292       }
293       // Stop at root digest
294       if (std::next(level) == levels.end()) {
295         break;
296       }
297 
298       // Pad the digest
299       memset(current_digest + digest_size, 0, padded_digest_size - digest_size);
300       level->calculating_offset += padded_digest_size;
301       // Pad the last hash block of this level
302       if (is_last_data) {
303         memset(
304             level->calculating_hash_block.data() + level->calculating_offset, 0,
305             level->calculating_hash_block.size() - level->calculating_offset);
306       } else if (level->calculating_offset <
307                  level->calculating_hash_block.size()) {
308         // Stop at this level if the hash block is not full, continue to read
309         // more data_blocks from the outside loop for digest calculation
310         break;
311       }
312       // Verify the full hash block
313       // current_block may point to tree_block. Since the following pread64
314       // changes tree_block, do not read current_block in the rest of this
315       // code block.
316       current_block = nullptr;
317       read_size = TEMP_FAILURE_RETRY(
318           pread64(image_fd, tree_block.data(), tree_block.size(),
319                   tree_offset + level->comparing_tree_offset));
320       if (read_size != tree_block.size()) {
321         return android::base::StringPrintf(
322             "Fail to read tree block at offset %llu",
323             (unsigned long long)tree_offset + level->comparing_tree_offset);
324       }
325 
326       for (uint32_t offset = 0; offset < tree_block.size();
327            offset += padded_digest_size) {
328         // If the digest in the hashtree is equal to the digest of zero block,
329         // it indicates the corresponding data block is in DONT_CARE chunk in
330         // sparse image. The block should not be verified.
331         if (level == levels.begin() &&
332             memcmp(tree_block.data() + offset, padded_zero_digest.data(),
333                    padded_digest_size) == 0) {
334           continue;
335         }
336         if (memcmp(tree_block.data() + offset,
337                    level->calculating_hash_block.data() + offset,
338                    padded_digest_size) != 0) {
339           return android::base::StringPrintf(
340               "Hash blocks mismatch, block offset = %llu, digest offset = %u",
341               (unsigned long long)tree_offset + level->comparing_tree_offset,
342               offset);
343         }
344       }
345 
346       level->calculating_offset = 0;
347       level->comparing_tree_offset += hash_block_size;
348       if (level->comparing_tree_offset > tree_size) {
349         return "Tree offset is out of bound";
350       }
351       // Prepare for next/upper level, to calculate the digest of this
352       // hash_block for comparison
353       current_block = &tree_block;
354     }
355   }
356 
357   if (levels.back().calculating_hash_block != root_digest) {
358     return "Root digests mismatch";
359   }
360   return "";
361 }
362 
363 // Converts descriptor.hash_algorithm to std::string.
GetHashAlgorithm(const AvbHashtreeDescriptor & descriptor)364 static std::string GetHashAlgorithm(const AvbHashtreeDescriptor &descriptor) {
365   return std::string(reinterpret_cast<const char *>(descriptor.hash_algorithm));
366 }
367 
368 // Converts descriptor.hash_algorithm to std::string.
GetHashAlgorithm(const AvbHashDescriptor & descriptor)369 static std::string GetHashAlgorithm(const AvbHashDescriptor &descriptor) {
370   return std::string(reinterpret_cast<const char *>(descriptor.hash_algorithm));
371 }
372 
373 // Checks whether the public key is an official GSI key or not.
ValidatePublicKeyBlob(const std::string & key_blob_to_validate)374 static bool ValidatePublicKeyBlob(const std::string &key_blob_to_validate) {
375   if (key_blob_to_validate.empty()) {
376     ALOGE("Failed to validate an empty key");
377     return false;
378   }
379 
380   std::string allowed_key_blob;
381   std::vector<std::string> allowed_key_paths = {
382       "/data/local/tmp/q-gsi.avbpubkey", "/data/local/tmp/r-gsi.avbpubkey",
383       "/data/local/tmp/s-gsi.avbpubkey"};
384   for (const auto &path : allowed_key_paths) {
385     if (android::base::ReadFileToString(path, &allowed_key_blob)) {
386       if (key_blob_to_validate == allowed_key_blob) {
387         ALOGE("Found matching GSI key: %s", path.c_str());
388         return true;
389       }
390     }
391   }
392   return false;
393 }
394 
395 // Gets the system partition's AvbHashtreeDescriptor and device file path.
396 //
397 // Arguments:
398 //  out_verify_result: The result of vbmeta verification.
399 //  out_system_path: The system's device file path.
400 //
401 // Returns:
402 //   The pointer to the system's AvbHashtreeDescriptor.
403 //   nullptr if any operation fails.
404 static std::unique_ptr<android::fs_mgr::FsAvbHashtreeDescriptor>
GetSystemHashtreeDescriptor(android::fs_mgr::VBMetaVerifyResult * out_verify_result,std::string * out_system_path)405 GetSystemHashtreeDescriptor(
406     android::fs_mgr::VBMetaVerifyResult *out_verify_result,
407     std::string *out_system_path) {
408   android::fs_mgr::Fstab default_fstab;
409   bool ok = ReadDefaultFstab(&default_fstab);
410   if (!ok) {
411     ALOGE("ReadDefaultFstab fails");
412     return nullptr;
413   }
414   android::fs_mgr::FstabEntry *system_fstab_entry =
415       GetEntryForPath(&default_fstab, "/system");
416   if (system_fstab_entry == nullptr) {
417     ALOGE("GetEntryForPath fails");
418     return nullptr;
419   }
420 
421   ok = fs_mgr_update_logical_partition(system_fstab_entry);
422   if (!ok) {
423     ALOGE("fs_mgr_update_logical_partition fails");
424     return nullptr;
425   }
426 
427   CHECK(out_system_path != nullptr);
428   *out_system_path = system_fstab_entry->blk_device;
429 
430   std::string out_public_key_data;
431   std::string out_avb_partition_name;
432   std::unique_ptr<android::fs_mgr::VBMetaData> vbmeta =
433       android::fs_mgr::LoadAndVerifyVbmeta(
434           *system_fstab_entry, "" /* expected_key_blob */, &out_public_key_data,
435           &out_avb_partition_name, out_verify_result);
436   if (vbmeta == nullptr) {
437     ALOGE("LoadAndVerifyVbmeta fails");
438     return nullptr;
439   }
440 
441   if (out_public_key_data.empty()) {
442     ALOGE("The GSI image is not signed");
443     return nullptr;
444   }
445 
446   if (!ValidatePublicKeyBlob(out_public_key_data)) {
447     ALOGE("The GSI image is not signed by an official key");
448     return nullptr;
449   }
450 
451   std::unique_ptr<android::fs_mgr::FsAvbHashtreeDescriptor> descriptor =
452       android::fs_mgr::GetHashtreeDescriptor("system", std::move(*vbmeta));
453   if (descriptor == nullptr) {
454     ALOGE("GetHashtreeDescriptor fails");
455     return nullptr;
456   }
457 
458   return descriptor;
459 }
460 
TEST(AvbTest,Boot)461 TEST(AvbTest, Boot) {
462   /* Skip for devices running kernels older than 5.4. */
463   struct utsname buf;
464   int ret, kernel_version_major, kernel_version_minor;
465   ret = uname(&buf);
466   ASSERT_EQ(ret, 0) << "Failed to get kernel version.";
467   char dummy;
468   ret = sscanf(buf.release, "%d.%d%c", &kernel_version_major,
469                &kernel_version_minor, &dummy);
470   ASSERT_GE(ret, 2) << "Failed to parse kernel version.";
471   if (kernel_version_major < 5 ||
472       (kernel_version_major == 5 && kernel_version_minor < 4)) {
473     return;
474   }
475 
476   /* load vbmeta struct from boot, verify struct integrity */
477   std::string out_public_key_data;
478   android::fs_mgr::VBMetaVerifyResult out_verify_result;
479   std::string boot_path = "/dev/block/by-name/boot" + fs_mgr_get_slot_suffix();
480   std::unique_ptr<android::fs_mgr::VBMetaData> vbmeta =
481       android::fs_mgr::LoadAndVerifyVbmetaByPath(
482           boot_path, "boot", "" /* expected_key_blob */,
483           true /* allow verification error */, false /* rollback_protection */,
484           false /* is_chained_vbmeta */, &out_public_key_data,
485           nullptr /* out_verification_disabled */, &out_verify_result);
486 
487   ASSERT_TRUE(vbmeta) << "Verification of GKI vbmeta fails.";
488   ASSERT_FALSE(out_public_key_data.empty()) << "The GKI image is not signed.";
489   EXPECT_TRUE(ValidatePublicKeyBlob(out_public_key_data))
490       << "The GKI image is not signed by an official key.";
491   EXPECT_EQ(out_verify_result, android::fs_mgr::VBMetaVerifyResult::kSuccess)
492       << "Verification of the GKI vbmeta structure failed.";
493 
494   /* verify boot partition according to vbmeta structure */
495   std::unique_ptr<android::fs_mgr::FsAvbHashDescriptor> descriptor =
496       android::fs_mgr::GetHashDescriptor("boot", std::move(*vbmeta));
497   const std::string &salt_str = descriptor->salt;
498   const std::string &expected_digest_str = descriptor->digest;
499 
500   android::base::unique_fd fd(open(boot_path.c_str(), O_RDONLY));
501   ASSERT_GE(fd, 0) << "Fail to open boot partition. Try 'adb root'.";
502 
503   const std::string hash_algorithm(GetHashAlgorithm(*descriptor));
504   ALOGI("hash_algorithm = %s", hash_algorithm.c_str());
505 
506   std::unique_ptr<ShaHasher> hasher = CreateShaHasher(hash_algorithm);
507   ASSERT_TRUE(hasher);
508 
509   std::vector<uint8_t> salt, expected_digest, out_digest;
510   bool ok = HexToBytes(salt_str, &salt);
511   ASSERT_TRUE(ok) << "Invalid salt in descriptor: " << salt_str;
512   ok = HexToBytes(expected_digest_str, &expected_digest);
513   ASSERT_TRUE(ok) << "Invalid digest in descriptor: " << expected_digest_str;
514   ASSERT_EQ(expected_digest.size(), hasher->GetDigestSize());
515 
516   std::vector<char> boot_partition_vector;
517   boot_partition_vector.resize(descriptor->image_size);
518   ASSERT_TRUE(android::base::ReadFully(fd, boot_partition_vector.data(),
519                                        descriptor->image_size))
520       << "Could not read boot partition to vector.";
521 
522   out_digest.resize(hasher->GetDigestSize());
523   ASSERT_TRUE(hasher->CalculateDigest(
524       boot_partition_vector.data(), descriptor->image_size,
525       salt.data(), descriptor->salt_len, out_digest.data()))
526       << "Unable to calculate boot image digest.";
527 
528   ASSERT_TRUE(out_digest.size() == expected_digest.size())
529       << "Calculated GKI boot digest size does not match expected digest size.";
530   ASSERT_TRUE(out_digest == expected_digest)
531       << "Calculated GKI boot digest does not match expected digest.";
532 }
533 
534 // Loads contents and metadata of logical system partition, calculates
535 // the hashtree, and compares with the metadata.
TEST(AvbTest,SystemHashtree)536 TEST(AvbTest, SystemHashtree) {
537   android::fs_mgr::VBMetaVerifyResult verify_result;
538   std::string system_path;
539   std::unique_ptr<android::fs_mgr::FsAvbHashtreeDescriptor> descriptor =
540       GetSystemHashtreeDescriptor(&verify_result, &system_path);
541   ASSERT_TRUE(descriptor);
542 
543   ALOGI("System partition is %s", system_path.c_str());
544 
545   // TODO: Skip assertion when running with non-compliance configuration.
546   EXPECT_EQ(verify_result, android::fs_mgr::VBMetaVerifyResult::kSuccess);
547   EXPECT_NE(verify_result,
548             android::fs_mgr::VBMetaVerifyResult::kErrorVerification)
549       << "The system image is not an officially signed GSI.";
550 
551   const std::string &salt_str = descriptor->salt;
552   const std::string &expected_digest_str = descriptor->root_digest;
553 
554   android::base::unique_fd fd(open(system_path.c_str(), O_RDONLY));
555   ASSERT_GE(fd, 0) << "Fail to open system partition. Try 'adb root'.";
556 
557   const std::string hash_algorithm(GetHashAlgorithm(*descriptor));
558   ALOGI("hash_algorithm = %s", hash_algorithm.c_str());
559 
560   std::unique_ptr<ShaHasher> hasher = CreateShaHasher(hash_algorithm);
561   ASSERT_TRUE(hasher);
562 
563   std::vector<uint8_t> salt, expected_digest;
564   bool ok = HexToBytes(salt_str, &salt);
565   ASSERT_TRUE(ok) << "Invalid salt in descriptor: " << salt_str;
566   ok = HexToBytes(expected_digest_str, &expected_digest);
567   ASSERT_TRUE(ok) << "Invalid digest in descriptor: " << expected_digest_str;
568   ASSERT_EQ(expected_digest.size(), hasher->GetDigestSize());
569 
570   ALOGI("image_size = %llu", (unsigned long long)descriptor->image_size);
571   ALOGI("data_block_size = %u", descriptor->data_block_size);
572   ALOGI("hash_block_size = %u", descriptor->hash_block_size);
573   ALOGI("tree_offset = %llu", (unsigned long long)descriptor->tree_offset);
574   ALOGI("tree_size = %llu", (unsigned long long)descriptor->tree_size);
575 
576   std::string error_message = VerifyHashtree(
577       fd, descriptor->image_size, salt, descriptor->data_block_size,
578       descriptor->hash_block_size, descriptor->tree_offset,
579       descriptor->tree_size, *hasher, expected_digest);
580   ASSERT_EQ(error_message, "");
581 }
582 
583 // Finds the next word consisting of non-whitespace characters in a string.
584 //
585 // Arguments:
586 //   str: The string to be searched for the next word.
587 //   pos: The starting position to search for the next word.
588 //        This function sets it to the past-the-end position of the word.
589 //
590 // Returns:
591 //   The starting position of the word.
592 //   If there is no next word, this function does not change pos and returns
593 //   std::string::npos.
NextWord(const std::string & str,size_t * pos)594 static size_t NextWord(const std::string &str, size_t *pos) {
595   const char *whitespaces = " \t\r\n";
596   size_t start = str.find_first_not_of(whitespaces, *pos);
597   if (start == std::string::npos) {
598     return start;
599   }
600   *pos = str.find_first_of(whitespaces, start);
601   if (*pos == std::string::npos) {
602     *pos = str.size();
603   }
604   return start;
605 }
606 
607 // Compares device mapper table with system hashtree descriptor.
TEST(AvbTest,SystemDescriptor)608 TEST(AvbTest, SystemDescriptor) {
609   // Get system hashtree descriptor.
610 
611   android::fs_mgr::VBMetaVerifyResult verify_result;
612   std::string system_path;
613   std::unique_ptr<android::fs_mgr::FsAvbHashtreeDescriptor> descriptor =
614       GetSystemHashtreeDescriptor(&verify_result, &system_path);
615   ASSERT_TRUE(descriptor);
616 
617   // TODO: Assert when running with compliance configuration.
618   // The SystemHashtree function asserts verify_result.
619   if (verify_result != android::fs_mgr::VBMetaVerifyResult::kSuccess) {
620     ALOGW("The system image is not an officially signed GSI.");
621   }
622 
623   // Get device mapper table.
624   android::dm::DeviceMapper &device_mapper =
625       android::dm::DeviceMapper::Instance();
626   std::vector<android::dm::DeviceMapper::TargetInfo> table;
627   bool ok = device_mapper.GetTableInfo("system-verity", &table);
628   ASSERT_TRUE(ok) << "GetTableInfo fails";
629   ASSERT_EQ(table.size(), 1);
630   const android::dm::DeviceMapper::TargetInfo &target = table[0];
631   // Sample output:
632   // Device mapper table for system-verity:
633   // 0-1783288: verity, 1 253:0 253:0 4096 4096 222911 222911 sha1
634   // 6b2b46715a2d27c53cc7f91fe63ce798ff1f3df7
635   // 65bc99ca8e97379d4f7adc66664941acc0a8e682 10 restart_on_corruption
636   // ignore_zero_blocks use_fec_from_device 253:0 fec_blocks 224668 fec_start
637   // 224668 fec_roots 2
638   ALOGI("Device mapper table for system-verity:\n%llu-%llu: %s, %s",
639         target.spec.sector_start, target.spec.sector_start + target.spec.length,
640         target.spec.target_type, target.data.c_str());
641   EXPECT_EQ(strcmp(target.spec.target_type, "verity"), 0);
642 
643   // Compare the target's positional parameters with the descriptor. Reference:
644   // https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity#mapping-table-for-verity-target
645   std::array<std::string, 10> descriptor_values = {
646       std::to_string(descriptor->dm_verity_version),
647       "",  // skip data_dev
648       "",  // skip hash_dev
649       std::to_string(descriptor->data_block_size),
650       std::to_string(descriptor->hash_block_size),
651       std::to_string(descriptor->image_size /
652                      descriptor->data_block_size),  // #blocks
653       std::to_string(descriptor->image_size /
654                      descriptor->data_block_size),  // hash_start
655       GetHashAlgorithm(*descriptor),
656       descriptor->root_digest,
657       descriptor->salt,
658   };
659 
660   size_t next_pos = 0;
661   for (const std::string &descriptor_value : descriptor_values) {
662     size_t begin_pos = NextWord(target.data, &next_pos);
663     ASSERT_NE(begin_pos, std::string::npos);
664     if (!descriptor_value.empty()) {
665       EXPECT_EQ(target.data.compare(begin_pos, next_pos - begin_pos,
666                                     descriptor_value),
667                 0);
668     }
669   }
670 
671   // Compare the target's optional parameters with the descriptor.
672   unsigned long opt_param_count;
673   {
674     size_t begin_pos = NextWord(target.data, &next_pos);
675     ASSERT_NE(begin_pos, std::string::npos);
676     opt_param_count =
677         std::stoul(target.data.substr(begin_pos, next_pos - begin_pos));
678   }
679   // https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity#optional-parameters
680   std::set<std::string> opt_params = {
681       "check_at_most_once",
682       "ignore_corruption",
683       "ignore_zero_blocks",
684       "restart_on_corruption",
685   };
686   // https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity#optional-fec-forward-error-correction-parameters
687   std::map<std::string, std::string> opt_fec_params = {
688       {"fec_blocks", ""},
689       {"fec_roots", ""},
690       {"fec_start", ""},
691       {"use_fec_from_device", ""},
692   };
693 
694   for (unsigned long i = 0; i < opt_param_count; i++) {
695     size_t begin_pos = NextWord(target.data, &next_pos);
696     ASSERT_NE(begin_pos, std::string::npos);
697     const std::string param_name(target.data, begin_pos, next_pos - begin_pos);
698     if (opt_fec_params.count(param_name)) {
699       i++;
700       ASSERT_LT(i, opt_param_count);
701       begin_pos = NextWord(target.data, &next_pos);
702       ASSERT_NE(begin_pos, std::string::npos);
703       opt_fec_params[param_name] =
704           target.data.substr(begin_pos, next_pos - begin_pos);
705     } else {
706       ASSERT_NE(opt_params.count(param_name), 0)
707           << "Unknown dm-verity target parameter: " << param_name;
708     }
709   }
710 
711   EXPECT_EQ(opt_fec_params["fec_roots"],
712             std::to_string(descriptor->fec_num_roots));
713   EXPECT_EQ(
714       opt_fec_params["fec_blocks"],
715       std::to_string(descriptor->fec_offset / descriptor->data_block_size));
716   EXPECT_EQ(
717       opt_fec_params["fec_start"],
718       std::to_string(descriptor->fec_offset / descriptor->data_block_size));
719   // skip use_fec_from_device
720 
721   ASSERT_EQ(NextWord(target.data, &next_pos), std::string::npos);
722 }
723