From a2bd7b7758a4585814f642d55301043276d8a002 Mon Sep 17 00:00:00 2001 From: bigbiff Date: Thu, 7 May 2020 21:45:34 -0400 Subject: [PATCH] factory reset: restore ext4 policy on /data/cache If ext4 policy is not restored, system won't boot properly after a factory reset. When /data is formatted by the user, we need to make sure we do not create the /data/cache directory so that Android can create it with the new policy for /data. This also removes extraneous umount calls, and places them in the specific wipe function for each filesystem. Change-Id: I71ff39d8660fbf4aa6fe8a8309e291166359da72 --- .gitignore | 1 + Android.mk | 8 ++- crypto/ext4crypt/e4policyget.cpp | 3 +- data.cpp | 8 +-- gui/Android.mk | 9 +++ gui/theme/common/languages/en.xml | 1 + partition.cpp | 112 ++++++++++++++++++++++++------ partitionmanager.cpp | 3 - partitions.hpp | 4 +- twrp-functions.cpp | 50 ++++++++++++- twrp-functions.hpp | 6 ++ twrp.cpp | 3 +- 12 files changed, 167 insertions(+), 41 deletions(-) mode change 100644 => 100755 crypto/ext4crypt/e4policyget.cpp mode change 100644 => 100755 gui/Android.mk mode change 100644 => 100755 partition.cpp mode change 100644 => 100755 partitions.hpp diff --git a/.gitignore b/.gitignore index e03babb1f6..480f5478d8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .*.swp *~ tags +.vscode diff --git a/Android.mk b/Android.mk index 26a5227f81..81a2f5ddf2 100755 --- a/Android.mk +++ b/Android.mk @@ -177,7 +177,11 @@ endif ifeq ($(TARGET_USERIMAGES_USE_EXT4), true) ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 28; echo $$?),0) LOCAL_CFLAGS += -DUSE_EXT4 - LOCAL_C_INCLUDES += system/extras/ext4_utils + endif + ifeq ($(shell test $(PLATFORM_SDK_VERSION) -le 28; echo $$?),0) + LOCAL_C_INCLUDES += system/extras/ext4_utils \ + system/extras/ext4_utils/include \ + bootable/recovery/crypto/ext4crypt LOCAL_SHARED_LIBRARIES += libext4_utils ifneq ($(wildcard external/lz4/Android.mk),) #LOCAL_STATIC_LIBRARIES += liblz4 @@ -206,8 +210,6 @@ else LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_TWRP_LIB) endif -LOCAL_C_INCLUDES += system/extras/ext4_utils - tw_git_revision := $(shell git -C $(LOCAL_PATH) rev-parse --short=8 HEAD 2>/dev/null) ifeq ($(shell git -C $(LOCAL_PATH) diff --quiet; echo $$?),1) tw_git_revision := $(tw_git_revision)-dirty diff --git a/crypto/ext4crypt/e4policyget.cpp b/crypto/ext4crypt/e4policyget.cpp old mode 100644 new mode 100755 index 05de86fe70..9211347024 --- a/crypto/ext4crypt/e4policyget.cpp +++ b/crypto/ext4crypt/e4policyget.cpp @@ -23,13 +23,12 @@ #define EXT4_KEY_DESCRIPTOR_SIZE_HEX 17 int main(int argc, char *argv[]) { - bool ret = false; if (argc != 2) { printf("Must specify a path\n"); return -1; } else { ext4_encryption_policy eep; - if (e4crypt_policy_get_struct(argv[1], &eep, sizeof(eep))) { + if (e4crypt_policy_get_struct(argv[1], &eep)) { char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX]; policy_to_hex(eep.master_key_descriptor, policy_hex); printf("%s\n", policy_hex); diff --git a/data.cpp b/data.cpp index b1e8404b30..83fb601117 100755 --- a/data.cpp +++ b/data.cpp @@ -1064,13 +1064,7 @@ void DataManager::Output_Version(void) return; } } - if (!TWFunc::Path_Exists(recoveryCacheDir)) { - LOGINFO("Recreating %s folder.\n", recoveryCacheDir.c_str()); - if (!TWFunc::Create_Dir_Recursive(recoveryCacheDir.c_str(), S_IRWXU | S_IRWXG | S_IWGRP | S_IXGRP, 0, 0)) { - LOGERR("DataManager::Output_Version -- Unable to make %s: %s\n", recoveryCacheDir.c_str(), strerror(errno)); - return; - } - } + std::string verPath = recoveryCacheDir + ".version"; if (TWFunc::Path_Exists(verPath)) { unlink(verPath.c_str()); diff --git a/gui/Android.mk b/gui/Android.mk old mode 100644 new mode 100755 index 22b5347702..60ba325b17 --- a/gui/Android.mk +++ b/gui/Android.mk @@ -46,6 +46,15 @@ else LOCAL_SHARED_LIBRARIES += libminzip LOCAL_CFLAGS += -DUSE_MINZIP endif +ifeq ($(TARGET_USERIMAGES_USE_EXT4), true) + ifeq ($(shell test $(PLATFORM_SDK_VERSION) -le 28; echo $$?),0) + LOCAL_C_INCLUDES += system/extras/ext4_utils \ + system/extras/ext4_utils/include \ + bootable/recovery/crypto/ext4crypt + LOCAL_SHARED_LIBRARIES += libext4_utils + endif +endif + LOCAL_MODULE := libguitwrp #TWRP_EVENT_LOGGING := true diff --git a/gui/theme/common/languages/en.xml b/gui/theme/common/languages/en.xml index 3769da5057..e26ccb7314 100755 --- a/gui/theme/common/languages/en.xml +++ b/gui/theme/common/languages/en.xml @@ -722,5 +722,6 @@ Unmount System before installing a ZIP Unmounting System... Failed unmounting System + WARNING: {1} wiped. FBE device should be booted into Android and not Recovery to set initial FBE policy after wipe. diff --git a/partition.cpp b/partition.cpp old mode 100644 new mode 100755 index faffcd37fd..b47c2947f7 --- a/partition.cpp +++ b/partition.cpp @@ -1,5 +1,5 @@ /* - Copyright 2013 to 2017 TeamWin + Copyright 2013 to 2020 TeamWin This file is part of TWRP/TeamWin Recovery Project. TWRP is free software: you can redistribute it and/or modify @@ -19,17 +19,20 @@ #include #include #include +#include +#include #include +#include #include -#include #include #include +#include +#include +#include #include +#include #include -#include #include -#include -#include #include "cutils/properties.h" #include "libblkid/include/blkid.h" @@ -1632,6 +1635,11 @@ bool TWPartition::Wipe(string New_File_System) { bool wiped = false, update_crypt = false, recreate_media = true; int check; string Layout_Filename = Mount_Point + "/.layout_version"; + ext4_encryption_policy policy; + + if (Mount_Point == "/data" && TWFunc::get_cache_dir() == AB_CACHE_DIR && Is_Decrypted) { + TWFunc::Get_Encryption_Policy(policy, AB_CACHE_DIR); + } if (!Can_Be_Wiped) { gui_msg(Msg(msg::kError, "cannot_wipe=Partition {1} cannot be wiped.")(Display_Name)); @@ -1648,6 +1656,11 @@ bool TWPartition::Wipe(string New_File_System) { if (Has_Data_Media && Current_File_System == New_File_System) { wiped = Wipe_Data_Without_Wiping_Media(); + if (Mount_Point == "/data" && TWFunc::get_cache_dir() == AB_CACHE_DIR) { + bool created = Recreate_AB_Cache_Dir(policy); + if (created) + gui_msg(Msg(msg::kWarning, "fbe_wipe_msg=WARNING: {1} wiped. FBE device should be booted into Android and not Recovery to set initial FBE policy after wipe.")(TWFunc::get_cache_dir())); + } recreate_media = false; } else { DataManager::GetValue(TW_RM_RF_VAR, check); @@ -1677,9 +1690,6 @@ bool TWPartition::Wipe(string New_File_System) { } if (wiped) { - if (Mount_Point == "/cache") - DataManager::Output_Version(); - if (TWFunc::Path_Exists("/.layout_version") && Mount(false)) TWFunc::copy_file("/.layout_version", Layout_Filename, 0600); @@ -1991,10 +2001,10 @@ bool TWPartition::Wipe_Encryption() { gui_msg(Msg(msg::kError, "unable_to_wipe=Unable to wipe {1}.")(Display_Name)); return false; } - if (!UnMount(true)) - goto exit; #ifdef TW_INCLUDE_CRYPTO + if (!UnMount(true)) + return false; if (Is_Decrypted && !Decrypted_Block_Device.empty()) { if (delete_crypto_blk_dev((char*)("userdata")) != 0) { LOGERR("Error deleting crypto block device, continuing anyway.\n"); @@ -2014,7 +2024,10 @@ bool TWPartition::Wipe_Encryption() { } DataManager::SetValue(TW_IS_ENCRYPTED, 0); #ifndef TW_OEM_BUILD - gui_msg("format_data_msg=You may need to reboot recovery to be able to use /data again."); + if (Is_FBE) + gui_msg(Msg(msg::kWarning, "fbe_wipe_msg=WARNING: {1} wiped. FBE device should be booted into Android and not Recovery to set initial FBE policy after wipe.")(TWFunc::get_cache_dir())); + else + gui_msg("format_data_msg=You may need to reboot recovery to be able to use /data again."); #endif ret = true; if (!Key_Directory.empty()) @@ -2080,6 +2093,9 @@ void TWPartition::Check_FS_Type() { } bool TWPartition::Wipe_EXTFS(string File_System) { + if (!UnMount(true)) + return false; + #if PLATFORM_SDK_VERSION < 28 if (!TWFunc::Path_Exists("/sbin/mke2fs")) #else @@ -2219,11 +2235,10 @@ bool TWPartition::Wipe_EXT4() { bool TWPartition::Wipe_FAT() { string command; + if (!UnMount(true)) + return false; if (TWFunc::Path_Exists("/sbin/mkfs.fat")) { - if (!UnMount(true)) - return false; - gui_msg(Msg("formatting_using=Formatting {1} using {2}...")(Display_Name)("mkfs.fat")); Find_Actual_Block_Device(); command = "mkfs.fat " + Actual_Block_Device; @@ -2246,11 +2261,10 @@ bool TWPartition::Wipe_FAT() { bool TWPartition::Wipe_EXFAT() { string command; + if (!UnMount(true)) + return false; if (TWFunc::Path_Exists("/sbin/mkexfatfs")) { - if (!UnMount(true)) - return false; - gui_msg(Msg("formatting_using=Formatting {1} using {2}...")(Display_Name)("mkexfatfs")); Find_Actual_Block_Device(); command = "mkexfatfs " + Actual_Block_Device; @@ -2317,6 +2331,8 @@ bool TWPartition::Wipe_RMRF() { bool TWPartition::Wipe_F2FS() { string command; + if (!UnMount(true)) + return false; if (TWFunc::Path_Exists("/sbin/mkfs.f2fs")) { bool NeedPreserveFooter = true; @@ -2327,8 +2343,6 @@ bool TWPartition::Wipe_F2FS() { gui_msg(Msg(msg::kError, "unable_to_wipe=Unable to wipe {1}.")(Display_Name)); return false; } - if (!UnMount(true)) - return false; /** * On decrypted devices, IOCTL_Get_Block_Size calculates size on device mapper, @@ -2402,6 +2416,9 @@ bool TWPartition::Wipe_NTFS() { string command; string Ntfsmake_Binary; + if (!UnMount(true)) + return false; + if (TWFunc::Path_Exists("/sbin/mkntfs")) Ntfsmake_Binary = "mkntfs"; else if (TWFunc::Path_Exists("/sbin/mkfs.ntfs")) @@ -2409,9 +2426,6 @@ bool TWPartition::Wipe_NTFS() { else return false; - if (!UnMount(true)) - return false; - gui_msg(Msg("formatting_using=Formatting {1} using {2}...")(Display_Name)(Ntfsmake_Binary)); Find_Actual_Block_Device(); command = "/sbin/" + Ntfsmake_Binary + " " + Actual_Block_Device; @@ -2435,7 +2449,6 @@ bool TWPartition::Wipe_Data_Without_Wiping_Media() { if (!Mount(true)) return false; - gui_msg("wiping_data=Wiping data without wiping /data/media ..."); ret = Wipe_Data_Without_Wiping_Media_Func(Mount_Point + "/"); if (ret) @@ -2444,6 +2457,59 @@ bool TWPartition::Wipe_Data_Without_Wiping_Media() { #endif // ifdef TW_OEM_BUILD } +bool TWPartition::Recreate_AB_Cache_Dir(const ext4_encryption_policy &policy) { + struct passwd pd; + struct passwd *pwdptr = &pd; + struct passwd *tempPd; + char pwdBuf[512]; + int uid = 0, gid = 0; + + if ((getpwnam_r("system", pwdptr, pwdBuf, sizeof(pwdBuf), &tempPd)) != 0) { + LOGERR("unable to get system user id\n"); + return false; + } else { + struct group grp; + struct group *grpptr = &grp; + struct group *tempGrp; + char grpBuf[512]; + + if ((getgrnam_r("cache", grpptr, grpBuf, sizeof(grpBuf), &tempGrp)) != 0) { + LOGERR("unable to get cache group id\n"); + return false; + } else { + uid = pd.pw_uid; + gid = grp.gr_gid; + + if (!TWFunc::Create_Dir_Recursive(AB_CACHE_DIR, S_IRWXU | S_IRWXG | S_IWGRP | S_IXGRP, uid, gid)) { + LOGERR("Unable to recreate %s\n", AB_CACHE_DIR); + return false; + } + if (setfilecon(AB_CACHE_DIR, "u:object_r:cache_file:s0") != 0) { + LOGERR("Unable to set contexts for %s\n", AB_CACHE_DIR); + return false; + } + char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX]; + policy_to_hex(policy.master_key_descriptor, policy_hex); + LOGINFO("setting policy for %s: %s\n", policy_hex, AB_CACHE_DIR); + if (sizeof(policy.master_key_descriptor) > 0) { + if (!TWFunc::Set_Encryption_Policy(AB_CACHE_DIR, policy)) { + LOGERR("Unable to set encryption policy for %s\n", AB_CACHE_DIR); + LOGINFO("Removing %s\n", AB_CACHE_DIR); + int ret = TWFunc::removeDir(AB_CACHE_DIR, true); + if (ret == -1) { + LOGERR("Unable to remove %s\n", AB_CACHE_DIR); + } + return false; + } + } else { + LOGERR("Not setting empty policy to %s\n", AB_CACHE_DIR); + return false; + } + } + } + return true; +} + bool TWPartition::Wipe_Data_Without_Wiping_Media_Func(const string& parent __unused) { string dir; diff --git a/partitionmanager.cpp b/partitionmanager.cpp index 64f39e4905..f9adb02a0e 100755 --- a/partitionmanager.cpp +++ b/partitionmanager.cpp @@ -1487,9 +1487,6 @@ int TWPartitionManager::Format_Data(void) { TWPartition* dat = Find_Partition_By_Path("/data"); if (dat != NULL) { - if (!dat->UnMount(true)) - return false; - return dat->Wipe_Encryption(); } else { gui_msg(Msg(msg::kError, "unable_to_locate=Unable to locate {1}.")("/data")); diff --git a/partitions.hpp b/partitions.hpp old mode 100644 new mode 100755 index 92970d92f1..5a52fa3081 --- a/partitions.hpp +++ b/partitions.hpp @@ -26,6 +26,7 @@ #include "exclude.hpp" #include "tw_atomic.hpp" #include "progresstracking.hpp" +#include "ext4crypt_tar.h" #define MAX_FSTAB_LINE_LENGTH 2048 @@ -207,6 +208,7 @@ class TWPartition bool Wipe_NTFS(); // Uses mkntfs to wipe bool Wipe_Data_Without_Wiping_Media(); // Uses rm -rf to wipe but does not wipe /data/media bool Wipe_Data_Without_Wiping_Media_Func(const string& parent); // Uses rm -rf to wipe but does not wipe /data/media + bool Recreate_AB_Cache_Dir(const ext4_encryption_policy &policy); // Recreate AB_CACHE_DIR after wipe void Wipe_Crypto_Key(); // Wipe crypto key from either footer or block device bool Backup_Tar(PartitionSettings *part_settings, pid_t *tar_fork_pid); // Backs up using tar for file systems bool Backup_Image(PartitionSettings *part_settings); // Backs up using raw read/write for emmc memory types @@ -281,7 +283,7 @@ class TWPartition bool SlotSelect; // Partition has A/B slots TWExclude backup_exclusions; // Exclusions for file based backups TWExclude wipe_exclusions; // Exclusions for file based wipes (data/media devices only) - string Key_Directory; // Metadata key directory needed for mounting FBE encrypted data partitions using metadata encryption + string Key_Directory; // Metadata key directory needed for mounting FBE encrypted data partitions using metadata encryption struct partition_fs_flags_struct { // This struct is used to store mount flags and options for different file systems for the same partition string File_System; diff --git a/twrp-functions.cpp b/twrp-functions.cpp index 593ad9d004..2f563d9999 100755 --- a/twrp-functions.cpp +++ b/twrp-functions.cpp @@ -640,7 +640,9 @@ void TWFunc::Update_Intent_File(string Intent) { int TWFunc::tw_reboot(RebootCommand command) { DataManager::Flush(); - Update_Log_File(); + if (!Is_Data_Wiped("/data")) + Update_Log_File(); + // Always force a sync before we reboot sync(); @@ -1333,4 +1335,50 @@ int TWFunc::Property_Override(string Prop_Name, string Prop_Value) { #endif } +bool TWFunc::Get_Encryption_Policy(ext4_encryption_policy &policy, std::string path) { + if (!TWFunc::Path_Exists(path)) { + LOGERR("Unable to find %s to get policy\n", path.c_str()); + return false; + } + if (!e4crypt_policy_get_struct(path.c_str(), &policy)) { + LOGERR("No policy set for path %s\n", path.c_str()); + return false; + } + return true; +} + +bool TWFunc::Set_Encryption_Policy(std::string path, const ext4_encryption_policy &policy) { + if (!TWFunc::Path_Exists(path)) { + LOGERR("unable to find %s to set policy\n", path.c_str()); + return false; + } + char binary_policy[EXT4_KEY_DESCRIPTOR_SIZE]; + char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX]; + policy_to_hex(binary_policy, policy_hex); + if (!e4crypt_policy_set_struct(path.c_str(), &policy)) { + LOGERR("unable to set policy for path: %s\n", path.c_str()); + return false; + } + return true; +} + +bool TWFunc::Is_Data_Wiped(std::string path) { + DIR* d = opendir(path.c_str()); + size_t file_count = 0; + if (d != NULL) { + struct dirent* de; + while ((de = readdir(d)) != NULL) { + LOGINFO("file: %s\n", de->d_name); + if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) + continue; + if (strncmp(de->d_name, "lost+found", 10) == 0 || strncmp(de->d_name, "media", 5) == 0) + continue; + file_count++; + + } + closedir(d); + } + LOGINFO("file_count: %zu\n", file_count); + return file_count == 0; +} #endif // ndef BUILD_TWRPTAR_MAIN diff --git a/twrp-functions.hpp b/twrp-functions.hpp index 9d53ab6e50..9c8378853f 100755 --- a/twrp-functions.hpp +++ b/twrp-functions.hpp @@ -21,8 +21,10 @@ #include #include +#include #include "twrpDigest/twrpDigest.hpp" +#include "ext4crypt_tar.h" #ifndef BUILD_TWRPTAR_MAIN #include "partitions.hpp" @@ -52,6 +54,7 @@ enum Archive_Type { COMPRESSED_ENCRYPTED }; + // Partition class class TWFunc { @@ -113,6 +116,9 @@ class TWFunc static void check_selinux_support(); // print whether selinux support is enabled to console static bool Is_TWRP_App_In_System(); // Check if the TWRP app is installed in the system partition static int Property_Override(string Prop_Name, string Prop_Value); // Override properties (including ro. properties) + static bool Get_Encryption_Policy(ext4_encryption_policy &policy, std::string path); // return encryption policy for path + static bool Set_Encryption_Policy(std::string path, const ext4_encryption_policy &policy); // set encryption policy for path + static bool Is_Data_Wiped(std::string path); // check if directory has been wiped private: static void Copy_Log(string Source, string Destination); diff --git a/twrp.cpp b/twrp.cpp index 7689c25323..036a2375e1 100755 --- a/twrp.cpp +++ b/twrp.cpp @@ -401,7 +401,8 @@ int main(int argc, char **argv) { // Reboot TWFunc::Update_Intent_File(Send_Intent); delete adb_bu_fifo; - TWFunc::Update_Log_File(); + if (!TWFunc::Is_Data_Wiped("/data")) + TWFunc::Update_Log_File(); gui_msg(Msg("rebooting=Rebooting...")); string Reboot_Arg; DataManager::GetValue("tw_reboot_arg", Reboot_Arg);