Loading Android.bp +24 −1 Original line number Diff line number Diff line Loading @@ -151,6 +151,7 @@ cc_defaults { static_libs: [ "librecovery_fastboot", "libminui", "libpackage", "libverifier", "libotautil", Loading @@ -175,7 +176,6 @@ cc_library_static { "fsck_unshare_blocks.cpp", "fuse_sdcard_provider.cpp", "install.cpp", "package.cpp", "recovery.cpp", "roots.cpp", ], Loading Loading @@ -210,6 +210,29 @@ cc_library_static { ], } cc_library_static { name: "libpackage", recovery_available: true, defaults: [ "recovery_defaults", ], srcs: [ "package.cpp", ], shared_libs: [ "libbase", "libcrypto", "libziparchive", ], static_libs: [ "libotautil", ], } cc_binary { name: "recovery", recovery: true, Loading package.cpp +111 −3 Original line number Diff line number Diff line Loading @@ -17,10 +17,12 @@ #include "package.h" #include <string.h> #include <unistd.h> #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/stringprintf.h> #include <openssl/sha.h> #include <android-base/unique_fd.h> #include "otautil/error_code.h" #include "otautil/sysutil.h" Loading Loading @@ -67,14 +69,38 @@ class MemoryPackage : public Package { ZipArchiveHandle zip_handle_; }; // TODO(xunchang) Implement the PackageFromFd. void Package::SetProgress(float progress) { if (set_progress_) { set_progress_(progress); } } class FilePackage : public Package { public: FilePackage(android::base::unique_fd&& fd, uint64_t file_size, const std::string& path, const std::function<void(float)>& set_progress); ~FilePackage() override; uint64_t GetPackageSize() const override { return package_size_; } bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) override; ZipArchiveHandle GetZipArchiveHandle() override; bool UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers, uint64_t start, uint64_t length) override; private: android::base::unique_fd fd_; // The underlying fd to the open package. uint64_t package_size_; std::string path_; // The physical path to the package. ZipArchiveHandle zip_handle_; }; std::unique_ptr<Package> Package::CreateMemoryPackage( const std::string& path, const std::function<void(float)>& set_progress) { std::unique_ptr<MemMapping> mmap = std::make_unique<MemMapping>(); Loading @@ -86,6 +112,23 @@ std::unique_ptr<Package> Package::CreateMemoryPackage( return std::make_unique<MemoryPackage>(path, std::move(mmap), set_progress); } std::unique_ptr<Package> Package::CreateFilePackage( const std::string& path, const std::function<void(float)>& set_progress) { android::base::unique_fd fd(open(path.c_str(), O_RDONLY)); if (fd == -1) { PLOG(ERROR) << "Failed to open " << path; return nullptr; } off64_t file_size = lseek64(fd.get(), 0, SEEK_END); if (file_size == -1) { PLOG(ERROR) << "Failed to get the package size"; return nullptr; } return std::make_unique<FilePackage>(std::move(fd), file_size, path, set_progress); } std::unique_ptr<Package> Package::CreateMemoryPackage( std::vector<uint8_t> content, const std::function<void(float)>& set_progress) { return std::make_unique<MemoryPackage>(std::move(content), set_progress); Loading Loading @@ -152,3 +195,68 @@ ZipArchiveHandle MemoryPackage::GetZipArchiveHandle() { return zip_handle_; } FilePackage::FilePackage(android::base::unique_fd&& fd, uint64_t file_size, const std::string& path, const std::function<void(float)>& set_progress) : fd_(std::move(fd)), package_size_(file_size), path_(path), zip_handle_(nullptr) { set_progress_ = set_progress; } FilePackage::~FilePackage() { if (zip_handle_) { CloseArchive(zip_handle_); } } bool FilePackage::ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) { if (byte_count > package_size_ || offset > package_size_ - byte_count) { LOG(ERROR) << "Out of bound read, offset: " << offset << ", size: " << byte_count << ", total package_size: " << package_size_; return false; } if (!android::base::ReadFullyAtOffset(fd_.get(), buffer, byte_count, offset)) { PLOG(ERROR) << "Failed to read " << byte_count << " bytes data at offset " << offset; return false; } return true; } bool FilePackage::UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers, uint64_t start, uint64_t length) { if (length > package_size_ || start > package_size_ - length) { LOG(ERROR) << "Out of bound read, offset: " << start << ", size: " << length << ", total package_size: " << package_size_; return false; } uint64_t so_far = 0; while (so_far < length) { uint64_t read_size = std::min<uint64_t>(length - so_far, 16 * MiB); std::vector<uint8_t> buffer(read_size); if (!ReadFullyAtOffset(buffer.data(), read_size, start + so_far)) { return false; } for (const auto& hasher : hashers) { hasher(buffer.data(), read_size); } so_far += read_size; } return true; } ZipArchiveHandle FilePackage::GetZipArchiveHandle() { if (zip_handle_) { return zip_handle_; } if (auto err = OpenArchiveFd(fd_.get(), path_.c_str(), &zip_handle_); err != 0) { LOG(ERROR) << "Can't open package" << path_ << " : " << ErrorCodeString(err); return nullptr; } return zip_handle_; } package.h +7 −6 Original line number Diff line number Diff line Loading @@ -32,6 +32,13 @@ // interface for both packages loaded in memory and packages read from fd. class Package : public VerifierInterface { public: static std::unique_ptr<Package> CreateMemoryPackage( const std::string& path, const std::function<void(float)>& set_progress); static std::unique_ptr<Package> CreateMemoryPackage( std::vector<uint8_t> content, const std::function<void(float)>& set_progress); static std::unique_ptr<Package> CreateFilePackage(const std::string& path, const std::function<void(float)>& set_progress); virtual ~Package() = default; // Opens the package as a zip file and returns the ZipArchiveHandle. Loading @@ -40,12 +47,6 @@ class Package : public VerifierInterface { // Updates the progress in fraction during package verification. void SetProgress(float progress) override; static std::unique_ptr<Package> CreateMemoryPackage( const std::string& path, const std::function<void(float)>& set_progress); static std::unique_ptr<Package> CreateMemoryPackage( std::vector<uint8_t> content, const std::function<void(float)>& set_progress); protected: // An optional function to update the progress. std::function<void(float)> set_progress_; Loading tests/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ librecovery_static_libs = [ "librecovery", "librecovery_fastboot", "libminui", "libpackage", "libverifier", "libotautil", Loading Loading @@ -117,6 +118,7 @@ cc_test { static_libs: libapplypatch_static_libs + [ "librecovery_ui", "libminui", "libpackage", "libverifier", "libotautil", "libupdater", Loading tests/component/verifier_test.cpp +10 −5 Original line number Diff line number Diff line Loading @@ -240,8 +240,10 @@ class VerifierTest : public testing::TestWithParam<std::vector<std::string>> { void SetUp() override { std::vector<std::string> args = GetParam(); std::string path = from_testdata_base(args[0]); package_ = Package::CreateMemoryPackage(path, nullptr); ASSERT_NE(nullptr, package_); memory_package_ = Package::CreateMemoryPackage(path, nullptr); ASSERT_NE(nullptr, memory_package_); file_package_ = Package::CreateFilePackage(path, nullptr); ASSERT_NE(nullptr, file_package_); for (auto it = ++args.cbegin(); it != args.cend(); ++it) { std::string public_key_file = from_testdata_base("testkey_" + *it + ".x509.pem"); Loading @@ -250,7 +252,8 @@ class VerifierTest : public testing::TestWithParam<std::vector<std::string>> { } } std::unique_ptr<Package> package_; std::unique_ptr<Package> memory_package_; std::unique_ptr<Package> file_package_; std::vector<Certificate> certs_; }; Loading Loading @@ -304,11 +307,13 @@ TEST(VerifierTest, BadPackage_SignatureStartOutOfBounds) { } TEST_P(VerifierSuccessTest, VerifySucceed) { ASSERT_EQ(VERIFY_SUCCESS, verify_file(package_.get(), certs_)); ASSERT_EQ(VERIFY_SUCCESS, verify_file(memory_package_.get(), certs_)); ASSERT_EQ(VERIFY_SUCCESS, verify_file(file_package_.get(), certs_)); } TEST_P(VerifierFailureTest, VerifyFailure) { ASSERT_EQ(VERIFY_FAILURE, verify_file(package_.get(), certs_)); ASSERT_EQ(VERIFY_FAILURE, verify_file(memory_package_.get(), certs_)); ASSERT_EQ(VERIFY_FAILURE, verify_file(file_package_.get(), certs_)); } INSTANTIATE_TEST_CASE_P(SingleKeySuccess, VerifierSuccessTest, Loading Loading
Android.bp +24 −1 Original line number Diff line number Diff line Loading @@ -151,6 +151,7 @@ cc_defaults { static_libs: [ "librecovery_fastboot", "libminui", "libpackage", "libverifier", "libotautil", Loading @@ -175,7 +176,6 @@ cc_library_static { "fsck_unshare_blocks.cpp", "fuse_sdcard_provider.cpp", "install.cpp", "package.cpp", "recovery.cpp", "roots.cpp", ], Loading Loading @@ -210,6 +210,29 @@ cc_library_static { ], } cc_library_static { name: "libpackage", recovery_available: true, defaults: [ "recovery_defaults", ], srcs: [ "package.cpp", ], shared_libs: [ "libbase", "libcrypto", "libziparchive", ], static_libs: [ "libotautil", ], } cc_binary { name: "recovery", recovery: true, Loading
package.cpp +111 −3 Original line number Diff line number Diff line Loading @@ -17,10 +17,12 @@ #include "package.h" #include <string.h> #include <unistd.h> #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/stringprintf.h> #include <openssl/sha.h> #include <android-base/unique_fd.h> #include "otautil/error_code.h" #include "otautil/sysutil.h" Loading Loading @@ -67,14 +69,38 @@ class MemoryPackage : public Package { ZipArchiveHandle zip_handle_; }; // TODO(xunchang) Implement the PackageFromFd. void Package::SetProgress(float progress) { if (set_progress_) { set_progress_(progress); } } class FilePackage : public Package { public: FilePackage(android::base::unique_fd&& fd, uint64_t file_size, const std::string& path, const std::function<void(float)>& set_progress); ~FilePackage() override; uint64_t GetPackageSize() const override { return package_size_; } bool ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) override; ZipArchiveHandle GetZipArchiveHandle() override; bool UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers, uint64_t start, uint64_t length) override; private: android::base::unique_fd fd_; // The underlying fd to the open package. uint64_t package_size_; std::string path_; // The physical path to the package. ZipArchiveHandle zip_handle_; }; std::unique_ptr<Package> Package::CreateMemoryPackage( const std::string& path, const std::function<void(float)>& set_progress) { std::unique_ptr<MemMapping> mmap = std::make_unique<MemMapping>(); Loading @@ -86,6 +112,23 @@ std::unique_ptr<Package> Package::CreateMemoryPackage( return std::make_unique<MemoryPackage>(path, std::move(mmap), set_progress); } std::unique_ptr<Package> Package::CreateFilePackage( const std::string& path, const std::function<void(float)>& set_progress) { android::base::unique_fd fd(open(path.c_str(), O_RDONLY)); if (fd == -1) { PLOG(ERROR) << "Failed to open " << path; return nullptr; } off64_t file_size = lseek64(fd.get(), 0, SEEK_END); if (file_size == -1) { PLOG(ERROR) << "Failed to get the package size"; return nullptr; } return std::make_unique<FilePackage>(std::move(fd), file_size, path, set_progress); } std::unique_ptr<Package> Package::CreateMemoryPackage( std::vector<uint8_t> content, const std::function<void(float)>& set_progress) { return std::make_unique<MemoryPackage>(std::move(content), set_progress); Loading Loading @@ -152,3 +195,68 @@ ZipArchiveHandle MemoryPackage::GetZipArchiveHandle() { return zip_handle_; } FilePackage::FilePackage(android::base::unique_fd&& fd, uint64_t file_size, const std::string& path, const std::function<void(float)>& set_progress) : fd_(std::move(fd)), package_size_(file_size), path_(path), zip_handle_(nullptr) { set_progress_ = set_progress; } FilePackage::~FilePackage() { if (zip_handle_) { CloseArchive(zip_handle_); } } bool FilePackage::ReadFullyAtOffset(uint8_t* buffer, uint64_t byte_count, uint64_t offset) { if (byte_count > package_size_ || offset > package_size_ - byte_count) { LOG(ERROR) << "Out of bound read, offset: " << offset << ", size: " << byte_count << ", total package_size: " << package_size_; return false; } if (!android::base::ReadFullyAtOffset(fd_.get(), buffer, byte_count, offset)) { PLOG(ERROR) << "Failed to read " << byte_count << " bytes data at offset " << offset; return false; } return true; } bool FilePackage::UpdateHashAtOffset(const std::vector<HasherUpdateCallback>& hashers, uint64_t start, uint64_t length) { if (length > package_size_ || start > package_size_ - length) { LOG(ERROR) << "Out of bound read, offset: " << start << ", size: " << length << ", total package_size: " << package_size_; return false; } uint64_t so_far = 0; while (so_far < length) { uint64_t read_size = std::min<uint64_t>(length - so_far, 16 * MiB); std::vector<uint8_t> buffer(read_size); if (!ReadFullyAtOffset(buffer.data(), read_size, start + so_far)) { return false; } for (const auto& hasher : hashers) { hasher(buffer.data(), read_size); } so_far += read_size; } return true; } ZipArchiveHandle FilePackage::GetZipArchiveHandle() { if (zip_handle_) { return zip_handle_; } if (auto err = OpenArchiveFd(fd_.get(), path_.c_str(), &zip_handle_); err != 0) { LOG(ERROR) << "Can't open package" << path_ << " : " << ErrorCodeString(err); return nullptr; } return zip_handle_; }
package.h +7 −6 Original line number Diff line number Diff line Loading @@ -32,6 +32,13 @@ // interface for both packages loaded in memory and packages read from fd. class Package : public VerifierInterface { public: static std::unique_ptr<Package> CreateMemoryPackage( const std::string& path, const std::function<void(float)>& set_progress); static std::unique_ptr<Package> CreateMemoryPackage( std::vector<uint8_t> content, const std::function<void(float)>& set_progress); static std::unique_ptr<Package> CreateFilePackage(const std::string& path, const std::function<void(float)>& set_progress); virtual ~Package() = default; // Opens the package as a zip file and returns the ZipArchiveHandle. Loading @@ -40,12 +47,6 @@ class Package : public VerifierInterface { // Updates the progress in fraction during package verification. void SetProgress(float progress) override; static std::unique_ptr<Package> CreateMemoryPackage( const std::string& path, const std::function<void(float)>& set_progress); static std::unique_ptr<Package> CreateMemoryPackage( std::vector<uint8_t> content, const std::function<void(float)>& set_progress); protected: // An optional function to update the progress. std::function<void(float)> set_progress_; Loading
tests/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ librecovery_static_libs = [ "librecovery", "librecovery_fastboot", "libminui", "libpackage", "libverifier", "libotautil", Loading Loading @@ -117,6 +118,7 @@ cc_test { static_libs: libapplypatch_static_libs + [ "librecovery_ui", "libminui", "libpackage", "libverifier", "libotautil", "libupdater", Loading
tests/component/verifier_test.cpp +10 −5 Original line number Diff line number Diff line Loading @@ -240,8 +240,10 @@ class VerifierTest : public testing::TestWithParam<std::vector<std::string>> { void SetUp() override { std::vector<std::string> args = GetParam(); std::string path = from_testdata_base(args[0]); package_ = Package::CreateMemoryPackage(path, nullptr); ASSERT_NE(nullptr, package_); memory_package_ = Package::CreateMemoryPackage(path, nullptr); ASSERT_NE(nullptr, memory_package_); file_package_ = Package::CreateFilePackage(path, nullptr); ASSERT_NE(nullptr, file_package_); for (auto it = ++args.cbegin(); it != args.cend(); ++it) { std::string public_key_file = from_testdata_base("testkey_" + *it + ".x509.pem"); Loading @@ -250,7 +252,8 @@ class VerifierTest : public testing::TestWithParam<std::vector<std::string>> { } } std::unique_ptr<Package> package_; std::unique_ptr<Package> memory_package_; std::unique_ptr<Package> file_package_; std::vector<Certificate> certs_; }; Loading Loading @@ -304,11 +307,13 @@ TEST(VerifierTest, BadPackage_SignatureStartOutOfBounds) { } TEST_P(VerifierSuccessTest, VerifySucceed) { ASSERT_EQ(VERIFY_SUCCESS, verify_file(package_.get(), certs_)); ASSERT_EQ(VERIFY_SUCCESS, verify_file(memory_package_.get(), certs_)); ASSERT_EQ(VERIFY_SUCCESS, verify_file(file_package_.get(), certs_)); } TEST_P(VerifierFailureTest, VerifyFailure) { ASSERT_EQ(VERIFY_FAILURE, verify_file(package_.get(), certs_)); ASSERT_EQ(VERIFY_FAILURE, verify_file(memory_package_.get(), certs_)); ASSERT_EQ(VERIFY_FAILURE, verify_file(file_package_.get(), certs_)); } INSTANTIATE_TEST_CASE_P(SingleKeySuccess, VerifierSuccessTest, Loading