diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index 1616a611c..bf5831502 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp @@ -102,28 +102,3 @@ cc_library_static { export_include_dirs: ["include_fstab"], header_libs: ["libbase_headers"], } - -cc_library_static { - name: "libfs_avb", - defaults: ["fs_mgr_defaults"], - recovery_available: true, - export_include_dirs: ["libfs_avb/include"], - srcs: [ - "libfs_avb/avb_ops.cpp", - "libfs_avb/fs_avb.cpp", - ], - static_libs: [ - "libavb", - "libfstab", - "libdm", - ], - export_static_lib_headers: [ - "libfstab", - ], - shared_libs: [ - "libcrypto", - ], - header_libs: [ - "libbase_headers", - ], -} diff --git a/fs_mgr/libfs_avb/Android.bp b/fs_mgr/libfs_avb/Android.bp new file mode 100644 index 000000000..d22eceb58 --- /dev/null +++ b/fs_mgr/libfs_avb/Android.bp @@ -0,0 +1,100 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_library_static { + name: "libfs_avb", + defaults: ["fs_mgr_defaults"], + recovery_available: true, + host_supported: true, + export_include_dirs: ["include"], + srcs: [ + "avb_ops.cpp", + "avb_util.cpp", + "fs_avb.cpp", + "util.cpp", + ], + static_libs: [ + "libavb", + "libdm", + "libfstab", + ], + export_static_lib_headers: [ + "libfstab", + ], + shared_libs: [ + "libcrypto", + ], + header_libs: [ + "libbase_headers", + ], +} + +cc_defaults { + name: "libfs_avb_host_test_defaults", + required: [ + "avbtool", + ], + data: [ + "tests/data/*", + ], + static_libs: [ + "libgtest_host", + ], + shared_libs: [ + "libbase", + "libchrome", + ], + target: { + darwin: { + enabled: false, + }, + }, + cflags: [ + "-DHOST_TEST", + ], +} + +cc_library_host_static { + name: "libfs_avb_test_util", + defaults: ["libfs_avb_host_test_defaults"], + srcs: [ + "tests/fs_avb_test_util.cpp", + ], +} + +cc_test_host { + name: "libfs_avb_test", + defaults: ["libfs_avb_host_test_defaults"], + static_libs: [ + "libfs_avb_test_util", + ], + srcs: [ + "tests/basic_test.cpp", + ], +} + +cc_test_host { + name: "libfs_avb_internal_test", + defaults: ["libfs_avb_host_test_defaults"], + static_libs: [ + "libfs_avb_test_util", + "libfstab", + ], + srcs: [ + "util.cpp", + "tests/util_test.cpp", + ], +} diff --git a/fs_mgr/libfs_avb/avb_ops.cpp b/fs_mgr/libfs_avb/avb_ops.cpp index c985a9784..3b0ef0ba0 100644 --- a/fs_mgr/libfs_avb/avb_ops.cpp +++ b/fs_mgr/libfs_avb/avb_ops.cpp @@ -37,7 +37,7 @@ #include #include -#include "fs_mgr_priv.h" +#include "util.h" using namespace std::literals; @@ -127,7 +127,7 @@ AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t of const std::string path = "/dev/block/by-name/"s + partition; // Ensures the device path (a symlink created by init) is ready to access. - if (!fs_mgr_wait_for_file(path, 1s)) { + if (!WaitForFile(path, 1s)) { return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; } diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp new file mode 100644 index 000000000..1cab0e609 --- /dev/null +++ b/fs_mgr/libfs_avb/avb_util.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "avb_util.h" + +#include +#include + +#include +#include + +#include "util.h" + +using android::base::unique_fd; + +namespace android { +namespace fs_mgr { + +// Constructs dm-verity arguments for sending DM_TABLE_LOAD ioctl to kernel. +// See the following link for more details: +// https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity +bool ConstructVerityTable(const AvbHashtreeDescriptor& hashtree_desc, const std::string& salt, + const std::string& root_digest, const std::string& blk_device, + android::dm::DmTable* table) { + // Loads androidboot.veritymode from kernel cmdline. + std::string verity_mode; + if (!fs_mgr_get_boot_config("veritymode", &verity_mode)) { + verity_mode = "enforcing"; // Defaults to enforcing when it's absent. + } + + // Converts veritymode to the format used in kernel. + std::string dm_verity_mode; + if (verity_mode == "enforcing") { + dm_verity_mode = "restart_on_corruption"; + } else if (verity_mode == "logging") { + dm_verity_mode = "ignore_corruption"; + } else if (verity_mode != "eio") { // Default dm_verity_mode is eio. + LERROR << "Unknown androidboot.veritymode: " << verity_mode; + return false; + } + + std::ostringstream hash_algorithm; + hash_algorithm << hashtree_desc.hash_algorithm; + + android::dm::DmTargetVerity target(0, hashtree_desc.image_size / 512, + hashtree_desc.dm_verity_version, blk_device, blk_device, + hashtree_desc.data_block_size, hashtree_desc.hash_block_size, + hashtree_desc.image_size / hashtree_desc.data_block_size, + hashtree_desc.tree_offset / hashtree_desc.hash_block_size, + hash_algorithm.str(), root_digest, salt); + if (hashtree_desc.fec_size > 0) { + target.UseFec(blk_device, hashtree_desc.fec_num_roots, + hashtree_desc.fec_offset / hashtree_desc.data_block_size, + hashtree_desc.fec_offset / hashtree_desc.data_block_size); + } + if (!dm_verity_mode.empty()) { + target.SetVerityMode(dm_verity_mode); + } + // Always use ignore_zero_blocks. + target.IgnoreZeroBlocks(); + + LINFO << "Built verity table: '" << target.GetParameterString() << "'"; + + return table->AddTarget(std::make_unique(target)); +} + +bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor& hashtree_desc, + const std::string& salt, const std::string& root_digest, + bool wait_for_verity_dev) { + android::dm::DmTable table; + if (!ConstructVerityTable(hashtree_desc, salt, root_digest, fstab_entry->blk_device, &table) || + !table.valid()) { + LERROR << "Failed to construct verity table."; + return false; + } + table.set_readonly(true); + + const std::string mount_point(basename(fstab_entry->mount_point.c_str())); + android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance(); + if (!dm.CreateDevice(mount_point, table)) { + LERROR << "Couldn't create verity device!"; + return false; + } + + std::string dev_path; + if (!dm.GetDmDevicePathByName(mount_point, &dev_path)) { + LERROR << "Couldn't get verity device path!"; + return false; + } + + // Marks the underlying block device as read-only. + SetBlockDeviceReadOnly(fstab_entry->blk_device); + + // Updates fstab_rec->blk_device to verity device name. + fstab_entry->blk_device = dev_path; + + // Makes sure we've set everything up properly. + if (wait_for_verity_dev && !WaitForFile(dev_path, 1s)) { + return false; + } + + return true; +} + +bool GetHashtreeDescriptor(const std::string& partition_name, + const std::vector& vbmeta_images, + AvbHashtreeDescriptor* out_hashtree_desc, std::string* out_salt, + std::string* out_digest) { + bool found = false; + const uint8_t* desc_partition_name; + + for (size_t i = 0; i < vbmeta_images.size() && !found; i++) { + // Get descriptors from vbmeta_images[i]. + size_t num_descriptors; + std::unique_ptr descriptors( + avb_descriptor_get_all(vbmeta_images[i].data(), vbmeta_images[i].size(), + &num_descriptors), + avb_free); + + if (!descriptors || num_descriptors < 1) { + continue; + } + + for (size_t j = 0; j < num_descriptors && !found; j++) { + AvbDescriptor desc; + if (!avb_descriptor_validate_and_byteswap(descriptors[j], &desc)) { + LWARNING << "Descriptor[" << j << "] is invalid"; + continue; + } + if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) { + desc_partition_name = + (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor); + if (!avb_hashtree_descriptor_validate_and_byteswap( + (AvbHashtreeDescriptor*)descriptors[j], out_hashtree_desc)) { + continue; + } + if (out_hashtree_desc->partition_name_len != partition_name.length()) { + continue; + } + // Notes that desc_partition_name is not NUL-terminated. + std::string hashtree_partition_name((const char*)desc_partition_name, + out_hashtree_desc->partition_name_len); + if (hashtree_partition_name == partition_name) { + found = true; + } + } + } + } + + if (!found) { + LERROR << "Partition descriptor not found: " << partition_name.c_str(); + return false; + } + + const uint8_t* desc_salt = desc_partition_name + out_hashtree_desc->partition_name_len; + *out_salt = BytesToHex(desc_salt, out_hashtree_desc->salt_len); + + const uint8_t* desc_digest = desc_salt + out_hashtree_desc->salt_len; + *out_digest = BytesToHex(desc_digest, out_hashtree_desc->root_digest_len); + + return true; +} + +} // namespace fs_mgr +} // namespace android diff --git a/fs_mgr/libfs_avb/avb_util.h b/fs_mgr/libfs_avb/avb_util.h new file mode 100644 index 000000000..b81e9316d --- /dev/null +++ b/fs_mgr/libfs_avb/avb_util.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include + +#include "fs_avb/fs_avb.h" + +namespace android { +namespace fs_mgr { + +// AvbHashtreeDescriptor to dm-verity table setup. +bool GetHashtreeDescriptor(const std::string& partition_name, + const std::vector& vbmeta_images, + AvbHashtreeDescriptor* out_hashtree_desc, std::string* out_salt, + std::string* out_digest); + +bool ConstructVerityTable(const AvbHashtreeDescriptor& hashtree_desc, const std::string& salt, + const std::string& root_digest, const std::string& blk_device, + android::dm::DmTable* table); + +bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor& hashtree_desc, + const std::string& salt, const std::string& root_digest, + bool wait_for_verity_dev); + +} // namespace fs_mgr +} // namespace android diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp index cf920f9c2..957aa871c 100644 --- a/fs_mgr/libfs_avb/fs_avb.cpp +++ b/fs_mgr/libfs_avb/fs_avb.cpp @@ -28,84 +28,30 @@ #include #include -#include #include -#include -#include #include #include #include "avb_ops.h" -#include "fs_mgr_priv.h" +#include "avb_util.h" #include "sha.h" +#include "util.h" + +using android::base::Basename; +using android::base::ParseUint; +using android::base::StringPrintf; namespace android { namespace fs_mgr { -static inline bool nibble_value(const char& c, uint8_t* value) { - FS_MGR_CHECK(value != nullptr); - - switch (c) { - case '0' ... '9': - *value = c - '0'; - break; - case 'a' ... 'f': - *value = c - 'a' + 10; - break; - case 'A' ... 'F': - *value = c - 'A' + 10; - break; - default: - return false; - } - - return true; -} - -static bool hex_to_bytes(uint8_t* bytes, size_t bytes_len, const std::string& hex) { - FS_MGR_CHECK(bytes != nullptr); - - if (hex.size() % 2 != 0) { - return false; - } - if (hex.size() / 2 > bytes_len) { - return false; - } - for (size_t i = 0, j = 0, n = hex.size(); i < n; i += 2, ++j) { - uint8_t high; - if (!nibble_value(hex[i], &high)) { - return false; - } - uint8_t low; - if (!nibble_value(hex[i + 1], &low)) { - return false; - } - bytes[j] = (high << 4) | low; - } - return true; -} - -static std::string bytes_to_hex(const uint8_t* bytes, size_t bytes_len) { - FS_MGR_CHECK(bytes != nullptr); - - static const char* hex_digits = "0123456789abcdef"; - std::string hex; - - for (size_t i = 0; i < bytes_len; i++) { - hex.push_back(hex_digits[(bytes[i] & 0xF0) >> 4]); - hex.push_back(hex_digits[bytes[i] & 0x0F]); - } - return hex; -} - template -static std::pair verify_vbmeta_digest(const std::vector& vbmeta_images, - const uint8_t* expected_digest) { +std::pair VerifyVbmetaDigest(const std::vector& vbmeta_images, + const uint8_t* expected_digest) { size_t total_size = 0; Hasher hasher; - for (size_t n = 0; n < vbmeta_images.size(); n++) { - hasher.update(vbmeta_images[n].vbmeta_data(), vbmeta_images[n].vbmeta_size()); - total_size += vbmeta_images[n].vbmeta_size(); + for (const auto& vbmeta : vbmeta_images) { + hasher.update(vbmeta.data(), vbmeta.size()); + total_size += vbmeta.size(); } bool matched = (memcmp(hasher.finalize(), expected_digest, Hasher::DIGEST_SIZE) == 0); @@ -148,7 +94,7 @@ std::unique_ptr AvbVerifier::Create() { std::string value; if (!fs_mgr_get_boot_config("vbmeta.size", &value) || - !android::base::ParseUint(value.c_str(), &avb_verifier->vbmeta_size_)) { + !ParseUint(value.c_str(), &avb_verifier->vbmeta_size_)) { LERROR << "Invalid hash size: " << value.c_str(); return nullptr; } @@ -177,7 +123,7 @@ std::unique_ptr AvbVerifier::Create() { return nullptr; } - if (!hex_to_bytes(avb_verifier->digest_, sizeof(avb_verifier->digest_), digest)) { + if (!HexToBytes(avb_verifier->digest_, sizeof(avb_verifier->digest_), digest)) { LERROR << "Hash digest contains non-hexidecimal character: " << digest.c_str(); return nullptr; } @@ -196,10 +142,10 @@ bool AvbVerifier::VerifyVbmetaImages(const std::vector& vbmeta_image if (hash_alg_ == kSHA256) { std::tie(total_size, digest_matched) = - verify_vbmeta_digest(vbmeta_images, digest_); + VerifyVbmetaDigest(vbmeta_images, digest_); } else if (hash_alg_ == kSHA512) { std::tie(total_size, digest_matched) = - verify_vbmeta_digest(vbmeta_images, digest_); + VerifyVbmetaDigest(vbmeta_images, digest_); } if (total_size != vbmeta_size_) { @@ -216,155 +162,9 @@ bool AvbVerifier::VerifyVbmetaImages(const std::vector& vbmeta_image return true; } -// Constructs dm-verity arguments for sending DM_TABLE_LOAD ioctl to kernel. -// See the following link for more details: -// https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity -static bool construct_verity_table(const AvbHashtreeDescriptor& hashtree_desc, - const std::string& salt, const std::string& root_digest, - const std::string& blk_device, android::dm::DmTable* table) { - // Loads androidboot.veritymode from kernel cmdline. - std::string verity_mode; - if (!fs_mgr_get_boot_config("veritymode", &verity_mode)) { - verity_mode = "enforcing"; // Defaults to enforcing when it's absent. - } - - // Converts veritymode to the format used in kernel. - std::string dm_verity_mode; - if (verity_mode == "enforcing") { - dm_verity_mode = "restart_on_corruption"; - } else if (verity_mode == "logging") { - dm_verity_mode = "ignore_corruption"; - } else if (verity_mode != "eio") { // Default dm_verity_mode is eio. - LERROR << "Unknown androidboot.veritymode: " << verity_mode; - return false; - } - - std::ostringstream hash_algorithm; - hash_algorithm << hashtree_desc.hash_algorithm; - - android::dm::DmTargetVerity target(0, hashtree_desc.image_size / 512, - hashtree_desc.dm_verity_version, blk_device, blk_device, - hashtree_desc.data_block_size, hashtree_desc.hash_block_size, - hashtree_desc.image_size / hashtree_desc.data_block_size, - hashtree_desc.tree_offset / hashtree_desc.hash_block_size, - hash_algorithm.str(), root_digest, salt); - if (hashtree_desc.fec_size > 0) { - target.UseFec(blk_device, hashtree_desc.fec_num_roots, - hashtree_desc.fec_offset / hashtree_desc.data_block_size, - hashtree_desc.fec_offset / hashtree_desc.data_block_size); - } - if (!dm_verity_mode.empty()) { - target.SetVerityMode(dm_verity_mode); - } - // Always use ignore_zero_blocks. - target.IgnoreZeroBlocks(); - - LINFO << "Built verity table: '" << target.GetParameterString() << "'"; - - return table->AddTarget(std::make_unique(target)); -} - -static bool hashtree_dm_verity_setup(FstabEntry* fstab_entry, - const AvbHashtreeDescriptor& hashtree_desc, - const std::string& salt, const std::string& root_digest, - bool wait_for_verity_dev) { - android::dm::DmTable table; - if (!construct_verity_table(hashtree_desc, salt, root_digest, fstab_entry->blk_device, - &table) || - !table.valid()) { - LERROR << "Failed to construct verity table."; - return false; - } - table.set_readonly(true); - - const std::string mount_point(basename(fstab_entry->mount_point.c_str())); - android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance(); - if (!dm.CreateDevice(mount_point, table)) { - LERROR << "Couldn't create verity device!"; - return false; - } - - std::string dev_path; - if (!dm.GetDmDevicePathByName(mount_point, &dev_path)) { - LERROR << "Couldn't get verity device path!"; - return false; - } - - // Marks the underlying block device as read-only. - fs_mgr_set_blk_ro(fstab_entry->blk_device); - - // Updates fstab_rec->blk_device to verity device name. - fstab_entry->blk_device = dev_path; - - // Makes sure we've set everything up properly. - if (wait_for_verity_dev && !fs_mgr_wait_for_file(dev_path, 1s)) { - return false; - } - - return true; -} - -static bool get_hashtree_descriptor(const std::string& partition_name, - const std::vector& vbmeta_images, - AvbHashtreeDescriptor* out_hashtree_desc, std::string* out_salt, - std::string* out_digest) { - bool found = false; - const uint8_t* desc_partition_name; - - for (size_t i = 0; i < vbmeta_images.size() && !found; i++) { - // Get descriptors from vbmeta_images[i]. - size_t num_descriptors; - std::unique_ptr descriptors( - avb_descriptor_get_all(vbmeta_images[i].vbmeta_data(), - vbmeta_images[i].vbmeta_size(), &num_descriptors), - avb_free); - - if (!descriptors || num_descriptors < 1) { - continue; - } - - for (size_t j = 0; j < num_descriptors && !found; j++) { - AvbDescriptor desc; - if (!avb_descriptor_validate_and_byteswap(descriptors[j], &desc)) { - LWARNING << "Descriptor[" << j << "] is invalid"; - continue; - } - if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) { - desc_partition_name = - (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor); - if (!avb_hashtree_descriptor_validate_and_byteswap( - (AvbHashtreeDescriptor*)descriptors[j], out_hashtree_desc)) { - continue; - } - if (out_hashtree_desc->partition_name_len != partition_name.length()) { - continue; - } - // Notes that desc_partition_name is not NUL-terminated. - std::string hashtree_partition_name((const char*)desc_partition_name, - out_hashtree_desc->partition_name_len); - if (hashtree_partition_name == partition_name) { - found = true; - } - } - } - } - - if (!found) { - LERROR << "Partition descriptor not found: " << partition_name.c_str(); - return false; - } - - const uint8_t* desc_salt = desc_partition_name + out_hashtree_desc->partition_name_len; - *out_salt = bytes_to_hex(desc_salt, out_hashtree_desc->salt_len); - - const uint8_t* desc_digest = desc_salt + out_hashtree_desc->salt_len; - *out_digest = bytes_to_hex(desc_digest, out_hashtree_desc->root_digest_len); - - return true; -} AvbUniquePtr AvbHandle::Open() { - bool is_device_unlocked = fs_mgr_is_device_unlocked(); + bool is_device_unlocked = IsDeviceUnlocked(); AvbUniquePtr avb_handle(new AvbHandle()); if (!avb_handle) { @@ -407,8 +207,7 @@ AvbUniquePtr AvbHandle::Open() { } // Sets the MAJOR.MINOR for init to set it into "ro.boot.avb_version". - avb_handle->avb_version_ = - android::base::StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR); + avb_handle->avb_version_ = StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR); // Checks whether FLAGS_VERIFICATION_DISABLED is set: // - Only the top-level vbmeta struct is read. @@ -416,7 +215,7 @@ AvbUniquePtr AvbHandle::Open() { // and AVB HASHTREE descriptor(s). AvbVBMetaImageHeader vbmeta_header; avb_vbmeta_image_header_to_host_byte_order( - (AvbVBMetaImageHeader*)avb_handle->vbmeta_images_[0].vbmeta_data(), &vbmeta_header); + (AvbVBMetaImageHeader*)avb_handle->vbmeta_images_[0].data(), &vbmeta_header); bool verification_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED); @@ -462,7 +261,7 @@ AvbHashtreeResult AvbHandle::SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait if (fstab_entry->fs_mgr_flags.logical) { partition_name = fstab_entry->logical_partition_name; } else { - partition_name = basename(fstab_entry->blk_device.c_str()); + partition_name = Basename(fstab_entry->blk_device); } if (fstab_entry->fs_mgr_flags.slot_select) { @@ -475,14 +274,14 @@ AvbHashtreeResult AvbHandle::SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait AvbHashtreeDescriptor hashtree_descriptor; std::string salt; std::string root_digest; - if (!get_hashtree_descriptor(partition_name, vbmeta_images_, &hashtree_descriptor, &salt, - &root_digest)) { + if (!GetHashtreeDescriptor(partition_name, vbmeta_images_, &hashtree_descriptor, &salt, + &root_digest)) { return AvbHashtreeResult::kFail; } // Converts HASHTREE descriptor to verity_table_params. - if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt, root_digest, - wait_for_verity_dev)) { + if (!HashtreeDmVeritySetup(fstab_entry, hashtree_descriptor, salt, root_digest, + wait_for_verity_dev)) { return AvbHashtreeResult::kFail; } diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h index 0c2b2318c..eca69845a 100644 --- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h +++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h @@ -37,7 +37,7 @@ class VBMetaData { // Constructors VBMetaData() : vbmeta_ptr_(nullptr), vbmeta_size_(0){}; - VBMetaData(uint8_t* data, size_t size) + VBMetaData(const uint8_t* data, size_t size) : vbmeta_ptr_(new (std::nothrow) uint8_t[size]), vbmeta_size_(size) { // The ownership of data is NOT transferred, i.e., the caller still // needs to release the memory as we make a copy here. @@ -49,8 +49,8 @@ class VBMetaData { // Get methods for each data member. const std::string& device_path() const { return device_path_; } - uint8_t* vbmeta_data() const { return vbmeta_ptr_.get(); } - const size_t& vbmeta_size() const { return vbmeta_size_; } + uint8_t* data() const { return vbmeta_ptr_.get(); } + const size_t& size() const { return vbmeta_size_; } // Maximum size of a vbmeta data - 64 KiB. static const size_t kMaxVBMetaSize = 64 * 1024; diff --git a/fs_mgr/libfs_avb/tests/Android.bp b/fs_mgr/libfs_avb/tests/Android.bp deleted file mode 100644 index 24e1d76f2..000000000 --- a/fs_mgr/libfs_avb/tests/Android.bp +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -cc_test_host { - name: "libfs_avb_host_unittest", - required: [ - "avbtool", - ], - data: [ - "data/*", - ], - static_libs: [ - "libgtest_host", - ], - shared_libs: [ - "libbase", - "libchrome", - ], - srcs: [ - "fs_avb_unittest_util.cpp", - ], - target: { - darwin: { - enabled: false, - }, - }, -} diff --git a/fs_mgr/libfs_avb/tests/fs_avb_unittest_util.cpp b/fs_mgr/libfs_avb/tests/basic_test.cpp similarity index 54% rename from fs_mgr/libfs_avb/tests/fs_avb_unittest_util.cpp rename to fs_mgr/libfs_avb/tests/basic_test.cpp index 216d1cb5c..5a1cd0dd8 100644 --- a/fs_mgr/libfs_avb/tests/fs_avb_unittest_util.cpp +++ b/fs_mgr/libfs_avb/tests/basic_test.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "fs_avb_unittest_util.h" +#include "fs_avb_test_util.h" #include @@ -24,195 +24,6 @@ namespace fs_avb_host_test { -void BaseFsAvbTest::SetUp() { - // Changes current directory to test executable directory so that relative path - // references to test dependencies don't rely on being manually run from - // the executable directory. With this, we can just open "./data/testkey_rsa2048.pem" - // from the source. - base::SetCurrentDirectory(base::FilePath(android::base::GetExecutableDirectory())); - - // Creates a temporary directory, e.g., /tmp/libfs_avb-tests.XXXXXX to stash images in. - base::FilePath tmp_dir; - ASSERT_TRUE(GetTempDir(&tmp_dir)); - base::CreateTemporaryDirInDir(tmp_dir, "libfs_avb-tests.", &test_dir_); -} - -void BaseFsAvbTest::TearDown() { - // Nukes temporary directory. - ASSERT_NE(std::string::npos, test_dir_.value().find("libfs_avb-tests")); - ASSERT_TRUE(base::DeleteFile(test_dir_, true /* recursive */)); -} - -std::string BaseFsAvbTest::CalcVBMetaDigest(const std::string& file_name, - const std::string& hash_algorithm) { - auto iter = vbmeta_images_.find(file_name); - EXPECT_NE(iter, vbmeta_images_.end()); // ensures file_name is generated before. - - // Gets the image path from iterator->second.path: VBMetaImage.path. - base::FilePath image_path = iter->second.path; - base::FilePath vbmeta_digest_path = test_dir_.Append("vbmeta_digest"); - EXPECT_COMMAND(0, - "avbtool calculate_vbmeta_digest --image %s --hash_algorithm %s" - " --output %s", - image_path.value().c_str(), hash_algorithm.c_str(), - vbmeta_digest_path.value().c_str()); - // Reads the content of the output digest file. - std::string vbmeta_digest_data; - EXPECT_TRUE(base::ReadFileToString(vbmeta_digest_path, &vbmeta_digest_data)); - // Returns the trimmed digest. - std::string trimmed_digest_data; - base::TrimString(vbmeta_digest_data, " \t\n", &trimmed_digest_data); - return trimmed_digest_data; -} - -void BaseFsAvbTest::GenerateVBMetaImage( - const std::string& file_name, const std::string& avb_algorithm, uint64_t rollback_index, - const base::FilePath& key_path, - const std::vector& include_descriptor_image_paths, - const std::vector& chain_partitions, - const std::string& additional_options) { - // --algorithm and --key - std::string signing_options; - if (avb_algorithm == "") { - signing_options = " --algorithm NONE "; - } else { - signing_options = - std::string(" --algorithm ") + avb_algorithm + " --key " + key_path.value() + " "; - } - // --include_descriptors_from_image - std::string include_descriptor_options; - for (const auto& path : include_descriptor_image_paths) { - include_descriptor_options += " --include_descriptors_from_image " + path.value(); - } - // --chain_partitions - std::string chain_partition_options; - for (const auto& partition : chain_partitions) { - chain_partition_options += base::StringPrintf( - " --chain_partition %s:%u:%s", partition.partition_name.c_str(), - partition.rollback_index_location, partition.key_blob_path.value().c_str()); - } - // Starts to 'make_vbmeta_image'. - VBMetaImage vbmeta_image; - vbmeta_image.path = test_dir_.Append(file_name); - EXPECT_COMMAND(0, - "avbtool make_vbmeta_image" - " --rollback_index %" PRIu64 - " %s %s %s %s" - " --output %s", - rollback_index, signing_options.c_str(), include_descriptor_options.c_str(), - chain_partition_options.c_str(), additional_options.c_str(), - vbmeta_image.path.value().c_str()); - int64_t file_size; - ASSERT_TRUE(base::GetFileSize(vbmeta_image.path, &file_size)); - vbmeta_image.content.resize(file_size); - ASSERT_TRUE(base::ReadFile(vbmeta_image.path, - reinterpret_cast(vbmeta_image.content.data()), file_size)); - // Stores the generated vbmeta image into vbmeta_images_ member object. - vbmeta_images_.emplace(file_name, std::move(vbmeta_image)); -} - -void BaseFsAvbTest::ExtractVBMetaImage(const base::FilePath& image_path, - const std::string& output_file_name, - const size_t padding_size) { - VBMetaImage vbmeta_image; - vbmeta_image.path = test_dir_.Append(output_file_name); - EXPECT_COMMAND(0, - "avbtool extract_vbmeta_image" - " --image %s" - " --output %s" - " --padding_size %zu", - image_path.value().c_str(), vbmeta_image.path.value().c_str(), padding_size); - int64_t file_size; - ASSERT_TRUE(base::GetFileSize(vbmeta_image.path, &file_size)); - vbmeta_image.content.resize(file_size); - ASSERT_TRUE(base::ReadFile(vbmeta_image.path, - reinterpret_cast(vbmeta_image.content.data()), file_size)); - // Stores the extracted vbmeta image into vbmeta_images_ member object. - vbmeta_images_.emplace(output_file_name, std::move(vbmeta_image)); -} - -// Generates a file with name |file_name| of size |image_size| with -// known content (0x00 0x01 0x02 .. 0xff 0x00 0x01 ..). -base::FilePath BaseFsAvbTest::GenerateImage(const std::string file_name, size_t image_size, - uint8_t start_byte) { - std::vector image; - image.resize(image_size); - for (size_t n = 0; n < image_size; n++) { - image[n] = uint8_t(n + start_byte); - } - base::FilePath image_path = test_dir_.Append(file_name); - EXPECT_EQ(image_size, - static_cast(base::WriteFile( - image_path, reinterpret_cast(image.data()), image.size()))); - return image_path; -} - -void BaseFsAvbTest::AddAvbFooter(const base::FilePath& image_path, const std::string& footer_type, - const std::string& partition_name, const uint64_t partition_size, - const std::string& avb_algorithm, uint64_t rollback_index, - const base::FilePath& key_path, const std::string& salt, - const std::string& additional_options) { - // 'add_hash_footer' or 'add_hashtree_footer'. - EXPECT_TRUE(footer_type == "hash" or footer_type == "hashtree"); - std::string add_footer_option = "add_" + footer_type + "_footer"; - - std::string signing_options; - if (avb_algorithm == "") { - signing_options = " --algorithm NONE "; - } else { - signing_options = - std::string(" --algorithm ") + avb_algorithm + " --key " + key_path.value() + " "; - } - EXPECT_COMMAND(0, - "avbtool %s" - " --image %s" - " --partition_name %s " - " --partition_size %" PRIu64 " --rollback_index %" PRIu64 - " --salt %s" - " %s %s", - add_footer_option.c_str(), image_path.value().c_str(), partition_name.c_str(), - partition_size, rollback_index, salt.c_str(), signing_options.c_str(), - additional_options.c_str()); -} - -std::string BaseFsAvbTest::InfoImage(const base::FilePath& image_path) { - base::FilePath tmp_path = test_dir_.Append("info_output.txt"); - EXPECT_COMMAND(0, "avbtool info_image --image %s --output %s", image_path.value().c_str(), - tmp_path.value().c_str()); - std::string info_data; - EXPECT_TRUE(base::ReadFileToString(tmp_path, &info_data)); - return info_data; -} - -std::string BaseFsAvbTest::InfoImage(const std::string& file_name) { - auto iter = vbmeta_images_.find(file_name); - EXPECT_NE(iter, vbmeta_images_.end()); // ensures file_name is generated before. - // Gets the image path from iterator->second.path: VBMetaImage.path. - base::FilePath image_path = iter->second.path; - return InfoImage(image_path); -} - -base::FilePath BaseFsAvbTest::ExtractPublicKeyAvb(const base::FilePath& key_path) { - std::string file_name = key_path.RemoveExtension().BaseName().value(); - base::FilePath tmp_path = test_dir_.Append(file_name + "public_key.bin"); - EXPECT_COMMAND(0, - "avbtool extract_public_key --key %s" - " --output %s", - key_path.value().c_str(), tmp_path.value().c_str()); - return tmp_path; -} - -std::string BaseFsAvbTest::ExtractPublicKeyAvbBlob(const base::FilePath& key_path) { - base::FilePath tmp_path = test_dir_.Append("public_key.bin"); - EXPECT_COMMAND(0, - "avbtool extract_public_key --key %s" - " --output %s", - key_path.value().c_str(), tmp_path.value().c_str()); - std::string key_data; - EXPECT_TRUE(base::ReadFileToString(tmp_path, &key_data)); - return key_data; -} - TEST_F(BaseFsAvbTest, GenerateImage) { const size_t image_size = 5 * 1024 * 1024; base::FilePath boot_path = GenerateImage("boot.img", image_size); @@ -237,8 +48,7 @@ TEST_F(BaseFsAvbTest, GenerateImage) { } TEST_F(BaseFsAvbTest, GenerateVBMetaImage) { - GenerateVBMetaImage("vbmeta.img", "SHA256_RSA2048", 0, - base::FilePath("data/testkey_rsa2048.pem"), + GenerateVBMetaImage("vbmeta.img", "SHA256_RSA2048", 0, data_dir_.Append("testkey_rsa2048.pem"), {}, /* include_descriptor_image_paths */ {}, /* chain_partitions */ "--internal_release_string \"unit test\""); @@ -270,7 +80,7 @@ TEST_F(BaseFsAvbTest, AddHashFooter) { EXPECT_EQ(file_size, image_size); // Appends AVB Hash Footer. AddAvbFooter(boot_path, "hash", "boot", partition_size, "SHA256_RSA4096", 10, - base::FilePath("data/testkey_rsa4096.pem"), "d00df00d", + data_dir_.Append("testkey_rsa4096.pem"), "d00df00d", "--internal_release_string \"unit test\""); // Extracts boot vbmeta from boot.img into boot-vbmeta.img. ExtractVBMetaImage(boot_path, "boot-vbmeta.img"); @@ -307,7 +117,7 @@ TEST_F(BaseFsAvbTest, AddHashtreeFooter) { EXPECT_EQ(file_size, image_size); // Appends AVB Hashtree Footer. AddAvbFooter(system_path, "hashtree", "system", partition_size, "SHA512_RSA8192", 20, - base::FilePath("data/testkey_rsa8192.pem"), "d00df00d", + data_dir_.Append("testkey_rsa8192.pem"), "d00df00d", "--internal_release_string \"unit test\""); // Extracts system vbmeta from system.img into system-vbmeta.img. ExtractVBMetaImage(system_path, "system-vbmeta.img"); @@ -346,7 +156,7 @@ TEST_F(BaseFsAvbTest, GenerateVBMetaImageWithDescriptors) { base::FilePath boot_path = GenerateImage("boot.img", boot_image_size); // Adds AVB Hash Footer. AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA4096", 10, - base::FilePath("data/testkey_rsa4096.pem"), "d00df00d", + data_dir_.Append("testkey_rsa4096.pem"), "d00df00d", "--internal_release_string \"unit test\""); // Generates a raw system.img, use a smaller size to speed-up unit test. @@ -355,12 +165,11 @@ TEST_F(BaseFsAvbTest, GenerateVBMetaImageWithDescriptors) { base::FilePath system_path = GenerateImage("system.img", system_image_size); // Adds AVB Hashtree Footer. AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA8192", 20, - base::FilePath("data/testkey_rsa8192.pem"), "d00df00d", + data_dir_.Append("testkey_rsa8192.pem"), "d00df00d", "--internal_release_string \"unit test\""); // Makes a vbmeta.img including both 'boot' and 'system' descriptors. - GenerateVBMetaImage("vbmeta.img", "SHA256_RSA2048", 0, - base::FilePath("data/testkey_rsa2048.pem"), + GenerateVBMetaImage("vbmeta.img", "SHA256_RSA2048", 0, data_dir_.Append("testkey_rsa2048.pem"), {boot_path, system_path}, /* include_descriptor_image_paths */ {}, /* chain_partitions */ "--internal_release_string \"unit test\""); @@ -409,7 +218,7 @@ TEST_F(BaseFsAvbTest, GenerateVBMetaImageWithChainDescriptors) { base::FilePath boot_path = GenerateImage("boot.img", boot_image_size); // Adds AVB Hash Footer. AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10, - base::FilePath("data/testkey_rsa2048.pem"), "d00df00d", + data_dir_.Append("testkey_rsa2048.pem"), "d00df00d", "--internal_release_string \"unit test\""); // Generates a raw system.img, use a smaller size to speed-up unit test. @@ -418,16 +227,15 @@ TEST_F(BaseFsAvbTest, GenerateVBMetaImageWithChainDescriptors) { base::FilePath system_path = GenerateImage("system.img", system_image_size); // Adds AVB Hashtree Footer. AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20, - base::FilePath("data/testkey_rsa4096.pem"), "d00df00d", + data_dir_.Append("testkey_rsa4096.pem"), "d00df00d", "--internal_release_string \"unit test\""); // Make a vbmeta image with chain partitions. base::FilePath rsa2048_public_key = - ExtractPublicKeyAvb(base::FilePath("data/testkey_rsa2048.pem")); + ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem")); base::FilePath rsa4096_public_key = - ExtractPublicKeyAvb(base::FilePath("data/testkey_rsa4096.pem")); - GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0, - base::FilePath("data/testkey_rsa8192.pem"), + ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem")); + GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0, data_dir_.Append("testkey_rsa8192.pem"), {}, /* include_descriptor_image_paths */ {{"boot", 1, rsa2048_public_key}, /* chain_partitions */ {"system", 2, rsa4096_public_key}}, diff --git a/fs_mgr/libfs_avb/tests/fs_avb_test_util.cpp b/fs_mgr/libfs_avb/tests/fs_avb_test_util.cpp new file mode 100644 index 000000000..95b17d8ed --- /dev/null +++ b/fs_mgr/libfs_avb/tests/fs_avb_test_util.cpp @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fs_avb_test_util.h" + +#include + +#include +#include +#include + +namespace fs_avb_host_test { + +// Need to match the data setting in Android.bp: +// data: ["tests/data/*"] +base::FilePath BaseFsAvbTest::data_dir_ = base::FilePath("tests/data"); + +void BaseFsAvbTest::SetUp() { + // Changes current directory to test executable directory so that relative path + // references to test dependencies don't rely on being manually run from + // the executable directory. With this, we can just open "./tests/data/testkey_rsa2048.pem" + // from the source. + base::SetCurrentDirectory(base::FilePath(android::base::GetExecutableDirectory())); + + // Creates a temporary directory, e.g., /tmp/libfs_avb-tests.XXXXXX to stash images in. + base::FilePath tmp_dir; + ASSERT_TRUE(GetTempDir(&tmp_dir)); + base::CreateTemporaryDirInDir(tmp_dir, "libfs_avb-tests.", &test_dir_); +} + +void BaseFsAvbTest::TearDown() { + // Nukes temporary directory. + ASSERT_NE(std::string::npos, test_dir_.value().find("libfs_avb-tests")); + ASSERT_TRUE(base::DeleteFile(test_dir_, true /* recursive */)); +} + +std::string BaseFsAvbTest::CalcVBMetaDigest(const std::string& file_name, + const std::string& hash_algorithm) { + auto iter = vbmeta_images_.find(file_name); + EXPECT_NE(iter, vbmeta_images_.end()); // ensures file_name is generated before. + + // Gets the image path from iterator->second.path: VBMetaImage.path. + base::FilePath image_path = iter->second.path; + base::FilePath vbmeta_digest_path = test_dir_.Append("vbmeta_digest"); + EXPECT_COMMAND(0, + "avbtool calculate_vbmeta_digest --image %s --hash_algorithm %s" + " --output %s", + image_path.value().c_str(), hash_algorithm.c_str(), + vbmeta_digest_path.value().c_str()); + // Reads the content of the output digest file. + std::string vbmeta_digest_data; + EXPECT_TRUE(base::ReadFileToString(vbmeta_digest_path, &vbmeta_digest_data)); + // Returns the trimmed digest. + std::string trimmed_digest_data; + base::TrimString(vbmeta_digest_data, " \t\n", &trimmed_digest_data); + return trimmed_digest_data; +} + +void BaseFsAvbTest::GenerateVBMetaImage( + const std::string& file_name, const std::string& avb_algorithm, uint64_t rollback_index, + const base::FilePath& key_path, + const std::vector& include_descriptor_image_paths, + const std::vector& chain_partitions, + const std::string& additional_options) { + // --algorithm and --key + std::string signing_options; + if (avb_algorithm == "") { + signing_options = " --algorithm NONE "; + } else { + signing_options = + std::string(" --algorithm ") + avb_algorithm + " --key " + key_path.value() + " "; + } + // --include_descriptors_from_image + std::string include_descriptor_options; + for (const auto& path : include_descriptor_image_paths) { + include_descriptor_options += " --include_descriptors_from_image " + path.value(); + } + // --chain_partitions + std::string chain_partition_options; + for (const auto& partition : chain_partitions) { + chain_partition_options += base::StringPrintf( + " --chain_partition %s:%u:%s", partition.partition_name.c_str(), + partition.rollback_index_location, partition.key_blob_path.value().c_str()); + } + // Starts to 'make_vbmeta_image'. + VBMetaImage vbmeta_image; + vbmeta_image.path = test_dir_.Append(file_name); + EXPECT_COMMAND(0, + "avbtool make_vbmeta_image" + " --rollback_index %" PRIu64 + " %s %s %s %s" + " --output %s", + rollback_index, signing_options.c_str(), include_descriptor_options.c_str(), + chain_partition_options.c_str(), additional_options.c_str(), + vbmeta_image.path.value().c_str()); + int64_t file_size; + ASSERT_TRUE(base::GetFileSize(vbmeta_image.path, &file_size)); + vbmeta_image.content.resize(file_size); + ASSERT_TRUE(base::ReadFile(vbmeta_image.path, + reinterpret_cast(vbmeta_image.content.data()), file_size)); + // Stores the generated vbmeta image into vbmeta_images_ member object. + vbmeta_images_.emplace(file_name, std::move(vbmeta_image)); +} + +void BaseFsAvbTest::ExtractVBMetaImage(const base::FilePath& image_path, + const std::string& output_file_name, + const size_t padding_size) { + VBMetaImage vbmeta_image; + vbmeta_image.path = test_dir_.Append(output_file_name); + EXPECT_COMMAND(0, + "avbtool extract_vbmeta_image" + " --image %s" + " --output %s" + " --padding_size %zu", + image_path.value().c_str(), vbmeta_image.path.value().c_str(), padding_size); + int64_t file_size; + ASSERT_TRUE(base::GetFileSize(vbmeta_image.path, &file_size)); + vbmeta_image.content.resize(file_size); + ASSERT_TRUE(base::ReadFile(vbmeta_image.path, + reinterpret_cast(vbmeta_image.content.data()), file_size)); + // Stores the extracted vbmeta image into vbmeta_images_ member object. + vbmeta_images_.emplace(output_file_name, std::move(vbmeta_image)); +} + +// Generates a file with name |file_name| of size |image_size| with +// known content (0x00 0x01 0x02 .. 0xff 0x00 0x01 ..). +base::FilePath BaseFsAvbTest::GenerateImage(const std::string& file_name, size_t image_size, + uint8_t start_byte) { + std::vector image; + image.resize(image_size); + for (size_t n = 0; n < image_size; n++) { + image[n] = uint8_t(n + start_byte); + } + base::FilePath image_path = test_dir_.Append(file_name); + EXPECT_EQ(image_size, + static_cast(base::WriteFile( + image_path, reinterpret_cast(image.data()), image.size()))); + return image_path; +} + +void BaseFsAvbTest::AddAvbFooter(const base::FilePath& image_path, const std::string& footer_type, + const std::string& partition_name, const uint64_t partition_size, + const std::string& avb_algorithm, uint64_t rollback_index, + const base::FilePath& key_path, const std::string& salt, + const std::string& additional_options) { + // 'add_hash_footer' or 'add_hashtree_footer'. + EXPECT_TRUE(footer_type == "hash" or footer_type == "hashtree"); + std::string add_footer_option = "add_" + footer_type + "_footer"; + + std::string signing_options; + if (avb_algorithm == "") { + signing_options = " --algorithm NONE "; + } else { + signing_options = + std::string(" --algorithm ") + avb_algorithm + " --key " + key_path.value() + " "; + } + EXPECT_COMMAND(0, + "avbtool %s" + " --image %s" + " --partition_name %s " + " --partition_size %" PRIu64 " --rollback_index %" PRIu64 + " --salt %s" + " %s %s", + add_footer_option.c_str(), image_path.value().c_str(), partition_name.c_str(), + partition_size, rollback_index, salt.c_str(), signing_options.c_str(), + additional_options.c_str()); +} + +std::string BaseFsAvbTest::InfoImage(const base::FilePath& image_path) { + base::FilePath tmp_path = test_dir_.Append("info_output.txt"); + EXPECT_COMMAND(0, "avbtool info_image --image %s --output %s", image_path.value().c_str(), + tmp_path.value().c_str()); + std::string info_data; + EXPECT_TRUE(base::ReadFileToString(tmp_path, &info_data)); + return info_data; +} + +std::string BaseFsAvbTest::InfoImage(const std::string& file_name) { + auto iter = vbmeta_images_.find(file_name); + EXPECT_NE(iter, vbmeta_images_.end()); // ensures file_name is generated before. + // Gets the image path from iterator->second.path: VBMetaImage.path. + base::FilePath image_path = iter->second.path; + return InfoImage(image_path); +} + +base::FilePath BaseFsAvbTest::ExtractPublicKeyAvb(const base::FilePath& key_path) { + std::string file_name = key_path.RemoveExtension().BaseName().value(); + base::FilePath tmp_path = test_dir_.Append(file_name + "public_key.bin"); + EXPECT_COMMAND(0, + "avbtool extract_public_key --key %s" + " --output %s", + key_path.value().c_str(), tmp_path.value().c_str()); + return tmp_path; +} + +std::string BaseFsAvbTest::ExtractPublicKeyAvbBlob(const base::FilePath& key_path) { + base::FilePath tmp_path = test_dir_.Append("public_key.bin"); + EXPECT_COMMAND(0, + "avbtool extract_public_key --key %s" + " --output %s", + key_path.value().c_str(), tmp_path.value().c_str()); + std::string key_data; + EXPECT_TRUE(base::ReadFileToString(tmp_path, &key_data)); + return key_data; +} + +} // namespace fs_avb_host_test diff --git a/fs_mgr/libfs_avb/tests/fs_avb_unittest_util.h b/fs_mgr/libfs_avb/tests/fs_avb_test_util.h similarity index 97% rename from fs_mgr/libfs_avb/tests/fs_avb_unittest_util.h rename to fs_mgr/libfs_avb/tests/fs_avb_test_util.h index f3294660c..f80dc5f88 100644 --- a/fs_mgr/libfs_avb/tests/fs_avb_unittest_util.h +++ b/fs_mgr/libfs_avb/tests/fs_avb_test_util.h @@ -79,7 +79,7 @@ class BaseFsAvbTest : public ::testing::Test { // Generate a file with name |file_name| of size |image_size| with // known content (0x00 0x01 0x02 .. 0xff 0x00 0x01 ..). - base::FilePath GenerateImage(const std::string file_name, size_t image_size, + base::FilePath GenerateImage(const std::string& file_name, size_t image_size, uint8_t start_byte = 0); // Invokes 'avbtool add_hash_footer' or 'avbtool add_hashtree_footer' to sign // the |image_path|. The |footer_type| can be either "hash" or "hashtree". @@ -107,6 +107,8 @@ class BaseFsAvbTest : public ::testing::Test { base::FilePath test_dir_; // Maps vbmeta image name (e.g., vbmeta_a.img, system_a.img) to VBMetaImage. std::map vbmeta_images_; + + static base::FilePath data_dir_; }; } // namespace fs_avb_host_test diff --git a/fs_mgr/libfs_avb/tests/util_test.cpp b/fs_mgr/libfs_avb/tests/util_test.cpp new file mode 100644 index 000000000..835e8fd3e --- /dev/null +++ b/fs_mgr/libfs_avb/tests/util_test.cpp @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include + +#include "fs_avb_test_util.h" +#include "util.h" + +// Target functions to test: +using android::fs_mgr::BytesToHex; +using android::fs_mgr::HexToBytes; +using android::fs_mgr::NibbleValue; +using android::fs_mgr::WaitForFile; + +namespace fs_avb_host_test { + +TEST(BasicUtilTest, NibbleValue09) { + uint8_t value; + + EXPECT_TRUE(NibbleValue('0', &value)); + EXPECT_EQ(0, value); + EXPECT_TRUE(NibbleValue('1', &value)); + EXPECT_EQ(1, value); + EXPECT_TRUE(NibbleValue('2', &value)); + EXPECT_EQ(2, value); + EXPECT_TRUE(NibbleValue('3', &value)); + EXPECT_EQ(3, value); + EXPECT_TRUE(NibbleValue('4', &value)); + EXPECT_EQ(4, value); + EXPECT_TRUE(NibbleValue('5', &value)); + EXPECT_EQ(5, value); + EXPECT_TRUE(NibbleValue('6', &value)); + EXPECT_EQ(6, value); + EXPECT_TRUE(NibbleValue('7', &value)); + EXPECT_EQ(7, value); + EXPECT_TRUE(NibbleValue('8', &value)); + EXPECT_EQ(8, value); + EXPECT_TRUE(NibbleValue('9', &value)); + EXPECT_EQ(9, value); +} + +TEST(BasicUtilTest, NibbleValueAF) { + uint8_t value; + + EXPECT_TRUE(NibbleValue('a', &value)); + EXPECT_EQ(10, value); + EXPECT_TRUE(NibbleValue('b', &value)); + EXPECT_EQ(11, value); + EXPECT_TRUE(NibbleValue('c', &value)); + EXPECT_EQ(12, value); + EXPECT_TRUE(NibbleValue('d', &value)); + EXPECT_EQ(13, value); + EXPECT_TRUE(NibbleValue('e', &value)); + EXPECT_EQ(14, value); + EXPECT_TRUE(NibbleValue('f', &value)); + EXPECT_EQ(15, value); + + EXPECT_TRUE(NibbleValue('A', &value)); + EXPECT_EQ(10, value); + EXPECT_TRUE(NibbleValue('B', &value)); + EXPECT_EQ(11, value); + EXPECT_TRUE(NibbleValue('C', &value)); + EXPECT_EQ(12, value); + EXPECT_TRUE(NibbleValue('D', &value)); + EXPECT_EQ(13, value); + EXPECT_TRUE(NibbleValue('E', &value)); + EXPECT_EQ(14, value); + EXPECT_TRUE(NibbleValue('F', &value)); + EXPECT_EQ(15, value); +} + +TEST(BasicUtilTest, NibbleValueInvalid) { + uint8_t value; + + EXPECT_FALSE(NibbleValue('G', &value)); + EXPECT_FALSE(NibbleValue('H', &value)); + EXPECT_FALSE(NibbleValue('I', &value)); + EXPECT_FALSE(NibbleValue('x', &value)); + EXPECT_FALSE(NibbleValue('y', &value)); + EXPECT_FALSE(NibbleValue('z', &value)); +} + +TEST(BasicUtilTest, HexToBytes) { + std::string hex = "000102030405060708090A0B0C0D0E0F"; + uint8_t bytes[16]; + + EXPECT_TRUE(HexToBytes((uint8_t*)bytes, sizeof(bytes), hex)); + for (size_t i = 0; i < sizeof(bytes); i++) { + EXPECT_EQ(i, bytes[i]); + } +} + +TEST(BasicUtilTest, HexToBytes2) { + std::string hex = "101112131415161718191A1B1C1D1E1F"; + uint8_t bytes[16]; + + EXPECT_TRUE(HexToBytes((uint8_t*)bytes, sizeof(bytes), hex)); + for (size_t i = 0; i < sizeof(bytes); i++) { + EXPECT_EQ(16 + i, bytes[i]); + } +} + +TEST(BasicUtilTest, BytesToHex) { + const uint8_t bytes[16]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + + EXPECT_EQ("0102", BytesToHex((uint8_t*)bytes, 2)); + EXPECT_EQ("01020304", BytesToHex((uint8_t*)bytes, 4)); + EXPECT_EQ("0102030405060708", BytesToHex((uint8_t*)bytes, 8)); + EXPECT_EQ("0102030405060708090a0b0c0d0e0f10", BytesToHex((uint8_t*)bytes, 16)); + + EXPECT_EQ("01", BytesToHex((uint8_t*)bytes, 1)); + EXPECT_EQ("010203", BytesToHex((uint8_t*)bytes, 3)); + EXPECT_EQ("0102030405", BytesToHex((uint8_t*)bytes, 5)); +} + +TEST(BasicUtilTest, HexToBytesInValidOddLenHex) { + std::string hex = "12345"; + uint8_t bytes[16]; + + EXPECT_FALSE(HexToBytes((uint8_t*)bytes, sizeof(bytes), hex)); +} + +TEST(BasicUtilTest, HexToBytesInsufficientByteLen) { + std::string hex = "101112131415161718191A1B1C1D1E1F"; + uint8_t bytes[8]; + + EXPECT_FALSE(HexToBytes((uint8_t*)bytes, sizeof(bytes), hex)); +} + +TEST(BasicUtilTest, WaitForFile) { + // Gets system tmp dir. + base::FilePath tmp_dir; + ASSERT_TRUE(GetTempDir(&tmp_dir)); + + // Waits this path. + base::FilePath wait_path = tmp_dir.Append("libfs_avb-test-exist-dir"); + ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */)); + + EXPECT_TRUE(base::CreateDirectory(wait_path)); + EXPECT_TRUE(WaitForFile(wait_path.value(), 1s)); + + // Removes the wait_path. + ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */)); +} + +TEST(BasicUtilTest, WaitForFileNonExist) { + base::FilePath wait_path("/path/not/exist"); + EXPECT_FALSE(WaitForFile(wait_path.value(), 200ms)); +} + +TEST(BasicUtilTest, WaitForFileDeferCreation) { + // Gets system tmp dir. + base::FilePath tmp_dir; + ASSERT_TRUE(GetTempDir(&tmp_dir)); + + // Waits this path. + base::FilePath wait_path = tmp_dir.Append("libfs_avb-test-exist-dir"); + ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */)); + auto wait_file = std::async(WaitForFile, wait_path.value(), 500ms); + + // Sleeps 100ms before creating the wait_path. + std::this_thread::sleep_for(100ms); + EXPECT_TRUE(base::CreateDirectory(wait_path)); + + // Checks WaitForFile() returns success. + EXPECT_TRUE(wait_file.get()); + + // Removes the wait_path. + ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */)); +} + +TEST(BasicUtilTest, WaitForFileDeferCreationFailure) { + // Gets system tmp dir. + base::FilePath tmp_dir; + ASSERT_TRUE(GetTempDir(&tmp_dir)); + + // Waits this path. + base::FilePath wait_path = tmp_dir.Append("libfs_avb-test-exist-dir"); + ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */)); + auto wait_file = std::async(WaitForFile, wait_path.value(), 50ms); + + // Sleeps 100ms before creating the wait_path. + std::this_thread::sleep_for(100ms); + EXPECT_TRUE(base::CreateDirectory(wait_path)); + + // Checks WaitForFile() returns failure, because it only waits 50ms. + EXPECT_FALSE(wait_file.get()); + + // Removes the wait_path. + ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */)); +} + +} // namespace fs_avb_host_test diff --git a/fs_mgr/libfs_avb/util.cpp b/fs_mgr/libfs_avb/util.cpp new file mode 100644 index 000000000..17d47d9cd --- /dev/null +++ b/fs_mgr/libfs_avb/util.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util.h" + +#include +#include + +#include +#include + +namespace android { +namespace fs_mgr { + +bool NibbleValue(const char& c, uint8_t* value) { + CHECK(value != nullptr); + + switch (c) { + case '0' ... '9': + *value = c - '0'; + break; + case 'a' ... 'f': + *value = c - 'a' + 10; + break; + case 'A' ... 'F': + *value = c - 'A' + 10; + break; + default: + return false; + } + + return true; +} + +bool HexToBytes(uint8_t* bytes, size_t bytes_len, const std::string& hex) { + CHECK(bytes != nullptr); + + if (hex.size() % 2 != 0) { + return false; + } + if (hex.size() / 2 > bytes_len) { + return false; + } + for (size_t i = 0, j = 0, n = hex.size(); i < n; i += 2, ++j) { + uint8_t high; + if (!NibbleValue(hex[i], &high)) { + return false; + } + uint8_t low; + if (!NibbleValue(hex[i + 1], &low)) { + return false; + } + bytes[j] = (high << 4) | low; + } + return true; +} + +std::string BytesToHex(const uint8_t* bytes, size_t bytes_len) { + CHECK(bytes != nullptr); + + static const char* hex_digits = "0123456789abcdef"; + std::string hex; + + for (size_t i = 0; i < bytes_len; i++) { + hex.push_back(hex_digits[(bytes[i] & 0xF0) >> 4]); + hex.push_back(hex_digits[bytes[i] & 0x0F]); + } + return hex; +} + +bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout) { + auto start_time = std::chrono::steady_clock::now(); + + while (true) { + if (0 == access(filename.c_str(), F_OK) || errno != ENOENT) { + return true; + } + + std::this_thread::sleep_for(50ms); + + auto now = std::chrono::steady_clock::now(); + auto time_elapsed = std::chrono::duration_cast(now - start_time); + if (time_elapsed > relative_timeout) return false; + } +} + +bool IsDeviceUnlocked() { + std::string verified_boot_state; + + if (fs_mgr_get_boot_config("verifiedbootstate", &verified_boot_state)) { + return verified_boot_state == "orange"; + } + return false; +} + +bool SetBlockDeviceReadOnly(const std::string& blockdev) { + android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blockdev.c_str(), O_RDONLY | O_CLOEXEC))); + if (fd < 0) { + return false; + } + + int ON = 1; + return ioctl(fd, BLKROSET, &ON) == 0; +} + +} // namespace fs_mgr +} // namespace android diff --git a/fs_mgr/libfs_avb/util.h b/fs_mgr/libfs_avb/util.h new file mode 100644 index 000000000..cb861f466 --- /dev/null +++ b/fs_mgr/libfs_avb/util.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#ifdef HOST_TEST +#include +#else +#include +#endif + +#define FS_AVB_TAG "[libfs_avb]" + +// Logs a message to kernel +#define LINFO LOG(INFO) << FS_AVB_TAG +#define LWARNING LOG(WARNING) << FS_AVB_TAG +#define LERROR LOG(ERROR) << FS_AVB_TAG +#define LFATAL LOG(FATAL) << FS_AVB_TAG + +// Logs a message with strerror(errno) at the end +#define PINFO PLOG(INFO) << FS_AVB_TAG +#define PWARNING PLOG(WARNING) << FS_AVB_TAG +#define PERROR PLOG(ERROR) << FS_AVB_TAG +#define PFATAL PLOG(FATAL) << FS_AVB_TAG + +extern bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val); + +using namespace std::chrono_literals; + +namespace android { +namespace fs_mgr { + +bool NibbleValue(const char& c, uint8_t* value); + +bool HexToBytes(uint8_t* bytes, size_t bytes_len, const std::string& hex); + +std::string BytesToHex(const uint8_t* bytes, size_t bytes_len); + +bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout); + +bool IsDeviceUnlocked(); + +bool SetBlockDeviceReadOnly(const std::string& blockdev); + +} // namespace fs_mgr +} // namespace android