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
diff --git a/.gitignore b/.gitignore
index e03babb..480f547 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
.*.swp
*~
tags
+.vscode
diff --git a/Android.mk b/Android.mk
index 26a5227..81a2f5d 100755
--- a/Android.mk
+++ b/Android.mk
@@ -177,7 +177,11 @@
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 @@
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 05de86f..9211347
--- 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 b1e8404..83fb601 100755
--- a/data.cpp
+++ b/data.cpp
@@ -1064,13 +1064,7 @@
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 22b5347..60ba325
--- a/gui/Android.mk
+++ b/gui/Android.mk
@@ -46,6 +46,15 @@
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 3769da5..e26ccb7 100755
--- a/gui/theme/common/languages/en.xml
+++ b/gui/theme/common/languages/en.xml
@@ -722,5 +722,6 @@
<string name="unmount_sys_install">Unmount System before installing a ZIP</string>
<string name="unmount_system">Unmounting System...</string>
<string name="unmount_system_err">Failed unmounting System</string>
+ <string name="fbe_wipe_msg">WARNING: {1} wiped. FBE device should be booted into Android and not Recovery to set initial FBE policy after wipe.</string>
</resources>
</language>
diff --git a/partition.cpp b/partition.cpp
old mode 100644
new mode 100755
index faffcd3..b47c294
--- 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/stat.h>
-#include <sys/vfs.h>
#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
#include <unistd.h>
#include <dirent.h>
-#include <libgen.h>
-#include <zlib.h>
-#include <iostream>
-#include <sstream>
-#include <sys/param.h>
#include <fcntl.h>
+#include <grp.h>
+#include <iostream>
+#include <libgen.h>
+#include <pwd.h>
+#include <zlib.h>
+#include <sstream>
#include "cutils/properties.h"
#include "libblkid/include/blkid.h"
@@ -1632,6 +1635,11 @@
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 @@
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 @@
}
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 @@
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 @@
}
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 @@
}
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_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_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_F2FS() {
string command;
+ if (!UnMount(true))
+ return false;
if (TWFunc::Path_Exists("/sbin/mkfs.f2fs")) {
bool NeedPreserveFooter = true;
@@ -2327,8 +2343,6 @@
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 @@
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 @@
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 @@
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 @@
#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 64f39e4..f9adb02 100755
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -1487,9 +1487,6 @@
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 92970d9..5a52fa3
--- 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 @@
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 @@
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 593ad9d..2f563d9 100755
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -640,7 +640,9 @@
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 @@
#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 9d53ab6..9c83788 100755
--- a/twrp-functions.hpp
+++ b/twrp-functions.hpp
@@ -21,8 +21,10 @@
#include <string>
#include <vector>
+#include <ext4_utils/ext4_crypt.h>
#include "twrpDigest/twrpDigest.hpp"
+#include "ext4crypt_tar.h"
#ifndef BUILD_TWRPTAR_MAIN
#include "partitions.hpp"
@@ -52,6 +54,7 @@
COMPRESSED_ENCRYPTED
};
+
// Partition class
class TWFunc
{
@@ -113,6 +116,9 @@
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 7689c25..036a237 100755
--- a/twrp.cpp
+++ b/twrp.cpp
@@ -401,7 +401,8 @@
// 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);