diff options
author | Tianjie Xu <xunchang@google.com> | 2020-03-27 21:29:28 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-03-27 21:29:28 +0000 |
commit | 6cbb5c48083f47197d1c93f337e860a23a40bbee (patch) | |
tree | be2a73f1c04f9037a0bd4b815ab60ab0a28f4603 | |
parent | 25d06ee10e155cf60dcec64582ff24478f2a5f25 (diff) | |
parent | 9b57bd48463fe3cf500d6a61ad77ef09fc9498ba (diff) | |
download | extras-6cbb5c48083f47197d1c93f337e860a23a40bbee.tar.gz |
Merge changes from topic "fec_avb" into rvc-dev am: f76271cb2d am: 9b57bd4846
Change-Id: I61ee77e27140a619d5a7b77c58665b0f8998a944
-rw-r--r-- | libfec/Android.bp | 47 | ||||
-rw-r--r-- | libfec/avb_utils.cpp | 160 | ||||
-rw-r--r-- | libfec/avb_utils.h | 30 | ||||
-rw-r--r-- | libfec/avb_utils_stub.cpp | 27 | ||||
-rw-r--r-- | libfec/fec_open.cpp | 144 | ||||
-rw-r--r-- | verity/fec/Android.bp | 6 |
6 files changed, 265 insertions, 149 deletions
diff --git a/libfec/Android.bp b/libfec/Android.bp index b355dfec..3da6fe7c 100644 --- a/libfec/Android.bp +++ b/libfec/Android.bp @@ -1,16 +1,22 @@ // Copyright 2015 The Android Open Source Project -cc_library { - name: "libfec", - host_supported: true, - recovery_available: true, +cc_defaults { + name: "libfec_default", + + cflags: [ + "-Wall", + "-Werror", + "-O3", + "-D_LARGEFILE64_SOURCE", + ], + srcs: [ "fec_open.cpp", "fec_read.cpp", "fec_verity.cpp", "fec_process.cpp", ], - cflags: ["-Wall", "-Werror", "-O3", "-D_LARGEFILE64_SOURCE"], + export_include_dirs: ["include"], // Exported header include/fec/io.h includes crypto_utils headers. export_shared_lib_headers: ["libcrypto_utils"], @@ -25,13 +31,15 @@ cc_library { ], static_libs: [ - "libavb", "libfec_rs", ], target: { host: { - cflags: ["-D_GNU_SOURCE", "-DFEC_NO_KLOG"] + cflags: [ + "-D_GNU_SOURCE", + "-DFEC_NO_KLOG", + ], }, linux_glibc: { sanitize: { @@ -40,3 +48,28 @@ cc_library { }, }, } + +cc_library { + name: "libfec", + defaults: ["libfec_default"], + host_supported: true, + recovery_available: true, + + target: { + linux: { + srcs: [ + "avb_utils.cpp", + ], + static_libs: [ + "libavb", + ], + }, + + // libavb isn't available on mac. + darwin: { + srcs: [ + "avb_utils_stub.cpp", + ], + }, + }, +} diff --git a/libfec/avb_utils.cpp b/libfec/avb_utils.cpp new file mode 100644 index 00000000..8913f2a1 --- /dev/null +++ b/libfec/avb_utils.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2020 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_utils.h" + +#include <android-base/strings.h> +#include <libavb/libavb.h> + +#include "fec_private.h" + +int parse_vbmeta_from_footer(fec_handle *f, std::vector<uint8_t> *vbmeta) { + if (f->size <= AVB_FOOTER_SIZE) { + debug("file size not large enough to be avb images:" PRIu64, f->size); + return -1; + } + + AvbFooter footer_read; + if (!raw_pread(f->fd, &footer_read, AVB_FOOTER_SIZE, + f->size - AVB_FOOTER_SIZE)) { + error("failed to read footer: %s", strerror(errno)); + return -1; + } + + AvbFooter footer; + if (!avb_footer_validate_and_byteswap(&footer_read, &footer)) { + debug("invalid avb footer"); + return -1; + } + uint64_t vbmeta_offset = footer.vbmeta_offset; + uint64_t vbmeta_size = footer.vbmeta_size; + check(vbmeta_offset <= f->size - sizeof(footer) - vbmeta_size); + + std::vector<uint8_t> vbmeta_data(vbmeta_size, 0); + // TODO(xunchang) handle the sparse image with libsparse. + if (!raw_pread(f->fd, vbmeta_data.data(), vbmeta_data.size(), + vbmeta_offset)) { + error("failed to read avb vbmeta: %s", strerror(errno)); + return -1; + } + + if (auto status = avb_vbmeta_image_verify( + vbmeta_data.data(), vbmeta_data.size(), nullptr, nullptr); + status != AVB_VBMETA_VERIFY_RESULT_OK && + status != AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED) { + error("failed to verify avb vbmeta, status: %d", status); + return -1; + } + *vbmeta = std::move(vbmeta_data); + return 0; +} + +int parse_avb_image(fec_handle *f, const std::vector<uint8_t> &vbmeta) { + // TODO(xunchang) check if avb verification or hashtree is disabled. + + // Look for the hashtree descriptor, we expect exactly one descriptor in + // vbmeta. + // TODO(xunchang) handle the image with AvbHashDescriptor. + auto parse_descriptor = [](const AvbDescriptor *descriptor, + void *user_data) { + if (descriptor && + avb_be64toh(descriptor->tag) == AVB_DESCRIPTOR_TAG_HASHTREE) { + auto desp = static_cast<const AvbDescriptor **>(user_data); + *desp = descriptor; + return false; + } + return true; + }; + + const AvbHashtreeDescriptor *hashtree_descriptor_ptr = nullptr; + avb_descriptor_foreach(vbmeta.data(), vbmeta.size(), parse_descriptor, + &hashtree_descriptor_ptr); + + AvbHashtreeDescriptor hashtree_descriptor; + if (!avb_hashtree_descriptor_validate_and_byteswap(hashtree_descriptor_ptr, + &hashtree_descriptor)) { + error("failed to verify avb hashtree descriptor"); + return -1; + } + + // The partition name, salt, root append right after the hashtree + // descriptor. + auto read_ptr = reinterpret_cast<const uint8_t *>(hashtree_descriptor_ptr); + // Calculate the offset with respect to the vbmeta; and check both the + // salt & root are within the range. + uint32_t salt_offset = + sizeof(AvbHashtreeDescriptor) + hashtree_descriptor.partition_name_len; + uint32_t root_offset = salt_offset + hashtree_descriptor.salt_len; + check(hashtree_descriptor.salt_len < vbmeta.size()); + check(salt_offset < vbmeta.size() - hashtree_descriptor.salt_len); + check(hashtree_descriptor.root_digest_len < vbmeta.size()); + check(root_offset < vbmeta.size() - hashtree_descriptor.root_digest_len); + std::vector<uint8_t> salt( + read_ptr + salt_offset, + read_ptr + salt_offset + hashtree_descriptor.salt_len); + std::vector<uint8_t> root_hash( + read_ptr + root_offset, + read_ptr + root_offset + hashtree_descriptor.root_digest_len); + + // Expect the AVB image has the format: + // 1. hashtree + // 2. ecc data + // 3. vbmeta + // 4. avb footer + check(hashtree_descriptor.fec_offset == + hashtree_descriptor.tree_offset + hashtree_descriptor.tree_size); + check(hashtree_descriptor.fec_offset <= + f->size - hashtree_descriptor.fec_size); + + f->data_size = hashtree_descriptor.fec_offset; + + f->ecc.blocks = fec_div_round_up(f->data_size, FEC_BLOCKSIZE); + f->ecc.rounds = fec_div_round_up(f->ecc.blocks, f->ecc.rsn); + f->ecc.size = hashtree_descriptor.fec_size; + f->ecc.start = hashtree_descriptor.fec_offset; + // TODO(xunchang) verify the integrity of the ecc data. + f->ecc.valid = true; + + std::string hash_algorithm = + reinterpret_cast<char *>(hashtree_descriptor.hash_algorithm); + int nid = -1; + if (android::base::EqualsIgnoreCase(hash_algorithm, "sha1")) { + nid = NID_sha1; + } else if (android::base::EqualsIgnoreCase(hash_algorithm, "sha256")) { + nid = NID_sha256; + } else { + error("unsupported hash algorithm %s", hash_algorithm.c_str()); + } + + hashtree_info hashtree; + hashtree.initialize(hashtree_descriptor.tree_offset, + hashtree_descriptor.tree_offset / FEC_BLOCKSIZE, salt, + nid); + if (hashtree.verify_tree(f, root_hash.data()) != 0) { + error("failed to verify hashtree"); + return -1; + } + + // We have validate the hashtree, + f->data_size = hashtree.hash_start; + f->avb = { + .valid = true, + .vbmeta = vbmeta, + .hashtree = std::move(hashtree), + }; + + return 0; +} diff --git a/libfec/avb_utils.h b/libfec/avb_utils.h new file mode 100644 index 00000000..78254508 --- /dev/null +++ b/libfec/avb_utils.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 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 <stdint.h> +#include <vector> + +struct fec_handle; + +// Checks if there is a valid AVB footer in the end of the image. If so, parses +// the contents of vbmeta struct from the given AVB footer. Returns 0 on +// success. +int parse_vbmeta_from_footer(fec_handle *f, std::vector<uint8_t> *vbmeta); + +// Parses the AVB vbmeta for the information of hashtree and fec data. +int parse_avb_image(fec_handle *f, const std::vector<uint8_t> &vbmeta); diff --git a/libfec/avb_utils_stub.cpp b/libfec/avb_utils_stub.cpp new file mode 100644 index 00000000..0b6061e5 --- /dev/null +++ b/libfec/avb_utils_stub.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020 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_utils.h" + +int parse_vbmeta_from_footer(fec_handle* /* f */, + std::vector<uint8_t> * /* vbmeta */) { + return -1; +} + +int parse_avb_image(fec_handle* /* f */, + const std::vector<uint8_t>& /* vbmeta */) { + return -1; +} diff --git a/libfec/fec_open.cpp b/libfec/fec_open.cpp index 8f3fa22d..fe458097 100644 --- a/libfec/fec_open.cpp +++ b/libfec/fec_open.cpp @@ -18,9 +18,7 @@ #include <sys/ioctl.h> #include <sys/stat.h> -#include <android-base/strings.h> #include <ext4_utils/ext4_sb.h> -#include <libavb/libavb.h> #include <squashfs_utils.h> #if defined(__linux__) @@ -31,6 +29,7 @@ #define fdatasync(fd) fcntl((fd), F_FULLFSYNC) #endif +#include "avb_utils.h" #include "fec_private.h" /* used by `find_offset'; returns metadata size for a file size `size' and @@ -495,145 +494,6 @@ int fec_get_status(struct fec_handle *f, struct fec_status *s) return 0; } -static int parse_vbmeta_from_footer(fec_handle *f, - std::vector<uint8_t> *vbmeta) { - if (f->size <= AVB_FOOTER_SIZE) { - debug("file size not large enough to be avb images:" PRIu64, f->size); - return -1; - } - - AvbFooter footer_read; - if (!raw_pread(f->fd, &footer_read, AVB_FOOTER_SIZE, - f->size - AVB_FOOTER_SIZE)) { - error("failed to read footer: %s", strerror(errno)); - return -1; - } - - AvbFooter footer; - if (!avb_footer_validate_and_byteswap(&footer_read, &footer)) { - debug("invalid avb footer"); - return -1; - } - uint64_t vbmeta_offset = footer.vbmeta_offset; - uint64_t vbmeta_size = footer.vbmeta_size; - check(vbmeta_offset <= f->size - sizeof(footer) - vbmeta_size); - - std::vector<uint8_t> vbmeta_data(vbmeta_size, 0); - // TODO(xunchang) handle the sparse image with libsparse. - if (!raw_pread(f->fd, vbmeta_data.data(), vbmeta_data.size(), - vbmeta_offset)) { - error("failed to read avb vbmeta: %s", strerror(errno)); - return -1; - } - - if (auto status = avb_vbmeta_image_verify( - vbmeta_data.data(), vbmeta_data.size(), nullptr, nullptr); - status != AVB_VBMETA_VERIFY_RESULT_OK && - status != AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED) { - error("failed to verify avb vbmeta, status: %d", status); - return -1; - } - *vbmeta = std::move(vbmeta_data); - return 0; -} - -static int parse_avb_image(fec_handle *f, const std::vector<uint8_t> &vbmeta) { - // TODO(xunchang) check if avb verification or hashtree is disabled. - - // Look for the hashtree descriptor, we expect exactly one descriptor in - // vbmeta. - // TODO(xunchang) handle the image with AvbHashDescriptor. - auto parse_descriptor = [](const AvbDescriptor *descriptor, - void *user_data) { - if (descriptor && - avb_be64toh(descriptor->tag) == AVB_DESCRIPTOR_TAG_HASHTREE) { - auto desp = static_cast<const AvbDescriptor **>(user_data); - *desp = descriptor; - return false; - } - return true; - }; - - const AvbHashtreeDescriptor *hashtree_descriptor_ptr = nullptr; - avb_descriptor_foreach(vbmeta.data(), vbmeta.size(), parse_descriptor, - &hashtree_descriptor_ptr); - - AvbHashtreeDescriptor hashtree_descriptor; - if (!avb_hashtree_descriptor_validate_and_byteswap(hashtree_descriptor_ptr, - &hashtree_descriptor)) { - error("failed to verify avb hashtree descriptor"); - return -1; - } - - // The partition name, salt, root append right after the hashtree - // descriptor. - auto read_ptr = reinterpret_cast<const uint8_t *>(hashtree_descriptor_ptr); - // Calculate the offset with respect to the vbmeta; and check both the - // salt & root are within the range. - uint32_t salt_offset = - sizeof(AvbHashtreeDescriptor) + hashtree_descriptor.partition_name_len; - uint32_t root_offset = salt_offset + hashtree_descriptor.salt_len; - check(hashtree_descriptor.salt_len < vbmeta.size()); - check(salt_offset < vbmeta.size() - hashtree_descriptor.salt_len); - check(hashtree_descriptor.root_digest_len < vbmeta.size()); - check(root_offset < vbmeta.size() - hashtree_descriptor.root_digest_len); - std::vector<uint8_t> salt( - read_ptr + salt_offset, - read_ptr + salt_offset + hashtree_descriptor.salt_len); - std::vector<uint8_t> root_hash( - read_ptr + root_offset, - read_ptr + root_offset + hashtree_descriptor.root_digest_len); - - // Expect the AVB image has the format: - // 1. hashtree - // 2. ecc data - // 3. vbmeta - // 4. avb footer - check(hashtree_descriptor.fec_offset == - hashtree_descriptor.tree_offset + hashtree_descriptor.tree_size); - check(hashtree_descriptor.fec_offset <= - f->size - hashtree_descriptor.fec_size); - - f->data_size = hashtree_descriptor.fec_offset; - - f->ecc.blocks = fec_div_round_up(f->data_size, FEC_BLOCKSIZE); - f->ecc.rounds = fec_div_round_up(f->ecc.blocks, f->ecc.rsn); - f->ecc.size = hashtree_descriptor.fec_size; - f->ecc.start = hashtree_descriptor.fec_offset; - // TODO(xunchang) verify the integrity of the ecc data. - f->ecc.valid = true; - - std::string hash_algorithm = - reinterpret_cast<char *>(hashtree_descriptor.hash_algorithm); - int nid = -1; - if (android::base::EqualsIgnoreCase(hash_algorithm, "sha1")) { - nid = NID_sha1; - } else if (android::base::EqualsIgnoreCase(hash_algorithm, "sha256")) { - nid = NID_sha256; - } else { - error("unsupported hash algorithm %s", hash_algorithm.c_str()); - } - - hashtree_info hashtree; - hashtree.initialize(hashtree_descriptor.tree_offset, - hashtree_descriptor.tree_offset / FEC_BLOCKSIZE, salt, - nid); - if (hashtree.verify_tree(f, root_hash.data()) != 0) { - error("failed to verify hashtree"); - return -1; - } - - // We have validate the hashtree, - f->data_size = hashtree.hash_start; - f->avb = { - .valid = true, - .vbmeta = vbmeta, - .hashtree = std::move(hashtree), - }; - - return 0; -} - /* opens `path' using given options and returns a fec_handle in `handle' if successful */ int fec_open(struct fec_handle **handle, const char *path, int mode, int flags, @@ -687,6 +547,8 @@ int fec_open(struct fec_handle **handle, const char *path, int mode, int flags, f->data_size = f->size; /* until ecc and/or verity are loaded */ + // Don't parse the avb image if FEC_NO_AVB is set. It's used when libavb is + // not supported on mac. std::vector<uint8_t> vbmeta; if (parse_vbmeta_from_footer(f.get(), &vbmeta) == 0) { if (parse_avb_image(f.get(), vbmeta) != 0) { diff --git a/verity/fec/Android.bp b/verity/fec/Android.bp index ac02f331..4bcecb09 100644 --- a/verity/fec/Android.bp +++ b/verity/fec/Android.bp @@ -7,6 +7,11 @@ cc_binary_host { misc_undefined: ["integer"], }, }, + linux: { + static_libs: [ + "libavb", + ], + }, }, srcs: [ @@ -22,7 +27,6 @@ cc_binary_host { "libcrypto", "libfec", "libfec_rs", - "libavb", "libext4_utils", "liblog", "libsquashfs_utils", |