From e63ca7dd087b4141c6926d66354e5631644efc3c Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Mon, 14 Jan 2019 15:21:52 +0000 Subject: installd: Implement support for userdata snapshot and restore. Adds two binder APIs: - snapshotAppData: Makes a copy of the apps credential encrypted and/or device encrypted data for a given user to one of /data/misc_[ce|de]/rollback. This path is writable only by installd. - restoreAppDataSnapshot: Restores a copy of the apps credential encrypted and/or device encrypted data from a snapshot, if one exists. Implemented for use from RollbackManagerService, which will make a transient copy of an app package as well as its data in order to roll them back within a specified window. Bug: 112431924 Test: installd_utils_test, installd_service_test Change-Id: I3e4d36c11e52fb885b585b1946e215cf986206fd --- cmds/installd/InstalldNativeService.cpp | 192 ++++++++++++++++++++++++++------ 1 file changed, 160 insertions(+), 32 deletions(-) (limited to 'cmds/installd/InstalldNativeService.cpp') diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 81055d854e..d817370b5d 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -783,6 +784,162 @@ binder::Status InstalldNativeService::fixupAppData(const std::unique_ptr& volumeUuid, + const std::string& packageName, int32_t user, int32_t storageFlags) { + ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_UUID(volumeUuid); + CHECK_ARGUMENT_PACKAGE_NAME(packageName); + std::lock_guard lock(mLock); + + const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr; + const char* package_name = packageName.c_str(); + + binder::Status res = ok(); + bool clear_ce_on_exit = false; + bool clear_de_on_exit = false; + + auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &user, &package_name] { + if (clear_de_on_exit) { + auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, package_name); + if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) { + LOG(WARNING) << "Failed to delete app data snapshot: " << to; + } + } + + if (clear_ce_on_exit) { + auto to = create_data_misc_ce_rollback_package_path(volume_uuid, user, package_name); + if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) { + LOG(WARNING) << "Failed to delete app data snapshot: " << to; + } + } + }; + + auto scope_guard = android::base::make_scope_guard(deleter); + + // The app may not have any data at all, in which case it's OK to skip here. + auto from_ce = create_data_user_ce_package_path(volume_uuid, user, package_name); + if (access(from_ce.c_str(), F_OK) != 0) { + LOG(INFO) << "Missing source " << from_ce; + return ok(); + } + + if (storageFlags & FLAG_STORAGE_DE) { + auto from = create_data_user_de_package_path(volume_uuid, user, package_name); + auto to = create_data_misc_de_rollback_path(volume_uuid, user); + + int rc = copy_directory_recursive(from.c_str(), to.c_str()); + if (rc != 0) { + res = error(rc, "Failed copying " + from + " to " + to); + clear_de_on_exit = true; + return res; + } + } + + if (storageFlags & FLAG_STORAGE_CE) { + auto from = create_data_user_ce_package_path(volume_uuid, user, package_name); + auto to = create_data_misc_ce_rollback_path(volume_uuid, user); + int rc = copy_directory_recursive(from.c_str(), to.c_str()); + if (rc != 0) { + res = error(rc, "Failed copying " + from + " to " + to); + clear_ce_on_exit = true; + return res; + } + } + + return res; +} + +binder::Status InstalldNativeService::restoreAppDataSnapshot( + const std::unique_ptr& volumeUuid, const std::string& packageName, + const int32_t appId, const int64_t ceDataInode, const std::string& seInfo, + const int32_t user, int32_t storageFlags) { + ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_UUID(volumeUuid); + CHECK_ARGUMENT_PACKAGE_NAME(packageName); + std::lock_guard lock(mLock); + + const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr; + const char* package_name = packageName.c_str(); + + auto from_ce = create_data_misc_ce_rollback_package_path(volume_uuid, + user, package_name); + auto from_de = create_data_misc_de_rollback_package_path(volume_uuid, + user, package_name); + + const bool needs_ce_rollback = (storageFlags & FLAG_STORAGE_CE) && + (access(from_ce.c_str(), F_OK) == 0); + const bool needs_de_rollback = (storageFlags & FLAG_STORAGE_DE) && + (access(from_de.c_str(), F_OK) == 0); + + if (!needs_ce_rollback && !needs_de_rollback) { + return ok(); + } + + // We know we're going to rollback one of the CE or DE data, so we clear + // application data first. Note that it's possible that we're asked to + // restore both CE & DE data but that one of the restores fail. Leaving the + // app with no data in those cases is arguably better than leaving the app + // with mismatched / stale data. + LOG(INFO) << "Clearing app data for " << packageName << " to restore snapshot."; + binder::Status res = clearAppData(volumeUuid, packageName, user, storageFlags, ceDataInode); + if (!res.isOk()) { + return res; + } + + if (needs_ce_rollback) { + auto to_ce = create_data_user_ce_path(volume_uuid, user); + int rc = copy_directory_recursive(from_ce.c_str(), to_ce.c_str()); + if (rc != 0) { + res = error(rc, "Failed copying " + from_ce + " to " + to_ce); + return res; + } + } + + if (needs_de_rollback) { + auto to_de = create_data_user_de_path(volume_uuid, user); + int rc = copy_directory_recursive(from_de.c_str(), to_de.c_str()); + if (rc != 0) { + // TODO(narayan): Should we clear clear the rolled back CE data if + // something goes wrong here ? We're choosing between leaving the + // app devoid of all its data or with just its ce data installed. + res = error(rc, "Failed copying " + from_de + " to " + to_de); + return res; + } + } + + // Finally, restore the SELinux label on the app data. + return restoreconAppData(volumeUuid, packageName, user, storageFlags, appId, seInfo); +} + binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr& fromUuid, const std::unique_ptr& toUuid, const std::string& packageName, const std::string& dataAppName, int32_t appId, const std::string& seInfo, @@ -807,19 +964,7 @@ binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr