xref: /aosp_15_r20/system/core/fs_mgr/libfs_avb/avb_util.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
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 #include "avb_util.h"
18 
19 #include <unistd.h>
20 
21 #include <array>
22 #include <sstream>
23 
24 #include <android-base/logging.h>
25 #include <android-base/file.h>
26 #include <android-base/strings.h>
27 #include <android-base/unique_fd.h>
28 
29 #include "util.h"
30 
31 using android::base::Basename;
32 using android::base::ReadFileToString;
33 using android::base::StartsWith;
34 using android::base::unique_fd;
35 
36 namespace android {
37 namespace fs_mgr {
38 
39 // Constructs dm-verity arguments for sending DM_TABLE_LOAD ioctl to kernel.
40 // See the following link for more details:
41 // https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity
ConstructVerityTable(const FsAvbHashtreeDescriptor & hashtree_desc,const std::string & blk_device,android::dm::DmTable * table)42 bool ConstructVerityTable(const FsAvbHashtreeDescriptor& hashtree_desc,
43                           const std::string& blk_device, android::dm::DmTable* table) {
44     // Loads androidboot.veritymode from kernel cmdline.
45     std::string verity_mode;
46     if (!fs_mgr_get_boot_config("veritymode", &verity_mode)) {
47         verity_mode = "enforcing";  // Defaults to enforcing when it's absent.
48     }
49 
50     // Converts veritymode to the format used in kernel.
51     std::string dm_verity_mode;
52     if (verity_mode == "panicking") {
53         dm_verity_mode = "panic_on_corruption";
54     } else if (verity_mode == "enforcing") {
55         dm_verity_mode = "restart_on_corruption";
56     } else if (verity_mode == "logging") {
57         dm_verity_mode = "ignore_corruption";
58     } else if (verity_mode != "eio") {  // Default dm_verity_mode is eio.
59         LERROR << "Unknown androidboot.veritymode: " << verity_mode;
60         return false;
61     }
62 
63     std::ostringstream hash_algorithm;
64     hash_algorithm << hashtree_desc.hash_algorithm;
65 
66     android::dm::DmTargetVerity target(
67             0, hashtree_desc.image_size / 512, hashtree_desc.dm_verity_version, blk_device,
68             blk_device, hashtree_desc.data_block_size, hashtree_desc.hash_block_size,
69             hashtree_desc.image_size / hashtree_desc.data_block_size,
70             hashtree_desc.tree_offset / hashtree_desc.hash_block_size, hash_algorithm.str(),
71             hashtree_desc.root_digest, hashtree_desc.salt);
72     if (hashtree_desc.fec_size > 0) {
73         target.UseFec(blk_device, hashtree_desc.fec_num_roots,
74                       hashtree_desc.fec_offset / hashtree_desc.data_block_size,
75                       hashtree_desc.fec_offset / hashtree_desc.data_block_size);
76     }
77     if (!dm_verity_mode.empty()) {
78         target.SetVerityMode(dm_verity_mode);
79     }
80     // Always use ignore_zero_blocks.
81     target.IgnoreZeroBlocks();
82 
83     if (hashtree_desc.flags & AVB_HASHTREE_DESCRIPTOR_FLAGS_CHECK_AT_MOST_ONCE) {
84         target.CheckAtMostOnce();
85     }
86 
87     LINFO << "Built verity table: '" << target.GetParameterString() << "'";
88 
89     return table->AddTarget(std::make_unique<android::dm::DmTargetVerity>(target));
90 }
91 
HashtreeDmVeritySetup(FstabEntry * fstab_entry,const FsAvbHashtreeDescriptor & hashtree_desc,bool wait_for_verity_dev)92 bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const FsAvbHashtreeDescriptor& hashtree_desc,
93                            bool wait_for_verity_dev) {
94     android::dm::DmTable table;
95     if (!ConstructVerityTable(hashtree_desc, fstab_entry->blk_device, &table) || !table.valid()) {
96         LERROR << "Failed to construct verity table.";
97         return false;
98     }
99     table.set_readonly(true);
100 
101     std::chrono::milliseconds timeout = {};
102     if (wait_for_verity_dev) timeout = 1s;
103 
104     std::string dev_path;
105     const std::string device_name(GetVerityDeviceName(*fstab_entry));
106     android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
107     if (!dm.CreateDevice(device_name, table, &dev_path, timeout)) {
108         LERROR << "Couldn't create verity device!";
109         return false;
110     }
111 
112     // Marks the underlying block device as read-only.
113     SetBlockDeviceReadOnly(fstab_entry->blk_device);
114 
115     // Updates fstab_rec->blk_device to verity device name.
116     fstab_entry->blk_device = dev_path;
117     return true;
118 }
119 
GetHashtreeDescriptor(const std::string & partition_name,const std::vector<VBMetaData> & vbmeta_images)120 std::unique_ptr<FsAvbHashtreeDescriptor> GetHashtreeDescriptor(
121         const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images) {
122     bool found = false;
123     const uint8_t* desc_partition_name;
124     auto hashtree_desc = std::make_unique<FsAvbHashtreeDescriptor>();
125 
126     for (const auto& vbmeta : vbmeta_images) {
127         size_t num_descriptors;
128         std::unique_ptr<const AvbDescriptor* [], decltype(&avb_free)> descriptors(
129                 avb_descriptor_get_all(vbmeta.data(), vbmeta.size(), &num_descriptors), avb_free);
130 
131         if (!descriptors || num_descriptors < 1) {
132             continue;
133         }
134 
135         for (size_t n = 0; n < num_descriptors && !found; n++) {
136             AvbDescriptor desc;
137             if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
138                 LWARNING << "Descriptor[" << n << "] is invalid";
139                 continue;
140             }
141             if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) {
142                 desc_partition_name =
143                         (const uint8_t*)descriptors[n] + sizeof(AvbHashtreeDescriptor);
144                 if (!avb_hashtree_descriptor_validate_and_byteswap(
145                         (AvbHashtreeDescriptor*)descriptors[n], hashtree_desc.get())) {
146                     continue;
147                 }
148                 if (hashtree_desc->partition_name_len != partition_name.length()) {
149                     continue;
150                 }
151                 // Notes that desc_partition_name is not NUL-terminated.
152                 std::string hashtree_partition_name((const char*)desc_partition_name,
153                                                     hashtree_desc->partition_name_len);
154                 if (hashtree_partition_name == partition_name) {
155                     found = true;
156                 }
157             }
158         }
159 
160         if (found) break;
161     }
162 
163     if (!found) {
164         LERROR << "Hashtree descriptor not found: " << partition_name;
165         return nullptr;
166     }
167 
168     hashtree_desc->partition_name = partition_name;
169 
170     const uint8_t* desc_salt = desc_partition_name + hashtree_desc->partition_name_len;
171     hashtree_desc->salt = BytesToHex(desc_salt, hashtree_desc->salt_len);
172 
173     const uint8_t* desc_digest = desc_salt + hashtree_desc->salt_len;
174     hashtree_desc->root_digest = BytesToHex(desc_digest, hashtree_desc->root_digest_len);
175 
176     return hashtree_desc;
177 }
178 
LoadAvbHashtreeToEnableVerity(FstabEntry * fstab_entry,bool wait_for_verity_dev,const std::vector<VBMetaData> & vbmeta_images,const std::string & ab_suffix,const std::string & ab_other_suffix)179 bool LoadAvbHashtreeToEnableVerity(FstabEntry* fstab_entry, bool wait_for_verity_dev,
180                                    const std::vector<VBMetaData>& vbmeta_images,
181                                    const std::string& ab_suffix,
182                                    const std::string& ab_other_suffix) {
183     // Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
184     // to setup dm-verity. The partition_names in AVB descriptors are without A/B suffix.
185     std::string partition_name = DeriveAvbPartitionName(*fstab_entry, ab_suffix, ab_other_suffix);
186 
187     if (partition_name.empty()) {
188         LERROR << "partition name is empty, cannot lookup AVB descriptors";
189         return false;
190     }
191 
192     std::unique_ptr<FsAvbHashtreeDescriptor> hashtree_descriptor =
193             GetHashtreeDescriptor(partition_name, vbmeta_images);
194     if (!hashtree_descriptor) {
195         return false;
196     }
197 
198     // Converts HASHTREE descriptor to verity table to load into kernel.
199     // When success, the new device path will be returned, e.g., /dev/block/dm-2.
200     return HashtreeDmVeritySetup(fstab_entry, *hashtree_descriptor, wait_for_verity_dev);
201 }
202 
203 // Converts a AVB partition_name (without A/B suffix) to a device partition name.
204 // e.g.,       "system" => "system_a",
205 //       "system_other" => "system_b".
206 //
207 // If the device is non-A/B, converts it to a partition name without suffix.
208 // e.g.,       "system" => "system",
209 //       "system_other" => "system".
AvbPartitionToDevicePatition(const std::string & avb_partition_name,const std::string & ab_suffix,const std::string & ab_other_suffix)210 std::string AvbPartitionToDevicePatition(const std::string& avb_partition_name,
211                                          const std::string& ab_suffix,
212                                          const std::string& ab_other_suffix) {
213     bool is_other_slot = false;
214     std::string sanitized_partition_name(avb_partition_name);
215 
216     auto other_suffix = sanitized_partition_name.rfind("_other");
217     if (other_suffix != std::string::npos) {
218         sanitized_partition_name.erase(other_suffix);  // converts system_other => system
219         is_other_slot = true;
220     }
221 
222     auto append_suffix = is_other_slot ? ab_other_suffix : ab_suffix;
223     return sanitized_partition_name + append_suffix;
224 }
225 
226 // Converts fstab_entry.blk_device (with ab_suffix) to a AVB partition name.
227 // e.g., "/dev/block/by-name/system_a", slot_select       => "system",
228 //       "/dev/block/by-name/system_b", slot_select_other => "system_other".
229 //
230 // Or for a logical partition (with ab_suffix):
231 // e.g., "system_a", slot_select       => "system",
232 //       "system_b", slot_select_other => "system_other".
DeriveAvbPartitionName(const FstabEntry & fstab_entry,const std::string & ab_suffix,const std::string & ab_other_suffix)233 std::string DeriveAvbPartitionName(const FstabEntry& fstab_entry, const std::string& ab_suffix,
234                                    const std::string& ab_other_suffix) {
235     std::string partition_name;
236     if (fstab_entry.fs_mgr_flags.logical) {
237         partition_name = fstab_entry.logical_partition_name;
238     } else {
239         partition_name = Basename(fstab_entry.blk_device);
240     }
241 
242     if (fstab_entry.fs_mgr_flags.slot_select) {
243         auto found = partition_name.rfind(ab_suffix);
244         if (found != std::string::npos) {
245             partition_name.erase(found);  // converts system_a => system
246         }
247     } else if (fstab_entry.fs_mgr_flags.slot_select_other) {
248         auto found = partition_name.rfind(ab_other_suffix);
249         if (found != std::string::npos) {
250             partition_name.erase(found);  // converts system_b => system
251         }
252         partition_name += "_other";  // converts system => system_other
253     }
254 
255     return partition_name;
256 }
257 
GetTotalSize(int fd)258 off64_t GetTotalSize(int fd) {
259     off64_t saved_current = lseek64(fd, 0, SEEK_CUR);
260     if (saved_current == -1) {
261         PERROR << "Failed to get current position";
262         return -1;
263     }
264 
265     // lseek64() returns the resulting offset location from the beginning of the file.
266     off64_t total_size = lseek64(fd, 0, SEEK_END);
267     if (total_size == -1) {
268         PERROR << "Failed to lseek64 to end of the partition";
269         return -1;
270     }
271 
272     // Restores the original offset.
273     if (lseek64(fd, saved_current, SEEK_SET) == -1) {
274         PERROR << "Failed to lseek64 to the original offset: " << saved_current;
275     }
276 
277     return total_size;
278 }
279 
GetAvbFooter(int fd)280 std::unique_ptr<AvbFooter> GetAvbFooter(int fd) {
281     std::array<uint8_t, AVB_FOOTER_SIZE> footer_buf;
282     auto footer = std::make_unique<AvbFooter>();
283 
284     off64_t footer_offset = GetTotalSize(fd) - AVB_FOOTER_SIZE;
285 
286     ssize_t num_read =
287             TEMP_FAILURE_RETRY(pread64(fd, footer_buf.data(), AVB_FOOTER_SIZE, footer_offset));
288     if (num_read < 0 || num_read != AVB_FOOTER_SIZE) {
289         PERROR << "Failed to read AVB footer at offset: " << footer_offset;
290         return nullptr;
291     }
292 
293     if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf.data(), footer.get())) {
294         PERROR << "AVB footer verification failed at offset " << footer_offset;
295         return nullptr;
296     }
297 
298     return footer;
299 }
300 
ValidatePublicKeyBlob(const uint8_t * key,size_t length,const std::string & expected_key_blob)301 bool ValidatePublicKeyBlob(const uint8_t* key, size_t length,
302                            const std::string& expected_key_blob) {
303     if (expected_key_blob.empty()) {  // no expectation of the key, return true.
304         return true;
305     }
306     if (expected_key_blob.size() != length) {
307         return false;
308     }
309     if (0 == memcmp(key, expected_key_blob.data(), length)) {
310         return true;
311     }
312     return false;
313 }
314 
ValidatePublicKeyBlob(const std::string & key_blob_to_validate,const std::vector<std::string> & allowed_key_paths)315 bool ValidatePublicKeyBlob(const std::string& key_blob_to_validate,
316                            const std::vector<std::string>& allowed_key_paths) {
317     std::string allowed_key_blob;
318     if (key_blob_to_validate.empty()) {
319         LWARNING << "Failed to validate an empty key";
320         return false;
321     }
322     for (const auto& path : allowed_key_paths) {
323         if (ReadFileToString(path, &allowed_key_blob)) {
324             if (key_blob_to_validate == allowed_key_blob) return true;
325         }
326     }
327     return false;
328 }
329 
VerifyVBMetaSignature(const VBMetaData & vbmeta,const std::string & expected_public_key_blob,std::string * out_public_key_data)330 VBMetaVerifyResult VerifyVBMetaSignature(const VBMetaData& vbmeta,
331                                          const std::string& expected_public_key_blob,
332                                          std::string* out_public_key_data) {
333     const uint8_t* pk_data;
334     size_t pk_len;
335     ::AvbVBMetaVerifyResult vbmeta_ret;
336 
337     vbmeta_ret = avb_vbmeta_image_verify(vbmeta.data(), vbmeta.size(), &pk_data, &pk_len);
338 
339     if (out_public_key_data != nullptr) {
340         out_public_key_data->clear();
341         if (pk_len > 0) {
342             out_public_key_data->append(reinterpret_cast<const char*>(pk_data), pk_len);
343         }
344     }
345 
346     switch (vbmeta_ret) {
347         case AVB_VBMETA_VERIFY_RESULT_OK:
348             if (pk_data == nullptr || pk_len <= 0) {
349                 LERROR << vbmeta.partition()
350                        << ": Error verifying vbmeta image: failed to get public key";
351                 return VBMetaVerifyResult::kError;
352             }
353             if (!ValidatePublicKeyBlob(pk_data, pk_len, expected_public_key_blob)) {
354                 LERROR << vbmeta.partition() << ": Error verifying vbmeta image: public key used to"
355                        << " sign data does not match key in chain descriptor";
356                 return VBMetaVerifyResult::kErrorVerification;
357             }
358             return VBMetaVerifyResult::kSuccess;
359         case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
360         case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
361         case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
362             LERROR << vbmeta.partition() << ": Error verifying vbmeta image: "
363                    << avb_vbmeta_verify_result_to_string(vbmeta_ret);
364             return VBMetaVerifyResult::kErrorVerification;
365         case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
366             // No way to continue this case.
367             LERROR << vbmeta.partition() << ": Error verifying vbmeta image: invalid vbmeta header";
368             break;
369         case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
370             // No way to continue this case.
371             LERROR << vbmeta.partition()
372                    << ": Error verifying vbmeta image: unsupported AVB version";
373             break;
374         default:
375             LERROR << "Unknown vbmeta image verify return value: " << vbmeta_ret;
376             break;
377     }
378 
379     return VBMetaVerifyResult::kError;
380 }
381 
VerifyVBMetaData(int fd,const std::string & partition_name,const std::string & expected_public_key_blob,std::string * out_public_key_data,VBMetaVerifyResult * out_verify_result)382 std::unique_ptr<VBMetaData> VerifyVBMetaData(int fd, const std::string& partition_name,
383                                              const std::string& expected_public_key_blob,
384                                              std::string* out_public_key_data,
385                                              VBMetaVerifyResult* out_verify_result) {
386     uint64_t vbmeta_offset = 0;
387     uint64_t vbmeta_size = VBMetaData::kMaxVBMetaSize;
388     bool is_vbmeta_partition = StartsWith(partition_name, "vbmeta");
389 
390     if (out_verify_result) {
391         *out_verify_result = VBMetaVerifyResult::kError;
392     }
393 
394     if (!is_vbmeta_partition) {
395         std::unique_ptr<AvbFooter> footer = GetAvbFooter(fd);
396         if (!footer) {
397             return nullptr;
398         }
399         vbmeta_offset = footer->vbmeta_offset;
400         vbmeta_size = footer->vbmeta_size;
401     }
402 
403     if (vbmeta_size > VBMetaData::kMaxVBMetaSize) {
404         LERROR << "VbMeta size in footer exceeds kMaxVBMetaSize";
405         return nullptr;
406     }
407 
408     auto vbmeta = std::make_unique<VBMetaData>(vbmeta_size, partition_name);
409     ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, vbmeta->data(), vbmeta_size, vbmeta_offset));
410     // Allows partial read for vbmeta partition, because its vbmeta_size is kMaxVBMetaSize.
411     if (num_read < 0 || (!is_vbmeta_partition && static_cast<uint64_t>(num_read) != vbmeta_size)) {
412         PERROR << partition_name << ": Failed to read vbmeta at offset " << vbmeta_offset
413                << " with size " << vbmeta_size;
414         return nullptr;
415     }
416 
417     auto verify_result =
418             VerifyVBMetaSignature(*vbmeta, expected_public_key_blob, out_public_key_data);
419 
420     if (out_verify_result != nullptr) {
421         *out_verify_result = verify_result;
422     }
423 
424     if (verify_result == VBMetaVerifyResult::kSuccess ||
425         verify_result == VBMetaVerifyResult::kErrorVerification) {
426         return vbmeta;
427     }
428 
429     return nullptr;
430 }
431 
RollbackDetected(const std::string & partition_name ATTRIBUTE_UNUSED,uint64_t rollback_index ATTRIBUTE_UNUSED)432 bool RollbackDetected(const std::string& partition_name ATTRIBUTE_UNUSED,
433                       uint64_t rollback_index ATTRIBUTE_UNUSED) {
434     // TODO(bowgotsai): Support rollback protection.
435     return false;
436 }
437 
GetChainPartitionInfo(const VBMetaData & vbmeta,bool * fatal_error)438 std::vector<ChainInfo> GetChainPartitionInfo(const VBMetaData& vbmeta, bool* fatal_error) {
439     CHECK(fatal_error != nullptr);
440     std::vector<ChainInfo> chain_partitions;
441 
442     size_t num_descriptors;
443     std::unique_ptr<const AvbDescriptor* [], decltype(&avb_free)> descriptors(
444             avb_descriptor_get_all(vbmeta.data(), vbmeta.size(), &num_descriptors), avb_free);
445 
446     if (!descriptors || num_descriptors < 1) {
447         return {};
448     }
449 
450     for (size_t i = 0; i < num_descriptors; i++) {
451         AvbDescriptor desc;
452         if (!avb_descriptor_validate_and_byteswap(descriptors[i], &desc)) {
453             LERROR << "Descriptor[" << i << "] is invalid in vbmeta: " << vbmeta.partition();
454             *fatal_error = true;
455             return {};
456         }
457         if (desc.tag == AVB_DESCRIPTOR_TAG_CHAIN_PARTITION) {
458             AvbChainPartitionDescriptor chain_desc;
459             if (!avb_chain_partition_descriptor_validate_and_byteswap(
460                         (AvbChainPartitionDescriptor*)descriptors[i], &chain_desc)) {
461                 LERROR << "Chain descriptor[" << i
462                        << "] is invalid in vbmeta: " << vbmeta.partition();
463                 *fatal_error = true;
464                 return {};
465             }
466             const char* chain_partition_name =
467                     ((const char*)descriptors[i]) + sizeof(AvbChainPartitionDescriptor);
468             const char* chain_public_key_blob =
469                     chain_partition_name + chain_desc.partition_name_len;
470             chain_partitions.emplace_back(
471                     std::string(chain_partition_name, chain_desc.partition_name_len),
472                     std::string(chain_public_key_blob, chain_desc.public_key_len));
473         }
474     }
475 
476     return chain_partitions;
477 }
478 
479 // Loads the vbmeta from a given path.
LoadAndVerifyVbmetaByPath(const std::string & image_path,const std::string & partition_name,const std::string & expected_public_key_blob,bool allow_verification_error,bool rollback_protection,bool is_chained_vbmeta,std::string * out_public_key_data,bool * out_verification_disabled,VBMetaVerifyResult * out_verify_result)480 std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath(
481         const std::string& image_path, const std::string& partition_name,
482         const std::string& expected_public_key_blob, bool allow_verification_error,
483         bool rollback_protection, bool is_chained_vbmeta, std::string* out_public_key_data,
484         bool* out_verification_disabled, VBMetaVerifyResult* out_verify_result) {
485     if (out_verify_result) {
486         *out_verify_result = VBMetaVerifyResult::kError;
487     }
488 
489     // Ensures the device path (might be a symlink created by init) is ready to access.
490     if (!WaitForFile(image_path, 1s)) {
491         PERROR << "No such path: " << image_path;
492         return nullptr;
493     }
494 
495     unique_fd fd(TEMP_FAILURE_RETRY(open(image_path.c_str(), O_RDONLY | O_CLOEXEC)));
496     if (fd < 0) {
497         PERROR << "Failed to open: " << image_path;
498         return nullptr;
499     }
500 
501     VBMetaVerifyResult verify_result;
502     std::unique_ptr<VBMetaData> vbmeta = VerifyVBMetaData(
503             fd, partition_name, expected_public_key_blob, out_public_key_data, &verify_result);
504     if (!vbmeta) {
505         LERROR << partition_name << ": Failed to load vbmeta, result: " << verify_result;
506         return nullptr;
507     }
508     vbmeta->set_vbmeta_path(image_path);
509 
510     if (!allow_verification_error && verify_result == VBMetaVerifyResult::kErrorVerification) {
511         LERROR << partition_name << ": allow verification error is not allowed";
512         return nullptr;
513     }
514 
515     std::unique_ptr<AvbVBMetaImageHeader> vbmeta_header =
516             vbmeta->GetVBMetaHeader(true /* update_vbmeta_size */);
517     if (!vbmeta_header) {
518         LERROR << partition_name << ": Failed to get vbmeta header";
519         return nullptr;
520     }
521 
522     if (rollback_protection && RollbackDetected(partition_name, vbmeta_header->rollback_index)) {
523         return nullptr;
524     }
525 
526     // vbmeta flags can only be set by the top-level vbmeta image.
527     if (is_chained_vbmeta && vbmeta_header->flags != 0) {
528         LERROR << partition_name << ": chained vbmeta image has non-zero flags";
529         return nullptr;
530     }
531 
532     // Checks if verification has been disabled by setting a bit in the image.
533     if (out_verification_disabled) {
534         if (vbmeta_header->flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
535             LWARNING << "VERIFICATION_DISABLED bit is set for partition: " << partition_name;
536             *out_verification_disabled = true;
537         } else {
538             *out_verification_disabled = false;
539         }
540     }
541 
542     if (out_verify_result) {
543         *out_verify_result = verify_result;
544     }
545 
546     return vbmeta;
547 }
548 
LoadAndVerifyVbmetaByPartition(const std::string & partition_name,const std::string & ab_suffix,const std::string & ab_other_suffix,const std::string & expected_public_key_blob,bool allow_verification_error,bool load_chained_vbmeta,bool rollback_protection,std::function<std::string (const std::string &)> device_path_constructor,bool is_chained_vbmeta,std::vector<VBMetaData> * out_vbmeta_images)549 VBMetaVerifyResult LoadAndVerifyVbmetaByPartition(
550     const std::string& partition_name, const std::string& ab_suffix,
551     const std::string& ab_other_suffix, const std::string& expected_public_key_blob,
552     bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection,
553     std::function<std::string(const std::string&)> device_path_constructor, bool is_chained_vbmeta,
554     std::vector<VBMetaData>* out_vbmeta_images) {
555     auto image_path = device_path_constructor(
556         AvbPartitionToDevicePatition(partition_name, ab_suffix, ab_other_suffix));
557 
558     bool verification_disabled = false;
559     VBMetaVerifyResult verify_result;
560     auto vbmeta = LoadAndVerifyVbmetaByPath(image_path, partition_name, expected_public_key_blob,
561                                             allow_verification_error, rollback_protection,
562                                             is_chained_vbmeta, nullptr /* out_public_key_data */,
563                                             &verification_disabled, &verify_result);
564 
565     if (!vbmeta) {
566         return VBMetaVerifyResult::kError;
567     }
568     if (out_vbmeta_images) {
569         out_vbmeta_images->emplace_back(std::move(*vbmeta));
570     }
571 
572     // Only loads chained vbmeta if AVB verification is NOT disabled.
573     if (!verification_disabled && load_chained_vbmeta) {
574         bool fatal_error = false;
575         auto chain_partitions = GetChainPartitionInfo(*out_vbmeta_images->rbegin(), &fatal_error);
576         if (fatal_error) {
577             return VBMetaVerifyResult::kError;
578         }
579         for (auto& chain : chain_partitions) {
580             auto sub_ret = LoadAndVerifyVbmetaByPartition(
581                 chain.partition_name, ab_suffix, ab_other_suffix, chain.public_key_blob,
582                 allow_verification_error, load_chained_vbmeta, rollback_protection,
583                 device_path_constructor, true, /* is_chained_vbmeta */
584                 out_vbmeta_images);
585             if (sub_ret != VBMetaVerifyResult::kSuccess) {
586                 verify_result = sub_ret;  // might be 'ERROR' or 'ERROR VERIFICATION'.
587                 if (verify_result == VBMetaVerifyResult::kError) {
588                     return verify_result;  // stop here if we got an 'ERROR'.
589                 }
590             }
591         }
592     }
593 
594     return verify_result;
595 }
596 
597 }  // namespace fs_mgr
598 }  // namespace android
599