diff options
-rw-r--r-- | Android.bp | 2 | ||||
-rw-r--r-- | install/include/install/install.h | 4 | ||||
-rw-r--r-- | install/install.cpp | 47 | ||||
-rw-r--r-- | recovery.cpp | 6 | ||||
-rw-r--r-- | tests/Android.bp | 1 | ||||
-rw-r--r-- | tests/unit/install_test.cpp | 28 |
6 files changed, 87 insertions, 1 deletions
diff --git a/Android.bp b/Android.bp index 3a8e97883..bda36c2f5 100644 --- a/Android.bp +++ b/Android.bp @@ -72,6 +72,7 @@ cc_defaults { ], static_libs: [ + "libc++fs", "libinstall", "librecovery_fastboot", "libminui", @@ -95,6 +96,7 @@ cc_library_static { ], shared_libs: [ + "libfusesideload", "librecovery_ui", ], } diff --git a/install/include/install/install.h b/install/include/install/install.h index 87d43ab09..bef23e9ca 100644 --- a/install/include/install/install.h +++ b/install/include/install/install.h @@ -63,3 +63,7 @@ bool ReadMetadataFromPackage(ZipArchiveHandle zip, std::map<std::string, std::st // pre-device and serial number (if presents). A/B OTA specific checks: pre-build version, // fingerprint, timestamp. bool CheckPackageMetadata(const std::map<std::string, std::string>& metadata, OtaType ota_type); + +// Ensures the path to the update package is mounted. Also set the |should_use_fuse| to true if the +// package stays on a removable media. +bool SetupPackageMount(const std::string& package_path, bool* should_use_fuse); diff --git a/install/install.cpp b/install/install.cpp index 4bb0903cc..1c9bf2fd2 100644 --- a/install/install.cpp +++ b/install/install.cpp @@ -30,6 +30,7 @@ #include <atomic> #include <chrono> #include <condition_variable> +#include <filesystem> #include <functional> #include <limits> #include <mutex> @@ -641,3 +642,49 @@ bool verify_package(Package* package, RecoveryUI* ui) { } return true; } + +bool SetupPackageMount(const std::string& package_path, bool* should_use_fuse) { + CHECK(should_use_fuse != nullptr); + + if (package_path.empty()) { + return false; + } + + *should_use_fuse = true; + if (package_path[0] == '@') { + auto block_map_path = package_path.substr(1); + if (ensure_path_mounted(block_map_path) != 0) { + LOG(ERROR) << "Failed to mount " << block_map_path; + return false; + } + // uncrypt only produces block map only if the package stays on /data. + *should_use_fuse = false; + return true; + } + + // Package is not a block map file. + if (ensure_path_mounted(package_path) != 0) { + LOG(ERROR) << "Failed to mount " << package_path; + return false; + } + + // Reject the package if the input path doesn't equal the canonicalized path. + // e.g. /cache/../sdcard/update_package. + std::error_code ec; + auto canonical_path = std::filesystem::canonical(package_path, ec); + if (ec) { + LOG(ERROR) << "Failed to get canonical of " << package_path << ", " << ec.message(); + return false; + } + if (canonical_path.string() != package_path) { + LOG(ERROR) << "Installation aborts. The canonical path " << canonical_path.string() + << " doesn't equal the original path " << package_path; + return false; + } + + constexpr const char* CACHE_ROOT = "/cache"; + if (android::base::StartsWith(package_path, CACHE_ROOT)) { + *should_use_fuse = false; + } + return true; +} diff --git a/recovery.cpp b/recovery.cpp index e4b8e45fb..9747aae82 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -687,7 +687,11 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri ensure_path_mounted(update_package); } - if (install_with_fuse) { + bool should_use_fuse = false; + if (!SetupPackageMount(update_package, &should_use_fuse)) { + LOG(INFO) << "Failed to set up the package access, skipping installation"; + status = INSTALL_ERROR; + } else if (install_with_fuse || should_use_fuse) { LOG(INFO) << "Installing package " << update_package << " with fuse"; status = InstallWithFuseFromPath(update_package, ui); } else if (auto memory_package = Package::CreateMemoryPackage( diff --git a/tests/Android.bp b/tests/Android.bp index e49d966c7..640bb042e 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -93,6 +93,7 @@ librecovery_static_libs = [ "libbinderthreadstate", "liblp", "libtinyxml2", + "libc++fs", ] cc_test { diff --git a/tests/unit/install_test.cpp b/tests/unit/install_test.cpp index 370fbdcc5..ecf1c9a61 100644 --- a/tests/unit/install_test.cpp +++ b/tests/unit/install_test.cpp @@ -34,6 +34,7 @@ #include "install/install.h" #include "install/wipe_device.h" #include "otautil/paths.h" +#include "otautil/roots.h" #include "private/setup_commands.h" static void BuildZipArchive(const std::map<std::string, std::string>& file_map, int fd, @@ -513,3 +514,30 @@ TEST(InstallTest, CheckPackageMetadata_ab_post_timestamp) { "\n"); TestCheckPackageMetadata(metadata, OtaType::AB, true); } + +TEST(InstallTest, SetupPackageMount_package_path) { + load_volume_table(); + bool install_with_fuse; + + // Setup should fail if the input path doesn't exist. + ASSERT_FALSE(SetupPackageMount("/does_not_exist", &install_with_fuse)); + + // Package should be installed with fuse if it's not in /cache. + TemporaryDir temp_dir; + TemporaryFile update_package(temp_dir.path); + ASSERT_TRUE(SetupPackageMount(update_package.path, &install_with_fuse)); + ASSERT_TRUE(install_with_fuse); + + // Setup should fail if the input path isn't canonicalized. + std::string uncanonical_package_path = android::base::Join( + std::vector<std::string>{ + temp_dir.path, + "..", + android::base::Basename(temp_dir.path), + android::base::Basename(update_package.path), + }, + '/'); + + ASSERT_EQ(0, access(uncanonical_package_path.c_str(), R_OK)); + ASSERT_FALSE(SetupPackageMount(uncanonical_package_path, &install_with_fuse)); +} |