1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#include <iostream>
26
27#include <endian.h>
28#include <inttypes.h>
29#include <string.h>
30
31#include <base/files/file_util.h>
32#include <base/strings/string_split.h>
33#include <base/strings/string_util.h>
34#include <base/strings/stringprintf.h>
35
36#include <libavb/avb_sha.h>
37#include <libavb/libavb.h>
38
39#include "avb_unittest_util.h"
40
41namespace avb {
42
43class AvbToolTest : public BaseAvbToolTest {
44 public:
45  AvbToolTest() {}
46
47  void AddHashFooterTest(bool sparse_image);
48  void AddHashtreeFooterTest(bool sparse_image);
49  void AddHashtreeFooterFECTest(bool sparse_image);
50};
51
52// This test ensure that the version is increased in both
53// avb_boot_image.h and the avb tool.
54TEST_F(AvbToolTest, AvbVersionInSync) {
55  base::FilePath path = testdir_.Append("version.txt");
56  EXPECT_COMMAND(0, "./avbtool version > %s", path.value().c_str());
57  std::string printed_version;
58  ASSERT_TRUE(base::ReadFileToString(path, &printed_version));
59  base::TrimWhitespaceASCII(printed_version, base::TRIM_ALL, &printed_version);
60  // See comments in libavb/avb_version.c and avbtool's get_release_string()
61  // about being in sync.
62  EXPECT_EQ(printed_version,
63            std::string("avbtool ") + std::string(avb_version_string()));
64}
65
66TEST_F(AvbToolTest, DefaultReleaseString) {
67  GenerateVBMetaImage("vbmeta.img",
68                      "SHA256_RSA2048",
69                      0,
70                      base::FilePath("test/data/testkey_rsa2048.pem"));
71
72  // Default release string is "avbtool " + avb_version_string().
73  AvbVBMetaImageHeader h;
74  avb_vbmeta_image_header_to_host_byte_order(
75      reinterpret_cast<AvbVBMetaImageHeader*>(vbmeta_image_.data()), &h);
76  EXPECT_EQ(std::string("avbtool ") + std::string(avb_version_string()),
77            std::string((const char*)h.release_string));
78}
79
80TEST_F(AvbToolTest, ReleaseStringAppend) {
81  GenerateVBMetaImage("vbmeta.img",
82                      "SHA256_RSA2048",
83                      0,
84                      base::FilePath("test/data/testkey_rsa2048.pem"),
85                      "--append_to_release_string \"Woot XYZ\"");
86
87  // Note that avbtool inserts the space by itself.
88  std::string expected_str =
89      std::string("avbtool ") + std::string(avb_version_string()) + " Woot XYZ";
90
91  AvbVBMetaImageHeader h;
92  avb_vbmeta_image_header_to_host_byte_order(
93      reinterpret_cast<AvbVBMetaImageHeader*>(vbmeta_image_.data()), &h);
94  EXPECT_EQ(expected_str, std::string((const char*)h.release_string));
95}
96
97TEST_F(AvbToolTest, ReleaseStringAppendTruncated) {
98  // Append enough text that truncation is sure to happen.
99  std::string append_str = "0123456789abcdef0123456789abcdef0123456789abcdef";
100  std::string expected_str = std::string("avbtool ") +
101                             std::string(avb_version_string()) + " " +
102                             append_str;
103  EXPECT_GT(expected_str.size(), (size_t)(AVB_RELEASE_STRING_SIZE - 1));
104  expected_str.resize(AVB_RELEASE_STRING_SIZE - 1);
105
106  GenerateVBMetaImage(
107      "vbmeta.img",
108      "SHA256_RSA2048",
109      0,
110      base::FilePath("test/data/testkey_rsa2048.pem"),
111      std::string("--append_to_release_string \"") + append_str + "\"");
112
113  // This checks that it ends with a NUL byte.
114  EXPECT_EQ(AVB_VBMETA_VERIFY_RESULT_OK,
115            avb_vbmeta_image_verify(
116                vbmeta_image_.data(), vbmeta_image_.size(), nullptr, nullptr));
117
118  // For good measure we also check here.
119  AvbVBMetaImageHeader h;
120  avb_vbmeta_image_header_to_host_byte_order(
121      reinterpret_cast<AvbVBMetaImageHeader*>(vbmeta_image_.data()), &h);
122  EXPECT_EQ(expected_str, std::string((const char*)h.release_string));
123}
124
125TEST_F(AvbToolTest, ExtractPublicKey) {
126  GenerateVBMetaImage("vbmeta.img",
127                      "SHA256_RSA2048",
128                      0,
129                      base::FilePath("test/data/testkey_rsa2048.pem"),
130                      "--internal_release_string \"\"");
131
132  std::string key_data =
133      PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem"));
134
135  AvbVBMetaImageHeader h;
136  avb_vbmeta_image_header_to_host_byte_order(
137      reinterpret_cast<AvbVBMetaImageHeader*>(vbmeta_image_.data()), &h);
138  uint8_t* d = reinterpret_cast<uint8_t*>(vbmeta_image_.data());
139  size_t auxiliary_data_block_offset =
140      sizeof(AvbVBMetaImageHeader) + h.authentication_data_block_size;
141  EXPECT_GT(h.auxiliary_data_block_size, key_data.size());
142  EXPECT_EQ(0,
143            memcmp(key_data.data(),
144                   d + auxiliary_data_block_offset + h.public_key_offset,
145                   key_data.size()));
146}
147
148TEST_F(AvbToolTest, CheckDescriptors) {
149  GenerateVBMetaImage("vbmeta.img",
150                      "SHA256_RSA2048",
151                      0,
152                      base::FilePath("test/data/testkey_rsa2048.pem"),
153                      "--prop foo:brillo "
154                      "--prop bar:chromeos "
155                      "--prop prisoner:24601 "
156                      "--prop hexnumber:0xcafe "
157                      "--prop hexnumber_capital:0xCAFE "
158                      "--prop large_hexnumber:0xfedcba9876543210 "
159                      "--prop larger_than_uint64:0xfedcba98765432101 "
160                      "--prop almost_a_number:423x "
161                      "--prop_from_file blob:test/data/small_blob.bin "
162                      "--internal_release_string \"\"");
163
164  AvbVBMetaImageHeader h;
165  avb_vbmeta_image_header_to_host_byte_order(
166      reinterpret_cast<AvbVBMetaImageHeader*>(vbmeta_image_.data()), &h);
167
168  EXPECT_EQ(AVB_VBMETA_VERIFY_RESULT_OK,
169            avb_vbmeta_image_verify(
170                vbmeta_image_.data(), vbmeta_image_.size(), nullptr, nullptr));
171
172  const char* s;
173  size_t len;
174  uint64_t val;
175
176  // Basic.
177  s = avb_property_lookup(
178      vbmeta_image_.data(), vbmeta_image_.size(), "foo", 0, &len);
179  EXPECT_EQ(0, strcmp(s, "brillo"));
180  EXPECT_EQ(6U, len);
181  s = avb_property_lookup(
182      vbmeta_image_.data(), vbmeta_image_.size(), "bar", 0, &len);
183  EXPECT_EQ(0, strcmp(s, "chromeos"));
184  EXPECT_EQ(8U, len);
185  s = avb_property_lookup(
186      vbmeta_image_.data(), vbmeta_image_.size(), "non-existant", 0, &len);
187  EXPECT_EQ(0U, len);
188  EXPECT_EQ(NULL, s);
189
190  // Numbers.
191  EXPECT_NE(
192      0,
193      avb_property_lookup_uint64(
194          vbmeta_image_.data(), vbmeta_image_.size(), "prisoner", 0, &val));
195  EXPECT_EQ(24601U, val);
196
197  EXPECT_NE(
198      0,
199      avb_property_lookup_uint64(
200          vbmeta_image_.data(), vbmeta_image_.size(), "hexnumber", 0, &val));
201  EXPECT_EQ(0xcafeU, val);
202
203  EXPECT_NE(0,
204            avb_property_lookup_uint64(vbmeta_image_.data(),
205                                       vbmeta_image_.size(),
206                                       "hexnumber_capital",
207                                       0,
208                                       &val));
209  EXPECT_EQ(0xcafeU, val);
210
211  EXPECT_NE(0,
212            avb_property_lookup_uint64(vbmeta_image_.data(),
213                                       vbmeta_image_.size(),
214                                       "large_hexnumber",
215                                       0,
216                                       &val));
217  EXPECT_EQ(0xfedcba9876543210U, val);
218
219  // We could catch overflows and return an error ... but we currently don't.
220  EXPECT_NE(0,
221            avb_property_lookup_uint64(vbmeta_image_.data(),
222                                       vbmeta_image_.size(),
223                                       "larger_than_uint64",
224                                       0,
225                                       &val));
226  EXPECT_EQ(0xedcba98765432101U, val);
227
228  // Number-parsing failures.
229  EXPECT_EQ(0,
230            avb_property_lookup_uint64(
231                vbmeta_image_.data(), vbmeta_image_.size(), "foo", 0, &val));
232
233  EXPECT_EQ(0,
234            avb_property_lookup_uint64(vbmeta_image_.data(),
235                                       vbmeta_image_.size(),
236                                       "almost_a_number",
237                                       0,
238                                       &val));
239
240  // Blobs.
241  //
242  // test/data/small_blob.bin is 21 byte file full of NUL-bytes except
243  // for the string "brillo ftw!" at index 2 and '\n' at the last
244  // byte.
245  s = avb_property_lookup(
246      vbmeta_image_.data(), vbmeta_image_.size(), "blob", 0, &len);
247  EXPECT_EQ(21U, len);
248  EXPECT_EQ(0, memcmp(s, "\0\0", 2));
249  EXPECT_EQ(0, memcmp(s + 2, "brillo ftw!", 11));
250  EXPECT_EQ(0, memcmp(s + 13, "\0\0\0\0\0\0\0", 7));
251  EXPECT_EQ('\n', s[20]);
252}
253
254TEST_F(AvbToolTest, CheckRollbackIndex) {
255  uint64_t rollback_index = 42;
256  GenerateVBMetaImage("vbmeta.img",
257                      "SHA256_RSA2048",
258                      rollback_index,
259                      base::FilePath("test/data/testkey_rsa2048.pem"),
260                      "--internal_release_string \"\"");
261
262  AvbVBMetaImageHeader h;
263  avb_vbmeta_image_header_to_host_byte_order(
264      reinterpret_cast<AvbVBMetaImageHeader*>(vbmeta_image_.data()), &h);
265
266  EXPECT_EQ(rollback_index, h.rollback_index);
267}
268
269TEST_F(AvbToolTest, CheckPubkeyReturned) {
270  GenerateVBMetaImage("vbmeta.img",
271                      "SHA256_RSA2048",
272                      0,
273                      base::FilePath("test/data/testkey_rsa2048.pem"),
274                      "--internal_release_string \"\"");
275
276  const uint8_t* pubkey = NULL;
277  size_t pubkey_length = 0;
278
279  EXPECT_EQ(
280      AVB_VBMETA_VERIFY_RESULT_OK,
281      avb_vbmeta_image_verify(
282          vbmeta_image_.data(), vbmeta_image_.size(), &pubkey, &pubkey_length));
283
284  AvbVBMetaImageHeader h;
285  avb_vbmeta_image_header_to_host_byte_order(
286      reinterpret_cast<AvbVBMetaImageHeader*>(vbmeta_image_.data()), &h);
287
288  EXPECT_EQ(pubkey_length, h.public_key_size);
289
290  const uint8_t* expected_pubkey =
291      vbmeta_image_.data() + sizeof(AvbVBMetaImageHeader) +
292      h.authentication_data_block_size + h.public_key_offset;
293  EXPECT_EQ(pubkey, expected_pubkey);
294}
295
296TEST_F(AvbToolTest, Info) {
297  GenerateVBMetaImage("vbmeta.img",
298                      "SHA256_RSA2048",
299                      0,
300                      base::FilePath("test/data/testkey_rsa2048.pem"),
301                      "--prop foo:brillo "
302                      "--prop bar:chromeos "
303                      "--prop prisoner:24601 "
304                      "--prop hexnumber:0xcafe "
305                      "--prop hexnumber_capital:0xCAFE "
306                      "--prop large_hexnumber:0xfedcba9876543210 "
307                      "--prop larger_than_uint64:0xfedcba98765432101 "
308                      "--prop almost_a_number:423x "
309                      "--prop_from_file blob:test/data/small_blob.bin "
310                      "--prop_from_file large_blob:test/data/large_blob.bin "
311                      "--internal_release_string \"\"");
312
313  ASSERT_EQ(
314      "Minimum libavb version:   1.0\n"
315      "Header Block:             256 bytes\n"
316      "Authentication Block:     320 bytes\n"
317      "Auxiliary Block:          3200 bytes\n"
318      "Algorithm:                SHA256_RSA2048\n"
319      "Rollback Index:           0\n"
320      "Flags:                    0\n"
321      "Release String:           ''\n"
322      "Descriptors:\n"
323      "    Prop: foo -> 'brillo'\n"
324      "    Prop: bar -> 'chromeos'\n"
325      "    Prop: prisoner -> '24601'\n"
326      "    Prop: hexnumber -> '0xcafe'\n"
327      "    Prop: hexnumber_capital -> '0xCAFE'\n"
328      "    Prop: large_hexnumber -> '0xfedcba9876543210'\n"
329      "    Prop: larger_than_uint64 -> '0xfedcba98765432101'\n"
330      "    Prop: almost_a_number -> '423x'\n"
331      "    Prop: blob -> '\\x00\\x00brillo "
332      "ftw!\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\n'\n"
333      "    Prop: large_blob -> (2048 bytes)\n",
334      InfoImage(vbmeta_image_path_));
335}
336
337static bool collect_descriptors(const AvbDescriptor* descriptor,
338                                void* user_data) {
339  std::vector<const AvbDescriptor*>* descriptors =
340      reinterpret_cast<std::vector<const AvbDescriptor*>*>(user_data);
341  descriptors->push_back(descriptor);
342  return true;  // Keep iterating.
343}
344
345void AvbToolTest::AddHashFooterTest(bool sparse_image) {
346  const size_t rootfs_size = 1028 * 1024;
347  const size_t partition_size = 1536 * 1024;
348
349  // Generate a 1028 KiB file with known content. Some content have
350  // been arranged to ensure FILL_DATA segments in the sparse file.
351  std::vector<uint8_t> rootfs;
352  rootfs.resize(rootfs_size);
353  for (size_t n = 0; n < rootfs_size; n++) {
354    if ((n >= 5 * 1000 && n < 105 * 1000) ||
355        (n >= 205 * 1000 && n < 305 * 1000) ||
356        (n >= 505 * 1000 && n < 605 * 1000)) {
357      rootfs[n] = uint8_t(n) & 0x03;
358    } else {
359      rootfs[n] = uint8_t(n);
360    }
361  }
362  base::FilePath ext_vbmeta_path = testdir_.Append("ext_vbmeta.bin");
363  base::FilePath rootfs_path = testdir_.Append("rootfs.bin");
364  EXPECT_EQ(rootfs_size,
365            static_cast<const size_t>(
366                base::WriteFile(rootfs_path,
367                                reinterpret_cast<const char*>(rootfs.data()),
368                                rootfs.size())));
369
370  if (sparse_image) {
371    EXPECT_COMMAND(0,
372                   "mv %s %s.unsparse",
373                   rootfs_path.value().c_str(),
374                   rootfs_path.value().c_str());
375    EXPECT_COMMAND(0,
376                   "img2simg %s.unsparse %s",
377                   rootfs_path.value().c_str(),
378                   rootfs_path.value().c_str());
379    EXPECT_COMMAND(0, "rm -f %s.unsparse", rootfs_path.value().c_str());
380  }
381
382  /* Do this twice to check that 'add_hash_footer' is idempotent. */
383  for (int n = 0; n < 2; n++) {
384    EXPECT_COMMAND(0,
385                   "./avbtool add_hash_footer --salt d00df00d "
386                   "--hash_algorithm sha256 --image %s "
387                   "--partition_size %d --partition_name foobar "
388                   "--algorithm SHA256_RSA2048 "
389                   "--key test/data/testkey_rsa2048.pem "
390                   "--output_vbmeta %s "
391                   "--internal_release_string \"\"",
392                   rootfs_path.value().c_str(),
393                   (int)partition_size,
394                   ext_vbmeta_path.value().c_str());
395
396    ASSERT_EQ(base::StringPrintf("Footer version:           1.0\n"
397                                 "Image size:               1572864 bytes\n"
398                                 "Original image size:      1052672 bytes\n"
399                                 "VBMeta offset:            1052672\n"
400                                 "VBMeta size:              1280 bytes\n"
401                                 "--\n"
402                                 "Minimum libavb version:   1.0%s\n"
403                                 "Header Block:             256 bytes\n"
404                                 "Authentication Block:     320 bytes\n"
405                                 "Auxiliary Block:          704 bytes\n"
406                                 "Algorithm:                SHA256_RSA2048\n"
407                                 "Rollback Index:           0\n"
408                                 "Flags:                    0\n"
409                                 "Release String:           ''\n"
410                                 "Descriptors:\n"
411                                 "    Hash descriptor:\n"
412                                 "      Image Size:            1052672 bytes\n"
413                                 "      Hash Algorithm:        sha256\n"
414                                 "      Partition Name:        foobar\n"
415                                 "      Salt:                  d00df00d\n"
416                                 "      Digest:                "
417                                 "9a58cc996d405e08a1e00f96dbfe9104fedf41cb83b1f"
418                                 "5e4ed357fbcf58d88d9\n",
419                                 sparse_image ? " (Sparse)" : ""),
420              InfoImage(rootfs_path));
421
422    ASSERT_EQ(
423        "Minimum libavb version:   1.0\n"
424        "Header Block:             256 bytes\n"
425        "Authentication Block:     320 bytes\n"
426        "Auxiliary Block:          704 bytes\n"
427        "Algorithm:                SHA256_RSA2048\n"
428        "Rollback Index:           0\n"
429        "Flags:                    0\n"
430        "Release String:           ''\n"
431        "Descriptors:\n"
432        "    Hash descriptor:\n"
433        "      Image Size:            1052672 bytes\n"
434        "      Hash Algorithm:        sha256\n"
435        "      Partition Name:        foobar\n"
436        "      Salt:                  d00df00d\n"
437        "      Digest:                "
438        "9a58cc996d405e08a1e00f96dbfe9104fedf41cb83b1f"
439        "5e4ed357fbcf58d88d9\n",
440        InfoImage(ext_vbmeta_path));
441  }
442
443  if (sparse_image) {
444    EXPECT_COMMAND(0,
445                   "mv %s %s.sparse",
446                   rootfs_path.value().c_str(),
447                   rootfs_path.value().c_str());
448    EXPECT_COMMAND(0,
449                   "simg2img %s.sparse %s",
450                   rootfs_path.value().c_str(),
451                   rootfs_path.value().c_str());
452    EXPECT_COMMAND(0, "rm -f %s.sparse", rootfs_path.value().c_str());
453  }
454
455  // Manually calculate the hash to check that it agrees with avbtool.
456  AvbSHA256Ctx hasher_ctx;
457  const uint8_t hasher_salt[4] = {0xd0, 0x0d, 0xf0, 0x0d};
458  avb_sha256_init(&hasher_ctx);
459  avb_sha256_update(&hasher_ctx, hasher_salt, 4);
460  avb_sha256_update(&hasher_ctx, rootfs.data(), rootfs_size);
461  uint8_t* hasher_digest = avb_sha256_final(&hasher_ctx);
462  EXPECT_EQ("9a58cc996d405e08a1e00f96dbfe9104fedf41cb83b1f5e4ed357fbcf58d88d9",
463            mem_to_hexstring(hasher_digest, AVB_SHA256_DIGEST_SIZE));
464
465  // Now check that we can find the VBMeta block again from the footer.
466  std::string part_data;
467  ASSERT_TRUE(base::ReadFileToString(rootfs_path, &part_data));
468
469  // Check footer contains correct data.
470  AvbFooter f;
471  EXPECT_NE(0,
472            avb_footer_validate_and_byteswap(
473                reinterpret_cast<const AvbFooter*>(
474                    part_data.data() + part_data.size() - AVB_FOOTER_SIZE),
475                &f));
476  EXPECT_EQ(
477      std::string(reinterpret_cast<const char*>(f.magic), AVB_FOOTER_MAGIC_LEN),
478      AVB_FOOTER_MAGIC);
479  EXPECT_EQ(AVB_FOOTER_VERSION_MAJOR, (int)f.version_major);
480  EXPECT_EQ(AVB_FOOTER_VERSION_MINOR, (int)f.version_minor);
481  EXPECT_EQ(1052672UL, f.original_image_size);
482  EXPECT_EQ(1052672UL, f.vbmeta_offset);
483  EXPECT_EQ(1280UL, f.vbmeta_size);
484
485  // Check that the vbmeta image at |f.vbmeta_offset| checks out.
486  const uint8_t* vbmeta_data =
487      reinterpret_cast<const uint8_t*>(part_data.data() + f.vbmeta_offset);
488  EXPECT_EQ(AVB_VBMETA_VERIFY_RESULT_OK,
489            avb_vbmeta_image_verify(vbmeta_data, f.vbmeta_size, NULL, NULL));
490
491  // Collect all descriptors.
492  std::vector<const AvbDescriptor*> descriptors;
493  avb_descriptor_foreach(
494      vbmeta_data, f.vbmeta_size, collect_descriptors, &descriptors);
495
496  // We should only have a single descriptor and it should be a
497  // hash descriptor.
498  EXPECT_EQ(1UL, descriptors.size());
499  EXPECT_EQ(AVB_DESCRIPTOR_TAG_HASH, avb_be64toh(descriptors[0]->tag));
500  AvbHashDescriptor d;
501  EXPECT_NE(
502      0,
503      avb_hash_descriptor_validate_and_byteswap(
504          reinterpret_cast<const AvbHashDescriptor*>(descriptors[0]), &d));
505  EXPECT_EQ(1052672UL, d.image_size);
506  EXPECT_EQ(6UL, d.partition_name_len);
507  EXPECT_EQ(4UL, d.salt_len);
508  EXPECT_EQ(32UL, d.digest_len);
509  const uint8_t* desc_end = reinterpret_cast<const uint8_t*>(descriptors[0]) +
510                            sizeof(AvbHashDescriptor);
511  uint64_t o = 0;
512  EXPECT_EQ("foobar",
513            std::string(reinterpret_cast<const char*>(desc_end + o),
514                        d.partition_name_len));
515  o += d.partition_name_len;
516  EXPECT_EQ("d00df00d", mem_to_hexstring(desc_end + o, d.salt_len));
517  o += d.salt_len;
518  EXPECT_EQ("9a58cc996d405e08a1e00f96dbfe9104fedf41cb83b1f5e4ed357fbcf58d88d9",
519            mem_to_hexstring(desc_end + o, d.digest_len));
520
521  // Check that the footer is correctly erased.
522  EXPECT_COMMAND(
523      0, "./avbtool erase_footer --image %s", rootfs_path.value().c_str());
524  int64_t erased_footer_file_size;
525  ASSERT_TRUE(base::GetFileSize(rootfs_path, &erased_footer_file_size));
526  EXPECT_EQ(static_cast<size_t>(erased_footer_file_size), rootfs_size);
527
528  // Check that --do_not_append_vbmeta_image works as intended.
529  EXPECT_COMMAND(0,
530                 "./avbtool add_hash_footer --salt d00df00d "
531                 "--hash_algorithm sha256 --image %s "
532                 "--partition_size %d --partition_name foobar "
533                 "--algorithm SHA256_RSA2048 "
534                 "--key test/data/testkey_rsa2048.pem "
535                 "--output_vbmeta %s_2nd_run --do_not_append_vbmeta_image "
536                 "--internal_release_string \"\"",
537                 rootfs_path.value().c_str(),
538                 (int)partition_size,
539                 ext_vbmeta_path.value().c_str());
540  int64_t file_size;
541  ASSERT_TRUE(base::GetFileSize(rootfs_path, &file_size));
542  EXPECT_EQ(static_cast<size_t>(file_size), rootfs_size);
543  EXPECT_COMMAND(0,
544                 "diff %s %s_2nd_run",
545                 ext_vbmeta_path.value().c_str(),
546                 ext_vbmeta_path.value().c_str());
547}
548
549TEST_F(AvbToolTest, AddHashFooter) {
550  AddHashFooterTest(false);
551}
552
553TEST_F(AvbToolTest, AddHashFooterSparse) {
554  AddHashFooterTest(true);
555}
556
557static std::string RemoveLinesStartingWith(const std::string& str,
558                                           const std::string& prefix) {
559  std::vector<std::string> lines;
560  std::string ret;
561
562  lines = base::SplitString(
563      str, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
564  for (const std::string& line : lines) {
565    if (!base::StartsWith(line, prefix, base::CompareCase::SENSITIVE)) {
566      ret += line;
567      ret += '\n';
568    }
569  }
570  return ret;
571}
572
573TEST_F(AvbToolTest, AddHashFooterSparseWithHoleAtTheEnd) {
574  const size_t partition_size = 10 * 1024 * 1024;
575  const size_t metadata_size = 128 * 1024;
576
577  // It's not enough to run img2simg on a file with a lot of zeroes at
578  // the end since that will turn up as "Fill with value (for value =
579  // 0x00000000)" and not "Don't care". Instead, use make_ext4fs for
580  // this since it will put a big hole (e.g. "Don't care" chunk) at
581  // the end.
582  base::FilePath partition_path = testdir_.Append("partition.bin");
583  EXPECT_COMMAND(0,
584                 "make_ext4fs -s -L test -l %zd %s",
585                 partition_size - metadata_size,
586                 partition_path.value().c_str());
587
588  EXPECT_COMMAND(0,
589                 "./avbtool add_hash_footer --salt d00df00d "
590                 "--hash_algorithm sha256 --image %s "
591                 "--partition_size %d --partition_name foobar "
592                 "--algorithm SHA256_RSA2048 "
593                 "--key test/data/testkey_rsa2048.pem "
594                 "--internal_release_string \"\"",
595                 partition_path.value().c_str(),
596                 (int)partition_size);
597
598  // Since we may be using an arbritary version of make_ext4fs
599  // (because of different branches) the contents of the resulting
600  // disk image may slightly change. It's enough to just remove the
601  // "Digest:" line from the output to work around this.
602  std::string info =
603      RemoveLinesStartingWith(InfoImage(partition_path), "      Digest:");
604  ASSERT_EQ(
605      "Footer version:           1.0\n"
606      "Image size:               10485760 bytes\n"
607      "Original image size:      10354688 bytes\n"
608      "VBMeta offset:            10354688\n"
609      "VBMeta size:              1280 bytes\n"
610      "--\n"
611      "Minimum libavb version:   1.0 (Sparse)\n"
612      "Header Block:             256 bytes\n"
613      "Authentication Block:     320 bytes\n"
614      "Auxiliary Block:          704 bytes\n"
615      "Algorithm:                SHA256_RSA2048\n"
616      "Rollback Index:           0\n"
617      "Flags:                    0\n"
618      "Release String:           ''\n"
619      "Descriptors:\n"
620      "    Hash descriptor:\n"
621      "      Image Size:            10354688 bytes\n"
622      "      Hash Algorithm:        sha256\n"
623      "      Partition Name:        foobar\n"
624      "      Salt:                  d00df00d\n",
625      info);
626
627  EXPECT_COMMAND(0,
628                 "mv %s %s.sparse",
629                 partition_path.value().c_str(),
630                 partition_path.value().c_str());
631  EXPECT_COMMAND(0,
632                 "simg2img %s.sparse %s",
633                 partition_path.value().c_str(),
634                 partition_path.value().c_str());
635  EXPECT_COMMAND(0, "rm -f %s.sparse", partition_path.value().c_str());
636}
637
638void AvbToolTest::AddHashtreeFooterTest(bool sparse_image) {
639  const size_t rootfs_size = 1028 * 1024;
640  const size_t partition_size = 1536 * 1024;
641
642  // Generate a 1028 KiB file with known content.
643  std::vector<uint8_t> rootfs;
644  rootfs.resize(rootfs_size);
645  for (size_t n = 0; n < rootfs_size; n++)
646    rootfs[n] = uint8_t(n);
647  base::FilePath ext_vbmeta_path = testdir_.Append("ext_vbmeta.bin");
648  base::FilePath rootfs_path = testdir_.Append("rootfs.bin");
649  EXPECT_EQ(rootfs_size,
650            static_cast<const size_t>(
651                base::WriteFile(rootfs_path,
652                                reinterpret_cast<const char*>(rootfs.data()),
653                                rootfs.size())));
654
655  if (sparse_image) {
656    EXPECT_COMMAND(0,
657                   "mv %s %s.unsparse",
658                   rootfs_path.value().c_str(),
659                   rootfs_path.value().c_str());
660    EXPECT_COMMAND(0,
661                   "img2simg %s.unsparse %s",
662                   rootfs_path.value().c_str(),
663                   rootfs_path.value().c_str());
664    EXPECT_COMMAND(0, "rm -f %s.unsparse", rootfs_path.value().c_str());
665  }
666
667  /* Do this twice to check that 'add_hashtree_footer' is idempotent. */
668  for (int n = 0; n < 2; n++) {
669    EXPECT_COMMAND(0,
670                   "./avbtool add_hashtree_footer --salt d00df00d --image %s "
671                   "--partition_size %d --partition_name foobar "
672                   "--algorithm SHA256_RSA2048 "
673                   "--key test/data/testkey_rsa2048.pem "
674                   "--output_vbmeta_image %s "
675                   "--internal_release_string \"\"",
676                   rootfs_path.value().c_str(),
677                   (int)partition_size,
678                   ext_vbmeta_path.value().c_str());
679
680    ASSERT_EQ(base::StringPrintf("Footer version:           1.0\n"
681                                 "Image size:               1572864 bytes\n"
682                                 "Original image size:      1052672 bytes\n"
683                                 "VBMeta offset:            1069056\n"
684                                 "VBMeta size:              1344 bytes\n"
685                                 "--\n"
686                                 "Minimum libavb version:   1.0%s\n"
687                                 "Header Block:             256 bytes\n"
688                                 "Authentication Block:     320 bytes\n"
689                                 "Auxiliary Block:          768 bytes\n"
690                                 "Algorithm:                SHA256_RSA2048\n"
691                                 "Rollback Index:           0\n"
692                                 "Flags:                    0\n"
693                                 "Release String:           ''\n"
694                                 "Descriptors:\n"
695                                 "    Hashtree descriptor:\n"
696                                 "      Version of dm-verity:  1\n"
697                                 "      Image Size:            1052672 bytes\n"
698                                 "      Tree Offset:           1052672\n"
699                                 "      Tree Size:             16384 bytes\n"
700                                 "      Data Block Size:       4096 bytes\n"
701                                 "      Hash Block Size:       4096 bytes\n"
702                                 "      FEC num roots:         0\n"
703                                 "      FEC offset:            0\n"
704                                 "      FEC size:              0 bytes\n"
705                                 "      Hash Algorithm:        sha1\n"
706                                 "      Partition Name:        foobar\n"
707                                 "      Salt:                  d00df00d\n"
708                                 "      Root Digest:           "
709                                 "e811611467dcd6e8dc4324e45f706c2bdd51db67\n",
710                                 sparse_image ? " (Sparse)" : ""),
711              InfoImage(rootfs_path));
712
713    ASSERT_EQ(
714        "Minimum libavb version:   1.0\n"
715        "Header Block:             256 bytes\n"
716        "Authentication Block:     320 bytes\n"
717        "Auxiliary Block:          768 bytes\n"
718        "Algorithm:                SHA256_RSA2048\n"
719        "Rollback Index:           0\n"
720        "Flags:                    0\n"
721        "Release String:           ''\n"
722        "Descriptors:\n"
723        "    Hashtree descriptor:\n"
724        "      Version of dm-verity:  1\n"
725        "      Image Size:            1052672 bytes\n"
726        "      Tree Offset:           1052672\n"
727        "      Tree Size:             16384 bytes\n"
728        "      Data Block Size:       4096 bytes\n"
729        "      Hash Block Size:       4096 bytes\n"
730        "      FEC num roots:         0\n"
731        "      FEC offset:            0\n"
732        "      FEC size:              0 bytes\n"
733        "      Hash Algorithm:        sha1\n"
734        "      Partition Name:        foobar\n"
735        "      Salt:                  d00df00d\n"
736        "      Root Digest:           "
737        "e811611467dcd6e8dc4324e45f706c2bdd51db67\n",
738        InfoImage(ext_vbmeta_path));
739  }
740
741  if (sparse_image) {
742    EXPECT_COMMAND(0,
743                   "mv %s %s.sparse",
744                   rootfs_path.value().c_str(),
745                   rootfs_path.value().c_str());
746    EXPECT_COMMAND(0,
747                   "simg2img %s.sparse %s",
748                   rootfs_path.value().c_str(),
749                   rootfs_path.value().c_str());
750    EXPECT_COMMAND(0, "rm -f %s.sparse", rootfs_path.value().c_str());
751  }
752
753  // To check that we generate the correct hashtree we can use
754  // veritysetup(1) - another codebase for working with dm-verity
755  // hashtrees - to verify it.
756  //
757  // If we don't want to impose the requirement of having the
758  // veritysetup(1) command available on builders we can comment this
759  // out.
760  EXPECT_COMMAND(0,
761                 "veritysetup --no-superblock --format=1 --hash=sha1 "
762                 "--data-block-size=4096 --hash-block-size=4096 "
763                 "--salt=d00df00d "
764                 "--data-blocks=257 "
765                 "--hash-offset=1052672 "
766                 "verify "
767                 "%s %s "
768                 "e811611467dcd6e8dc4324e45f706c2bdd51db67",
769                 rootfs_path.value().c_str(),
770                 rootfs_path.value().c_str());
771
772  // Now check that we can find the VBMeta block again from the footer.
773  std::string part_data;
774  ASSERT_TRUE(base::ReadFileToString(rootfs_path, &part_data));
775
776  // Check footer contains correct data.
777  AvbFooter f;
778  EXPECT_NE(0,
779            avb_footer_validate_and_byteswap(
780                reinterpret_cast<const AvbFooter*>(
781                    part_data.data() + part_data.size() - AVB_FOOTER_SIZE),
782                &f));
783  EXPECT_EQ(
784      std::string(reinterpret_cast<const char*>(f.magic), AVB_FOOTER_MAGIC_LEN),
785      AVB_FOOTER_MAGIC);
786  EXPECT_EQ(AVB_FOOTER_VERSION_MAJOR, (int)f.version_major);
787  EXPECT_EQ(AVB_FOOTER_VERSION_MINOR, (int)f.version_minor);
788  EXPECT_EQ(1052672UL, f.original_image_size);
789  EXPECT_EQ(1069056UL, f.vbmeta_offset);
790  EXPECT_EQ(1344UL, f.vbmeta_size);
791
792  // Check that the vbmeta image at |f.vbmeta_offset| checks out.
793  const uint8_t* vbmeta_data =
794      reinterpret_cast<const uint8_t*>(part_data.data() + f.vbmeta_offset);
795  EXPECT_EQ(AVB_VBMETA_VERIFY_RESULT_OK,
796            avb_vbmeta_image_verify(vbmeta_data, f.vbmeta_size, NULL, NULL));
797
798  // Collect all descriptors.
799  std::vector<const AvbDescriptor*> descriptors;
800  avb_descriptor_foreach(
801      vbmeta_data, f.vbmeta_size, collect_descriptors, &descriptors);
802
803  // We should only have a single descriptor and it should be a
804  // hashtree descriptor.
805  EXPECT_EQ(1UL, descriptors.size());
806  EXPECT_EQ(AVB_DESCRIPTOR_TAG_HASHTREE, avb_be64toh(descriptors[0]->tag));
807  AvbHashtreeDescriptor d;
808  EXPECT_NE(
809      0,
810      avb_hashtree_descriptor_validate_and_byteswap(
811          reinterpret_cast<const AvbHashtreeDescriptor*>(descriptors[0]), &d));
812  EXPECT_EQ(1UL, d.dm_verity_version);
813  EXPECT_EQ(1052672UL, d.image_size);
814  EXPECT_EQ(1052672UL, d.tree_offset);
815  EXPECT_EQ(16384UL, d.tree_size);
816  EXPECT_EQ(4096UL, d.data_block_size);
817  EXPECT_EQ(4096UL, d.hash_block_size);
818  EXPECT_EQ(6UL, d.partition_name_len);
819  EXPECT_EQ(4UL, d.salt_len);
820  EXPECT_EQ(20UL, d.root_digest_len);
821  const uint8_t* desc_end = reinterpret_cast<const uint8_t*>(descriptors[0]) +
822                            sizeof(AvbHashtreeDescriptor);
823  uint64_t o = 0;
824  EXPECT_EQ("foobar",
825            std::string(reinterpret_cast<const char*>(desc_end + o),
826                        d.partition_name_len));
827  o += d.partition_name_len;
828  EXPECT_EQ("d00df00d", mem_to_hexstring(desc_end + o, d.salt_len));
829  o += d.salt_len;
830  EXPECT_EQ("e811611467dcd6e8dc4324e45f706c2bdd51db67",
831            mem_to_hexstring(desc_end + o, d.root_digest_len));
832
833  // Check that we correctly generate dm-verity kernel cmdline
834  // snippets, if requested.
835  base::FilePath vbmeta_dmv_path = testdir_.Append("vbmeta_dm_verity_desc.bin");
836  EXPECT_COMMAND(0,
837                 "./avbtool make_vbmeta_image "
838                 "--output %s "
839                 "--setup_rootfs_from_kernel %s "
840                 "--algorithm SHA256_RSA2048 "
841                 "--key test/data/testkey_rsa2048.pem "
842                 "--internal_release_string \"\"",
843                 vbmeta_dmv_path.value().c_str(),
844                 rootfs_path.value().c_str());
845
846  ASSERT_EQ(
847      "Minimum libavb version:   1.0\n"
848      "Header Block:             256 bytes\n"
849      "Authentication Block:     320 bytes\n"
850      "Auxiliary Block:          896 bytes\n"
851      "Algorithm:                SHA256_RSA2048\n"
852      "Rollback Index:           0\n"
853      "Flags:                    0\n"
854      "Release String:           ''\n"
855      "Descriptors:\n"
856      "    Kernel Cmdline descriptor:\n"
857      "      Flags:                 1\n"
858      "      Kernel Cmdline:        'dm=\"1 vroot none ro 1,0 2056 verity 1 "
859      "PARTUUID=$(ANDROID_SYSTEM_PARTUUID) PARTUUID=$(ANDROID_SYSTEM_PARTUUID) "
860      "4096 4096 257 257 sha1 e811611467dcd6e8dc4324e45f706c2bdd51db67 "
861      "d00df00d 2 restart_on_corruption ignore_zero_blocks\" root=/dev/dm-0'\n"
862      "    Kernel Cmdline descriptor:\n"
863      "      Flags:                 2\n"
864      "      Kernel Cmdline:        "
865      "'root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)'\n",
866      InfoImage(vbmeta_dmv_path));
867
868  // Check that the footer is correctly erased and the hashtree
869  // remains - see above for why the constant 1069056 is used.
870  EXPECT_COMMAND(0,
871                 "./avbtool erase_footer --image %s --keep_hashtree",
872                 rootfs_path.value().c_str());
873  int64_t erased_footer_file_size;
874  ASSERT_TRUE(base::GetFileSize(rootfs_path, &erased_footer_file_size));
875  EXPECT_EQ(static_cast<size_t>(erased_footer_file_size), 1069056UL);
876
877  // Check that --do_not_append_vbmeta_image works as intended.
878  //
879  // For this we need to reset the size of the image to the original
880  // size because it's not possible to identify the existing hashtree.
881  EXPECT_COMMAND(
882      0, "truncate -s %d %s", (int)rootfs_size, rootfs_path.value().c_str());
883  EXPECT_COMMAND(0,
884                 "./avbtool add_hashtree_footer --salt d00df00d --image %s "
885                 "--partition_size %d --partition_name foobar "
886                 "--algorithm SHA256_RSA2048 "
887                 "--key test/data/testkey_rsa2048.pem "
888                 "--output_vbmeta %s_2nd_run --do_not_append_vbmeta_image "
889                 "--internal_release_string \"\"",
890                 rootfs_path.value().c_str(),
891                 (int)partition_size,
892                 ext_vbmeta_path.value().c_str());
893  int64_t file_size;
894  ASSERT_TRUE(base::GetFileSize(rootfs_path, &file_size));
895  EXPECT_EQ(static_cast<size_t>(file_size), 1069056UL);
896  EXPECT_COMMAND(0,
897                 "diff %s %s_2nd_run",
898                 ext_vbmeta_path.value().c_str(),
899                 ext_vbmeta_path.value().c_str());
900}
901
902TEST_F(AvbToolTest, AddHashtreeFooter) {
903  AddHashtreeFooterTest(false);
904}
905
906TEST_F(AvbToolTest, AddHashtreeFooterSparse) {
907  AddHashtreeFooterTest(true);
908}
909
910void AvbToolTest::AddHashtreeFooterFECTest(bool sparse_image) {
911  const size_t rootfs_size = 1028 * 1024;
912  const size_t partition_size = 1536 * 1024;
913
914  // Generate a 1028 KiB file with known content.
915  std::vector<uint8_t> rootfs;
916  rootfs.resize(rootfs_size);
917  for (size_t n = 0; n < rootfs_size; n++)
918    rootfs[n] = uint8_t(n);
919  base::FilePath rootfs_path = testdir_.Append("rootfs.bin");
920  EXPECT_EQ(rootfs_size,
921            static_cast<const size_t>(
922                base::WriteFile(rootfs_path,
923                                reinterpret_cast<const char*>(rootfs.data()),
924                                rootfs.size())));
925
926  if (sparse_image) {
927    EXPECT_COMMAND(0,
928                   "mv %s %s.unsparse",
929                   rootfs_path.value().c_str(),
930                   rootfs_path.value().c_str());
931    EXPECT_COMMAND(0,
932                   "img2simg %s.unsparse %s",
933                   rootfs_path.value().c_str(),
934                   rootfs_path.value().c_str());
935    EXPECT_COMMAND(0, "rm -f %s.unsparse", rootfs_path.value().c_str());
936  }
937
938  /* Do this twice to check that 'add_hashtree_footer' is idempotent. */
939  for (int n = 0; n < 2; n++) {
940    EXPECT_COMMAND(0,
941                   "./avbtool add_hashtree_footer --salt d00df00d --image %s "
942                   "--partition_size %d --partition_name foobar "
943                   "--generate_fec "
944                   "--algorithm SHA256_RSA2048 "
945                   "--key test/data/testkey_rsa2048.pem "
946                   "--internal_release_string \"\"",
947                   rootfs_path.value().c_str(),
948                   (int)partition_size);
949
950    ASSERT_EQ(base::StringPrintf("Footer version:           1.0\n"
951                                 "Image size:               1572864 bytes\n"
952                                 "Original image size:      1052672 bytes\n"
953                                 "VBMeta offset:            1085440\n"
954                                 "VBMeta size:              1344 bytes\n"
955                                 "--\n"
956                                 "Minimum libavb version:   1.0%s\n"
957                                 "Header Block:             256 bytes\n"
958                                 "Authentication Block:     320 bytes\n"
959                                 "Auxiliary Block:          768 bytes\n"
960                                 "Algorithm:                SHA256_RSA2048\n"
961                                 "Rollback Index:           0\n"
962                                 "Flags:                    0\n"
963                                 "Release String:           ''\n"
964                                 "Descriptors:\n"
965                                 "    Hashtree descriptor:\n"
966                                 "      Version of dm-verity:  1\n"
967                                 "      Image Size:            1052672 bytes\n"
968                                 "      Tree Offset:           1052672\n"
969                                 "      Tree Size:             16384 bytes\n"
970                                 "      Data Block Size:       4096 bytes\n"
971                                 "      Hash Block Size:       4096 bytes\n"
972                                 "      FEC num roots:         2\n"
973                                 "      FEC offset:            1069056\n"
974                                 "      FEC size:              16384 bytes\n"
975                                 "      Hash Algorithm:        sha1\n"
976                                 "      Partition Name:        foobar\n"
977                                 "      Salt:                  d00df00d\n"
978                                 "      Root Digest:           "
979                                 "e811611467dcd6e8dc4324e45f706c2bdd51db67\n",
980                                 sparse_image ? " (Sparse)" : ""),
981              InfoImage(rootfs_path));
982  }
983
984  if (sparse_image) {
985    EXPECT_COMMAND(0,
986                   "mv %s %s.sparse",
987                   rootfs_path.value().c_str(),
988                   rootfs_path.value().c_str());
989    EXPECT_COMMAND(0,
990                   "simg2img %s.sparse %s",
991                   rootfs_path.value().c_str(),
992                   rootfs_path.value().c_str());
993    EXPECT_COMMAND(0, "rm -f %s.sparse", rootfs_path.value().c_str());
994  }
995
996  /* TODO: would be nice to verify that the FEC data is correct. */
997
998  // Now check that we can find the VBMeta block again from the footer.
999  std::string part_data;
1000  ASSERT_TRUE(base::ReadFileToString(rootfs_path, &part_data));
1001
1002  // Check footer contains correct data.
1003  AvbFooter f;
1004  EXPECT_NE(0,
1005            avb_footer_validate_and_byteswap(
1006                reinterpret_cast<const AvbFooter*>(
1007                    part_data.data() + part_data.size() - AVB_FOOTER_SIZE),
1008                &f));
1009  EXPECT_EQ(
1010      std::string(reinterpret_cast<const char*>(f.magic), AVB_FOOTER_MAGIC_LEN),
1011      AVB_FOOTER_MAGIC);
1012  EXPECT_EQ(AVB_FOOTER_VERSION_MAJOR, (int)f.version_major);
1013  EXPECT_EQ(AVB_FOOTER_VERSION_MINOR, (int)f.version_minor);
1014  EXPECT_EQ(1052672UL, f.original_image_size);
1015  EXPECT_EQ(1085440UL, f.vbmeta_offset);
1016  EXPECT_EQ(1344UL, f.vbmeta_size);
1017
1018  // Check that the vbmeta image at |f.vbmeta_offset| checks out.
1019  const uint8_t* vbmeta_data =
1020      reinterpret_cast<const uint8_t*>(part_data.data() + f.vbmeta_offset);
1021  EXPECT_EQ(AVB_VBMETA_VERIFY_RESULT_OK,
1022            avb_vbmeta_image_verify(vbmeta_data, f.vbmeta_size, NULL, NULL));
1023
1024  // Collect all descriptors.
1025  std::vector<const AvbDescriptor*> descriptors;
1026  avb_descriptor_foreach(
1027      vbmeta_data, f.vbmeta_size, collect_descriptors, &descriptors);
1028
1029  // We should only have a single descriptor and it should be a
1030  // hashtree descriptor.
1031  EXPECT_EQ(1UL, descriptors.size());
1032  EXPECT_EQ(AVB_DESCRIPTOR_TAG_HASHTREE, avb_be64toh(descriptors[0]->tag));
1033  AvbHashtreeDescriptor d;
1034  EXPECT_NE(
1035      0,
1036      avb_hashtree_descriptor_validate_and_byteswap(
1037          reinterpret_cast<const AvbHashtreeDescriptor*>(descriptors[0]), &d));
1038  EXPECT_EQ(1UL, d.dm_verity_version);
1039  EXPECT_EQ(1052672UL, d.image_size);
1040  EXPECT_EQ(1052672UL, d.tree_offset);
1041  EXPECT_EQ(16384UL, d.tree_size);
1042  EXPECT_EQ(4096UL, d.data_block_size);
1043  EXPECT_EQ(2UL, d.fec_num_roots);
1044  EXPECT_EQ(1069056UL, d.fec_offset);
1045  EXPECT_EQ(16384UL, d.fec_size);
1046  EXPECT_EQ(6UL, d.partition_name_len);
1047  EXPECT_EQ(4UL, d.salt_len);
1048  EXPECT_EQ(20UL, d.root_digest_len);
1049  const uint8_t* desc_end = reinterpret_cast<const uint8_t*>(descriptors[0]) +
1050                            sizeof(AvbHashtreeDescriptor);
1051  uint64_t o = 0;
1052  EXPECT_EQ("foobar",
1053            std::string(reinterpret_cast<const char*>(desc_end + o),
1054                        d.partition_name_len));
1055  o += d.partition_name_len;
1056  EXPECT_EQ("d00df00d", mem_to_hexstring(desc_end + o, d.salt_len));
1057  o += d.salt_len;
1058  EXPECT_EQ("e811611467dcd6e8dc4324e45f706c2bdd51db67",
1059            mem_to_hexstring(desc_end + o, d.root_digest_len));
1060
1061  // Check that we correctly generate dm-verity kernel cmdline
1062  // snippets, if requested.
1063  base::FilePath vbmeta_dmv_path = testdir_.Append("vbmeta_dm_verity_desc.bin");
1064  EXPECT_COMMAND(0,
1065                 "./avbtool make_vbmeta_image "
1066                 "--output %s "
1067                 "--setup_rootfs_from_kernel %s "
1068                 "--algorithm SHA256_RSA2048 "
1069                 "--key test/data/testkey_rsa2048.pem "
1070                 "--internal_release_string \"\"",
1071                 vbmeta_dmv_path.value().c_str(),
1072                 rootfs_path.value().c_str());
1073
1074  ASSERT_EQ(
1075      "Minimum libavb version:   1.0\n"
1076      "Header Block:             256 bytes\n"
1077      "Authentication Block:     320 bytes\n"
1078      "Auxiliary Block:          960 bytes\n"
1079      "Algorithm:                SHA256_RSA2048\n"
1080      "Rollback Index:           0\n"
1081      "Flags:                    0\n"
1082      "Release String:           ''\n"
1083      "Descriptors:\n"
1084      "    Kernel Cmdline descriptor:\n"
1085      "      Flags:                 1\n"
1086      "      Kernel Cmdline:        'dm=\"1 vroot none ro 1,0 2056 verity 1 "
1087      "PARTUUID=$(ANDROID_SYSTEM_PARTUUID) PARTUUID=$(ANDROID_SYSTEM_PARTUUID) "
1088      "4096 4096 257 257 sha1 e811611467dcd6e8dc4324e45f706c2bdd51db67 "
1089      "d00df00d 10 restart_on_corruption ignore_zero_blocks "
1090      "use_fec_from_device "
1091      "PARTUUID=$(ANDROID_SYSTEM_PARTUUID) fec_roots 2 fec_blocks 261 "
1092      "fec_start 261\" root=/dev/dm-0'\n"
1093      "    Kernel Cmdline descriptor:\n"
1094      "      Flags:                 2\n"
1095      "      Kernel Cmdline:        "
1096      "'root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)'\n",
1097      InfoImage(vbmeta_dmv_path));
1098
1099  // Check that the footer is correctly erased and the hashtree and
1100  // FEC data remains. The constant 1085440 is used because it's where
1101  // the FEC data ends (it's at offset 1069056 and size 16384).
1102  EXPECT_COMMAND(0,
1103                 "./avbtool erase_footer --image %s --keep_hashtree",
1104                 rootfs_path.value().c_str());
1105  int64_t erased_footer_file_size;
1106  ASSERT_TRUE(base::GetFileSize(rootfs_path, &erased_footer_file_size));
1107  EXPECT_EQ(static_cast<size_t>(erased_footer_file_size), 1085440UL);
1108}
1109
1110TEST_F(AvbToolTest, AddHashtreeFooterFEC) {
1111  AddHashtreeFooterFECTest(false);
1112}
1113
1114TEST_F(AvbToolTest, AddHashtreeFooterFECSparse) {
1115  AddHashtreeFooterFECTest(true);
1116}
1117
1118TEST_F(AvbToolTest, AddHashtreeFooterCalcMaxImageSize) {
1119  const size_t partition_size = 10 * 1024 * 1024;
1120  base::FilePath output_path = testdir_.Append("max_size.txt");
1121
1122  EXPECT_COMMAND(0,
1123                 "./avbtool add_hashtree_footer "
1124                 "--partition_size %zd --calc_max_image_size > %s",
1125                 partition_size,
1126                 output_path.value().c_str());
1127  std::string max_image_size_data;
1128  EXPECT_TRUE(base::ReadFileToString(output_path, &max_image_size_data));
1129  EXPECT_EQ("10330112\n", max_image_size_data);
1130  size_t max_image_size = atoll(max_image_size_data.c_str());
1131
1132  // Hashtree and metadata takes up 152 KiB - compare to below with
1133  // FEC which is 244 KiB.
1134  EXPECT_EQ(152 * 1024ULL, partition_size - max_image_size);
1135
1136  // Check that we can add a hashtree with an image this size for such
1137  // a partition size.
1138  base::FilePath system_path = GenerateImage("system", max_image_size);
1139  EXPECT_COMMAND(0,
1140                 "./avbtool add_hashtree_footer"
1141                 " --image %s"
1142                 " --partition_name system"
1143                 " --partition_size %zd"
1144                 " --salt deadbeef"
1145                 " --algorithm SHA512_RSA4096 "
1146                 " --key test/data/testkey_rsa4096.pem"
1147                 " --internal_release_string \"\"",
1148                 system_path.value().c_str(),
1149                 partition_size);
1150}
1151
1152TEST_F(AvbToolTest, AddHashtreeFooterCalcMaxImageSizeWithFEC) {
1153  const size_t partition_size = 10 * 1024 * 1024;
1154  base::FilePath output_path = testdir_.Append("max_size.txt");
1155
1156  EXPECT_COMMAND(0,
1157                 "./avbtool add_hashtree_footer "
1158                 "--partition_size %zd --generate_fec "
1159                 "--calc_max_image_size > %s",
1160                 partition_size,
1161                 output_path.value().c_str());
1162  std::string max_image_size_data;
1163  EXPECT_TRUE(base::ReadFileToString(output_path, &max_image_size_data));
1164  EXPECT_EQ("10235904\n", max_image_size_data);
1165  size_t max_image_size = atoll(max_image_size_data.c_str());
1166
1167  // Hashtree, FEC codes, and metadata takes up 244 KiB - compare to
1168  // above wihtout FEC which is 152 KiB.
1169  EXPECT_EQ(244 * 1024ULL, partition_size - max_image_size);
1170
1171  // Check that we can add a hashtree with an image this size for such
1172  // a partition size.
1173  base::FilePath system_path = GenerateImage("system", max_image_size);
1174  EXPECT_COMMAND(0,
1175                 "./avbtool add_hashtree_footer"
1176                 " --image %s"
1177                 " --partition_name system"
1178                 " --partition_size %zd"
1179                 " --salt deadbeef"
1180                 " --generate_fec "
1181                 " --algorithm SHA512_RSA4096 "
1182                 " --key test/data/testkey_rsa4096.pem"
1183                 " --internal_release_string \"\"",
1184                 system_path.value().c_str(),
1185                 partition_size);
1186}
1187
1188TEST_F(AvbToolTest, KernelCmdlineDescriptor) {
1189  base::FilePath vbmeta_path =
1190      testdir_.Append("vbmeta_kernel_cmdline_desc.bin");
1191
1192  EXPECT_COMMAND(0,
1193                 "./avbtool make_vbmeta_image "
1194                 "--output %s "
1195                 "--kernel_cmdline 'foo bar baz' "
1196                 "--kernel_cmdline 'second cmdline' "
1197                 "--algorithm SHA256_RSA2048 "
1198                 "--key test/data/testkey_rsa2048.pem "
1199                 "--internal_release_string \"\"",
1200                 vbmeta_path.value().c_str());
1201
1202  ASSERT_EQ(
1203      "Minimum libavb version:   1.0\n"
1204      "Header Block:             256 bytes\n"
1205      "Authentication Block:     320 bytes\n"
1206      "Auxiliary Block:          640 bytes\n"
1207      "Algorithm:                SHA256_RSA2048\n"
1208      "Rollback Index:           0\n"
1209      "Flags:                    0\n"
1210      "Release String:           ''\n"
1211      "Descriptors:\n"
1212      "    Kernel Cmdline descriptor:\n"
1213      "      Flags:                 0\n"
1214      "      Kernel Cmdline:        'foo bar baz'\n"
1215      "    Kernel Cmdline descriptor:\n"
1216      "      Flags:                 0\n"
1217      "      Kernel Cmdline:        'second cmdline'\n",
1218      InfoImage(vbmeta_path));
1219
1220  // Now check the VBMeta image.
1221  std::string image_data;
1222  ASSERT_TRUE(base::ReadFileToString(vbmeta_path, &image_data));
1223
1224  const uint8_t* vbmeta_data =
1225      reinterpret_cast<const uint8_t*>(image_data.data());
1226  const size_t vbmeta_size = image_data.length();
1227  EXPECT_EQ(AVB_VBMETA_VERIFY_RESULT_OK,
1228            avb_vbmeta_image_verify(vbmeta_data, vbmeta_size, NULL, NULL));
1229
1230  // Collect all descriptors.
1231  std::vector<const AvbDescriptor*> descriptors;
1232  avb_descriptor_foreach(
1233      vbmeta_data, vbmeta_size, collect_descriptors, &descriptors);
1234
1235  // We should have two descriptors - check them.
1236  EXPECT_EQ(2UL, descriptors.size());
1237  AvbKernelCmdlineDescriptor d;
1238  EXPECT_EQ(AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE,
1239            avb_be64toh(descriptors[0]->tag));
1240  EXPECT_NE(
1241      0,
1242      avb_kernel_cmdline_descriptor_validate_and_byteswap(
1243          reinterpret_cast<const AvbKernelCmdlineDescriptor*>(descriptors[0]),
1244          &d));
1245  EXPECT_EQ("foo bar baz",
1246            std::string(reinterpret_cast<const char*>(descriptors[0]) +
1247                            sizeof(AvbKernelCmdlineDescriptor),
1248                        d.kernel_cmdline_length));
1249  EXPECT_EQ(AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE,
1250            avb_be64toh(descriptors[1]->tag));
1251  EXPECT_NE(
1252      0,
1253      avb_kernel_cmdline_descriptor_validate_and_byteswap(
1254          reinterpret_cast<const AvbKernelCmdlineDescriptor*>(descriptors[1]),
1255          &d));
1256  EXPECT_EQ("second cmdline",
1257            std::string(reinterpret_cast<const char*>(descriptors[1]) +
1258                            sizeof(AvbKernelCmdlineDescriptor),
1259                        d.kernel_cmdline_length));
1260}
1261
1262TEST_F(AvbToolTest, IncludeDescriptor) {
1263  base::FilePath vbmeta1_path = testdir_.Append("vbmeta_id1.bin");
1264  base::FilePath vbmeta2_path = testdir_.Append("vbmeta_id2.bin");
1265  base::FilePath vbmeta3_path = testdir_.Append("vbmeta_id3.bin");
1266
1267  EXPECT_COMMAND(0,
1268                 "./avbtool make_vbmeta_image "
1269                 "--output %s "
1270                 "--kernel_cmdline 'something' "
1271                 "--prop name:value "
1272                 "--internal_release_string \"\"",
1273                 vbmeta1_path.value().c_str());
1274
1275  EXPECT_COMMAND(0,
1276                 "./avbtool make_vbmeta_image "
1277                 "--output %s "
1278                 "--prop name2:value2 "
1279                 "--prop name3:value3 "
1280                 "--internal_release_string \"\"",
1281                 vbmeta2_path.value().c_str());
1282
1283  EXPECT_COMMAND(0,
1284                 "./avbtool make_vbmeta_image "
1285                 "--output %s "
1286                 "--prop name4:value4 "
1287                 "--include_descriptors_from_image %s "
1288                 "--include_descriptors_from_image %s "
1289                 "--internal_release_string \"\"",
1290                 vbmeta3_path.value().c_str(),
1291                 vbmeta1_path.value().c_str(),
1292                 vbmeta2_path.value().c_str());
1293
1294  ASSERT_EQ(
1295      "Minimum libavb version:   1.0\n"
1296      "Header Block:             256 bytes\n"
1297      "Authentication Block:     0 bytes\n"
1298      "Auxiliary Block:          256 bytes\n"
1299      "Algorithm:                NONE\n"
1300      "Rollback Index:           0\n"
1301      "Flags:                    0\n"
1302      "Release String:           ''\n"
1303      "Descriptors:\n"
1304      "    Prop: name4 -> 'value4'\n"
1305      "    Prop: name -> 'value'\n"
1306      "    Kernel Cmdline descriptor:\n"
1307      "      Flags:                 0\n"
1308      "      Kernel Cmdline:        'something'\n"
1309      "    Prop: name2 -> 'value2'\n"
1310      "    Prop: name3 -> 'value3'\n",
1311      InfoImage(vbmeta3_path));
1312}
1313
1314TEST_F(AvbToolTest, ChainedPartition) {
1315  base::FilePath vbmeta_path = testdir_.Append("vbmeta_cp.bin");
1316
1317  base::FilePath pk_path = testdir_.Append("testkey_rsa2048.avbpubkey");
1318
1319  EXPECT_COMMAND(
1320      0,
1321      "./avbtool extract_public_key --key test/data/testkey_rsa2048.pem"
1322      " --output %s",
1323      pk_path.value().c_str());
1324
1325  EXPECT_COMMAND(
1326      0,
1327      "./avbtool make_vbmeta_image "
1328      "--output %s "
1329      "--chain_partition system:1:%s "
1330      "--algorithm SHA256_RSA2048 --key test/data/testkey_rsa2048.pem "
1331      "--internal_release_string \"\"",
1332      vbmeta_path.value().c_str(),
1333      pk_path.value().c_str());
1334
1335  ASSERT_EQ(
1336      "Minimum libavb version:   1.0\n"
1337      "Header Block:             256 bytes\n"
1338      "Authentication Block:     320 bytes\n"
1339      "Auxiliary Block:          1152 bytes\n"
1340      "Algorithm:                SHA256_RSA2048\n"
1341      "Rollback Index:           0\n"
1342      "Flags:                    0\n"
1343      "Release String:           ''\n"
1344      "Descriptors:\n"
1345      "    Chain Partition descriptor:\n"
1346      "      Partition Name:          system\n"
1347      "      Rollback Index Location: 1\n"
1348      "      Public key (sha1):       "
1349      "cdbb77177f731920bbe0a0f94f84d9038ae0617d\n",
1350      InfoImage(vbmeta_path));
1351
1352  // Now check the VBMeta image.
1353  std::string image_data;
1354  ASSERT_TRUE(base::ReadFileToString(vbmeta_path, &image_data));
1355
1356  const uint8_t* vbmeta_data =
1357      reinterpret_cast<const uint8_t*>(image_data.data());
1358  const size_t vbmeta_size = image_data.length();
1359  EXPECT_EQ(AVB_VBMETA_VERIFY_RESULT_OK,
1360            avb_vbmeta_image_verify(vbmeta_data, vbmeta_size, NULL, NULL));
1361
1362  // Collect all descriptors.
1363  std::vector<const AvbDescriptor*> descriptors;
1364  avb_descriptor_foreach(
1365      vbmeta_data, vbmeta_size, collect_descriptors, &descriptors);
1366
1367  // We should have one descriptor - check it.
1368  EXPECT_EQ(1UL, descriptors.size());
1369
1370  std::string pk_data;
1371  ASSERT_TRUE(base::ReadFileToString(pk_path, &pk_data));
1372
1373  AvbChainPartitionDescriptor d;
1374  EXPECT_EQ(AVB_DESCRIPTOR_TAG_CHAIN_PARTITION,
1375            avb_be64toh(descriptors[0]->tag));
1376  EXPECT_NE(
1377      0,
1378      avb_chain_partition_descriptor_validate_and_byteswap(
1379          reinterpret_cast<const AvbChainPartitionDescriptor*>(descriptors[0]),
1380          &d));
1381  const uint8_t* desc_end = reinterpret_cast<const uint8_t*>(descriptors[0]) +
1382                            sizeof(AvbChainPartitionDescriptor);
1383  uint64_t o = 0;
1384  EXPECT_EQ("system",
1385            std::string(reinterpret_cast<const char*>(desc_end + o),
1386                        d.partition_name_len));
1387  o += d.partition_name_len;
1388  EXPECT_EQ(pk_data,
1389            std::string(reinterpret_cast<const char*>(descriptors[0]) +
1390                            sizeof(AvbChainPartitionDescriptor) + o,
1391                        d.public_key_len));
1392}
1393
1394TEST_F(AvbToolTest, AppendVBMetaImage) {
1395  size_t boot_size = 5 * 1024 * 1024;
1396  size_t boot_partition_size = 32 * 1024 * 1024;
1397  base::FilePath boot_path = GenerateImage("boot", boot_size);
1398
1399  GenerateVBMetaImage("vbmeta.img",
1400                      "SHA256_RSA2048",
1401                      0,
1402                      base::FilePath("test/data/testkey_rsa2048.pem"),
1403                      std::string("--append_to_release_string \"\" "
1404                                  "--kernel_cmdline foo"));
1405
1406  EXPECT_COMMAND(0,
1407                 "./avbtool append_vbmeta_image "
1408                 "--image %s "
1409                 "--partition_size %d "
1410                 "--vbmeta_image %s ",
1411                 boot_path.value().c_str(),
1412                 (int)boot_partition_size,
1413                 vbmeta_image_path_.value().c_str());
1414
1415  std::string vbmeta_contents = InfoImage(vbmeta_image_path_);
1416  std::string boot_contents = InfoImage(boot_path);
1417
1418  // Check that boot.img has the same vbmeta blob as from vbmeta.img -
1419  // we do this by inspecting 'avbtool info_image' output combined
1420  // with the known footer location given boot.img has 5 MiB known
1421  // content and the partition size is 32 MiB.
1422  ASSERT_EQ(
1423      "Minimum libavb version:   1.0\n"
1424      "Header Block:             256 bytes\n"
1425      "Authentication Block:     320 bytes\n"
1426      "Auxiliary Block:          576 bytes\n"
1427      "Algorithm:                SHA256_RSA2048\n"
1428      "Rollback Index:           0\n"
1429      "Flags:                    0\n"
1430      "Release String:           'avbtool 1.0.0 '\n"
1431      "Descriptors:\n"
1432      "    Kernel Cmdline descriptor:\n"
1433      "      Flags:                 0\n"
1434      "      Kernel Cmdline:        'foo'\n",
1435      vbmeta_contents);
1436  std::string known_footer =
1437      "Footer version:           1.0\n"
1438      "Image size:               33554432 bytes\n"
1439      "Original image size:      5242880 bytes\n"
1440      "VBMeta offset:            5242880\n"
1441      "VBMeta size:              1152 bytes\n"
1442      "--\n";
1443  ASSERT_EQ(known_footer + vbmeta_contents, boot_contents);
1444
1445  // Also verify that the blobs are the same, bit for bit.
1446  base::File f =
1447      base::File(boot_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
1448  std::vector<uint8_t> loaded_vbmeta;
1449  loaded_vbmeta.resize(1152);
1450  EXPECT_EQ(
1451      f.Read(
1452          5 * 1024 * 1024, reinterpret_cast<char*>(loaded_vbmeta.data()), 1152),
1453      1152);
1454  EXPECT_EQ(vbmeta_image_, loaded_vbmeta);
1455}
1456
1457TEST_F(AvbToolTest, SigningHelperBasic) {
1458  base::FilePath vbmeta_path = testdir_.Append("vbmeta.bin");
1459  base::FilePath signing_helper_test_path =
1460      testdir_.Append("signing_helper_test");
1461  EXPECT_COMMAND(
1462      0,
1463      "SIGNING_HELPER_TEST=\"%s\" ./avbtool make_vbmeta_image "
1464      "--output %s "
1465      "--algorithm SHA256_RSA2048 --key test/data/testkey_rsa2048.pem "
1466      "--signing_helper test/avbtool_signing_helper_test.py "
1467      "--internal_release_string \"\"",
1468      signing_helper_test_path.value().c_str(),
1469      vbmeta_path.value().c_str());
1470
1471  // Now check the value in test file.
1472  std::string value;
1473  ASSERT_TRUE(base::ReadFileToString(signing_helper_test_path, &value));
1474  EXPECT_EQ("DONE", value);
1475}
1476
1477TEST_F(AvbToolTest, SigningHelperReturnError) {
1478  base::FilePath vbmeta_path = testdir_.Append("vbmeta.bin");
1479  EXPECT_COMMAND(
1480      1,
1481      "./avbtool make_vbmeta_image "
1482      "--output %s "
1483      "--algorithm SHA256_RSA2048 --key test/data/testkey_rsa2048.pem "
1484      "--signing_helper test/avbtool_signing_helper_test.py "
1485      "--internal_release_string \"\"",
1486      vbmeta_path.value().c_str());
1487}
1488
1489TEST_F(AvbToolTest, MakeAtxPikCertificate) {
1490  base::FilePath subject_path = testdir_.Append("tmp_subject");
1491  ASSERT_TRUE(base::WriteFile(subject_path, "fake PIK subject", 16));
1492  base::FilePath pubkey_path = testdir_.Append("tmp_pubkey.pem");
1493  EXPECT_COMMAND(
1494      0,
1495      "openssl pkey -pubout -in test/data/testkey_atx_pik.pem -out %s",
1496      pubkey_path.value().c_str());
1497
1498  base::FilePath output_path = testdir_.Append("tmp_certificate.bin");
1499  EXPECT_COMMAND(0,
1500                 "./avbtool make_atx_certificate"
1501                 " --subject %s"
1502                 " --subject_key %s"
1503                 " --subject_key_version 42"
1504                 " --subject_is_intermediate_authority"
1505                 " --authority_key test/data/testkey_atx_prk.pem"
1506                 " --output %s",
1507                 subject_path.value().c_str(),
1508                 pubkey_path.value().c_str(),
1509                 output_path.value().c_str());
1510
1511  EXPECT_COMMAND(0,
1512                 "diff test/data/atx_pik_certificate.bin %s",
1513                 output_path.value().c_str());
1514}
1515
1516TEST_F(AvbToolTest, MakeAtxPskCertificate) {
1517  base::FilePath pubkey_path = testdir_.Append("tmp_pubkey.pem");
1518  EXPECT_COMMAND(
1519      0,
1520      "openssl pkey -pubout -in test/data/testkey_atx_psk.pem -out %s",
1521      pubkey_path.value().c_str());
1522
1523  base::FilePath output_path = testdir_.Append("tmp_certificate.bin");
1524  EXPECT_COMMAND(0,
1525                 "./avbtool make_atx_certificate"
1526                 " --subject test/data/atx_product_id.bin"
1527                 " --subject_key %s"
1528                 " --subject_key_version 42"
1529                 " --authority_key test/data/testkey_atx_pik.pem"
1530                 " --output %s",
1531                 pubkey_path.value().c_str(),
1532                 output_path.value().c_str());
1533
1534  EXPECT_COMMAND(0,
1535                 "diff test/data/atx_psk_certificate.bin %s",
1536                 output_path.value().c_str());
1537}
1538
1539TEST_F(AvbToolTest, MakeAtxPermanentAttributes) {
1540  base::FilePath pubkey_path = testdir_.Append("tmp_pubkey.pem");
1541  EXPECT_COMMAND(
1542      0,
1543      "openssl pkey -pubout -in test/data/testkey_atx_prk.pem -out %s",
1544      pubkey_path.value().c_str());
1545
1546  base::FilePath output_path = testdir_.Append("tmp_attributes.bin");
1547  EXPECT_COMMAND(0,
1548                 "./avbtool make_atx_permanent_attributes"
1549                 " --root_authority_key %s"
1550                 " --product_id test/data/atx_product_id.bin"
1551                 " --output %s",
1552                 pubkey_path.value().c_str(),
1553                 output_path.value().c_str());
1554
1555  EXPECT_COMMAND(0,
1556                 "diff test/data/atx_permanent_attributes.bin %s",
1557                 output_path.value().c_str());
1558}
1559
1560TEST_F(AvbToolTest, MakeAtxMetadata) {
1561  base::FilePath output_path = testdir_.Append("tmp_metadata.bin");
1562
1563  EXPECT_COMMAND(
1564      0,
1565      "./avbtool make_atx_metadata"
1566      " --intermediate_key_certificate test/data/atx_pik_certificate.bin"
1567      " --product_key_certificate test/data/atx_psk_certificate.bin"
1568      " --output %s",
1569      output_path.value().c_str());
1570
1571  EXPECT_COMMAND(
1572      0, "diff test/data/atx_metadata.bin %s", output_path.value().c_str());
1573}
1574
1575}  // namespace avb
1576