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