Fix the long broken format function
* For EXT2/3:
* Align mke2fs options with Android 9.0 fs_mgr_format.cpp.
* For EXT4:
* Note that make_ext4fs is still in use on Android 8.1 to workaround
a FDE encryption bug even though mke2fs has become the default
choice. The bug is fixed in Android 9.0+.
* For F2FS:
* Drop the broken "-r" option, it's never ported to O, explicitly
pass number of sectors instead.
* Keep all options aligned with Pie fs_mgr.
* Check existence before start wiping, as Wipe_EXT4 does.
* For all:
* Calculate block size at runtime, and reserve the space specified
via negative "length" option from fstab. Note that positive length
will be ignored.
* If the partition has crypto footer, and "length" is not specified
in fstab, automatically reverse CRYPT_FOOTER_OFFSET (16384).
* Remove the default crypto key location: footer, this is a bad
assumption since most partitions don't use encryption! We need to
know the real situation to decide whether to reserve crypto footer
on format.
* If the current action is "wipe" or "change filesystem", wipe crypto
footer or block device after mkfs if the partition is
unencrypted or undecrypted (e.g., wrong password).
* If the current action is "format data", unconditionally wipe crypto
footer or block device.
Change-Id: I7304a8ee703131ea4a08ab7c60334af28cac28b3
diff --git a/Android.mk b/Android.mk
index 920b390..6eb1cbc 100755
--- a/Android.mk
+++ b/Android.mk
@@ -46,6 +46,7 @@
else
LOCAL_CFLAGS += -DTW_DEVICE_VERSION='"-0"'
endif
+LOCAL_CFLAGS += -DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION)
LOCAL_SRC_FILES := \
twrp.cpp \
diff --git a/partition.cpp b/partition.cpp
index b96b969..b421598 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -258,7 +258,7 @@
Format_Block_Size = 0;
Ignore_Blkid = false;
Retain_Layout_Version = false;
- Crypto_Key_Location = "footer";
+ Crypto_Key_Location = "";
MTP_Storage_ID = 0;
Can_Flash_Img = false;
Mount_Read_Only = false;
@@ -1603,7 +1603,7 @@
else if (New_File_System == "ext4")
wiped = Wipe_EXT4();
else if (New_File_System == "ext2" || New_File_System == "ext3")
- wiped = Wipe_EXT23(New_File_System);
+ wiped = Wipe_EXTFS(New_File_System);
else if (New_File_System == "vfat")
wiped = Wipe_FAT();
else if (New_File_System == "exfat")
@@ -1931,68 +1931,26 @@
if (!base_partition->PreWipeEncryption())
goto exit;
+ Find_Actual_Block_Device();
+ if (!Is_Present) {
+ LOGINFO("Block device not present, cannot format %s.\n", Display_Name.c_str());
+ gui_msg(Msg(msg::kError, "unable_to_wipe=Unable to wipe {1}.")(Display_Name));
+ return false;
+ }
if (!UnMount(true))
goto exit;
- Has_Data_Media = false;
#ifdef TW_INCLUDE_CRYPTO
if (Is_Decrypted && !Decrypted_Block_Device.empty()) {
- if (!UnMount(true))
- goto exit;
if (delete_crypto_blk_dev((char*)("userdata")) != 0) {
LOGERR("Error deleting crypto block device, continuing anyway.\n");
}
}
#endif
+ Has_Data_Media = false;
Decrypted_Block_Device = "";
Is_Decrypted = false;
Is_Encrypted = false;
- Find_Actual_Block_Device();
- if (Crypto_Key_Location == "footer") {
- int newlen, fd;
- if (Length != 0) {
- newlen = Length;
- if (newlen < 0)
- newlen = newlen * -1;
- } else {
- newlen = CRYPT_FOOTER_OFFSET;
- }
- if ((fd = open(Actual_Block_Device.c_str(), O_RDWR)) < 0) {
- gui_print_color("warning", "Unable to open '%s' to wipe crypto key\n", Actual_Block_Device.c_str());
- } else {
- unsigned int block_count;
- if ((ioctl(fd, BLKGETSIZE, &block_count)) == -1) {
- gui_print_color("warning", "Unable to get block size for wiping crypto footer.\n");
- } else {
- off64_t offset = ((off64_t)block_count * 512) - newlen;
- if (lseek64(fd, offset, SEEK_SET) == -1) {
- gui_print_color("warning", "Unable to lseek64 for wiping crypto footer.\n");
- } else {
- void* buffer = malloc(newlen);
- if (!buffer) {
- gui_print_color("warning", "Failed to malloc for wiping crypto footer.\n");
- } else {
- memset(buffer, 0, newlen);
- int ret = write(fd, buffer, newlen);
- if (ret != newlen) {
- gui_print_color("warning", "Failed to wipe crypto footer.\n");
- } else {
- LOGINFO("Successfully wiped crypto footer.\n");
- }
- free(buffer);
- }
- }
- }
- close(fd);
- }
- } else {
- if (TWFunc::IOCTL_Get_Block_Size(Crypto_Key_Location.c_str()) >= 16384LLU) {
- string Command = "dd of='" + Crypto_Key_Location + "' if=/dev/zero bs=16384 count=1";
- TWFunc::Exec_Cmd(Command);
- } else {
- LOGINFO("Crypto key location reports size < 16K so not wiping crypto footer.\n");
- }
- }
if (Wipe(Fstab_File_System)) {
Has_Data_Media = Save_Data_Media;
if (Has_Data_Media && !Symlink_Mount_Point.empty()) {
@@ -2067,33 +2025,17 @@
}
}
-bool TWPartition::Wipe_EXT23(string File_System) {
- if (!UnMount(true))
- return false;
-
- if (TWFunc::Path_Exists("/sbin/mke2fs")) {
- string command;
-
- gui_msg(Msg("formatting_using=Formatting {1} using {2}...")(Display_Name)("mke2fs"));
- Find_Actual_Block_Device();
- command = "mke2fs -t " + File_System + " -m 0 " + Actual_Block_Device;
- LOGINFO("mke2fs command: %s\n", command.c_str());
- if (TWFunc::Exec_Cmd(command) == 0) {
- Current_File_System = File_System;
- Recreate_AndSec_Folder();
- gui_msg("done=Done.");
- return true;
- } else {
- gui_msg(Msg(msg::kError, "unable_to_wipe=Unable to wipe {1}.")(Display_Name));
- return false;
- }
- } else
+bool TWPartition::Wipe_EXTFS(string File_System) {
+#if PLATFORM_SDK_VERSION < 28
+ if (!TWFunc::Path_Exists("/sbin/mke2fs"))
+#else
+ if (!TWFunc::Path_Exists("/sbin/mke2fs") || !TWFunc::Path_Exists("/sbin/e2fsdroid"))
+#endif
return Wipe_RMRF();
- return false;
-}
+ int ret;
+ bool NeedPreserveFooter = true;
-bool TWPartition::Wipe_EXT4() {
Find_Actual_Block_Device();
if (!Is_Present) {
LOGINFO("Block device not present, cannot wipe %s.\n", Display_Name.c_str());
@@ -2103,22 +2045,103 @@
if (!UnMount(true))
return false;
-#if defined(USE_EXT4)
+ /**
+ * On decrypted devices, IOCTL_Get_Block_Size calculates size on device mapper,
+ * so there's no need to preserve footer.
+ */
+ if ((Is_Decrypted && !Decrypted_Block_Device.empty()) ||
+ Crypto_Key_Location != "footer") {
+ NeedPreserveFooter = false;
+ }
+
+ unsigned long long dev_sz = TWFunc::IOCTL_Get_Block_Size(Actual_Block_Device.c_str());
+ if (!dev_sz)
+ return false;
+
+ if (NeedPreserveFooter)
+ Length < 0 ? dev_sz += Length : dev_sz -= CRYPT_FOOTER_OFFSET;
+
+ string size_str = to_string(dev_sz / 4096);
+ string Command;
+
+ gui_msg(Msg("formatting_using=Formatting {1} using {2}...")(Display_Name)("mke2fs"));
+
+ // Execute mke2fs to create empty ext4 filesystem
+ Command = "mke2fs -t " + File_System + " -b 4096 " + Actual_Block_Device + " " + size_str;
+ LOGINFO("mke2fs command: %s\n", Command.c_str());
+ ret = TWFunc::Exec_Cmd(Command);
+ if (ret) {
+ gui_msg(Msg(msg::kError, "unable_to_wipe=Unable to wipe {1}.")(Display_Name));
+ return false;
+ }
+
+ if (TWFunc::Path_Exists("/sbin/e2fsdroid")) {
+ // Execute e2fsdroid to initialize selinux context
+ Command = "e2fsdroid -e -a " + Mount_Point + " " + Actual_Block_Device;
+ LOGINFO("e2fsdroid command: %s\n", Command.c_str());
+ ret = TWFunc::Exec_Cmd(Command);
+ if (ret) {
+ gui_msg(Msg(msg::kError, "unable_to_wipe=Unable to wipe {1}.")(Display_Name));
+ return false;
+ }
+ } else {
+ LOGINFO("e2fsdroid not present\n");
+ }
+
+ if (NeedPreserveFooter)
+ Wipe_Crypto_Key();
+ Current_File_System = File_System;
+ Recreate_AndSec_Folder();
+ gui_msg("done=Done.");
+ return true;
+}
+
+bool TWPartition::Wipe_EXT4() {
+#ifdef USE_EXT4
int ret;
+ bool NeedPreserveFooter = true;
+
+ Find_Actual_Block_Device();
+ if (!Is_Present) {
+ LOGINFO("Block device not present, cannot wipe %s.\n", Display_Name.c_str());
+ 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,
+ * so there's no need to preserve footer.
+ */
+ if ((Is_Decrypted && !Decrypted_Block_Device.empty()) ||
+ Crypto_Key_Location != "footer") {
+ NeedPreserveFooter = false;
+ }
+
+ unsigned long long dev_sz = TWFunc::IOCTL_Get_Block_Size(Actual_Block_Device.c_str());
+ if (!dev_sz)
+ return false;
+
+ if (NeedPreserveFooter)
+ Length < 0 ? dev_sz += Length : dev_sz -= CRYPT_FOOTER_OFFSET;
+
char *secontext = NULL;
gui_msg(Msg("formatting_using=Formatting {1} using {2}...")(Display_Name)("make_ext4fs"));
if (!selinux_handle || selabel_lookup(selinux_handle, &secontext, Mount_Point.c_str(), S_IFDIR) < 0) {
LOGINFO("Cannot lookup security context for '%s'\n", Mount_Point.c_str());
- ret = make_ext4fs(Actual_Block_Device.c_str(), Length, Mount_Point.c_str(), NULL);
+ ret = make_ext4fs(Actual_Block_Device.c_str(), dev_sz, Mount_Point.c_str(), NULL);
} else {
- ret = make_ext4fs(Actual_Block_Device.c_str(), Length, Mount_Point.c_str(), selinux_handle);
+ ret = make_ext4fs(Actual_Block_Device.c_str(), dev_sz, Mount_Point.c_str(), selinux_handle);
}
if (ret != 0) {
gui_msg(Msg(msg::kError, "unable_to_wipe=Unable to wipe {1}.")(Display_Name));
return false;
} else {
+ if (NeedPreserveFooter)
+ Wipe_Crypto_Key();
string sedir = Mount_Point + "/lost+found";
PartitionManager.Mount_By_Path(sedir.c_str(), true);
rmdir(sedir.c_str());
@@ -2126,37 +2149,8 @@
return true;
}
#else
- if (TWFunc::Path_Exists("/sbin/make_ext4fs")) {
- string Command;
-
- gui_msg(Msg("formatting_using=Formatting {1} using {2}...")(Display_Name)("make_ext4fs"));
- Find_Actual_Block_Device();
- Command = "make_ext4fs";
- if (!Is_Decrypted && Length != 0) {
- // Only use length if we're not decrypted
- char len[32];
- sprintf(len, "%i", Length);
- Command += " -l ";
- Command += len;
- }
- if (TWFunc::Path_Exists("/file_contexts")) {
- Command += " -S /file_contexts";
- }
- Command += " -a " + Mount_Point + " " + Actual_Block_Device;
- LOGINFO("make_ext4fs command: %s\n", Command.c_str());
- if (TWFunc::Exec_Cmd(Command) == 0) {
- Current_File_System = "ext4";
- Recreate_AndSec_Folder();
- gui_msg("done=Done.");
- return true;
- } else {
- gui_msg(Msg(msg::kError, "unable_to_wipe=Unable to wipe {1}.")(Display_Name));
- return false;
- }
- } else
- return Wipe_EXT23("ext4");
+ return Wipe_EXTFS("ext4");
#endif
- return false;
}
bool TWPartition::Wipe_FAT() {
@@ -2261,29 +2255,42 @@
string command;
if (TWFunc::Path_Exists("/sbin/mkfs.f2fs")) {
+ bool NeedPreserveFooter = true;
+
+ Find_Actual_Block_Device();
+ if (!Is_Present) {
+ LOGINFO("Block device not present, cannot wipe %s.\n", Display_Name.c_str());
+ gui_msg(Msg(msg::kError, "unable_to_wipe=Unable to wipe {1}.")(Display_Name));
+ return false;
+ }
if (!UnMount(true))
return false;
- gui_msg(Msg("formatting_using=Formatting {1} using {2}...")(Display_Name)("mkfs.f2fs"));
- Find_Actual_Block_Device();
- if (!TWFunc::Path_Exists("/sbin/sload.f2fs")) {
- command = "mkfs.f2fs -t 0";
- if (!Is_Decrypted && Length != 0) {
- // Only use length if we're not decrypted
- char len[32];
- int mod_length = Length;
- if (Length < 0)
- mod_length *= -1;
- sprintf(len, "%i", mod_length);
- command += " -r ";
- command += len;
- }
- command += " " + Actual_Block_Device;
- } else {
- unsigned long long size = IOCTL_Get_Block_Size() + Length;
- command = "mkfs.f2fs -d1 -f -O encrypt -O quota -O verity -w 4096 " + Actual_Block_Device + " " + std::to_string(size / 4096) + " && sload.f2fs -t /data " + Actual_Block_Device;
+ /**
+ * On decrypted devices, IOCTL_Get_Block_Size calculates size on device mapper,
+ * so there's no need to preserve footer.
+ */
+ if ((Is_Decrypted && !Decrypted_Block_Device.empty()) ||
+ Crypto_Key_Location != "footer") {
+ NeedPreserveFooter = false;
}
+
+ unsigned long long dev_sz = TWFunc::IOCTL_Get_Block_Size(Actual_Block_Device.c_str());
+ if (!dev_sz)
+ return false;
+
+ if (NeedPreserveFooter)
+ Length < 0 ? dev_sz += Length : dev_sz -= CRYPT_FOOTER_OFFSET;
+
+ gui_msg(Msg("formatting_using=Formatting {1} using {2}...")(Display_Name)("mkfs.f2fs"));
+ command = "mkfs.f2fs -d1 -f -O encrypt -O quota -O verity -w 4096 " + Actual_Block_Device + " " + to_string(dev_sz / 4096);
+ if (TWFunc::Path_Exists("/sbin/sload.f2fs")) {
+ command += " && sload.f2fs -t /data " + Actual_Block_Device;
+ }
+ LOGINFO("mkfs.f2fs command: %s\n", command.c_str());
if (TWFunc::Exec_Cmd(command) == 0) {
+ if (NeedPreserveFooter)
+ Wipe_Crypto_Key();
Recreate_AndSec_Folder();
gui_msg("done=Done.");
return true;
@@ -2381,6 +2388,52 @@
return false;
}
+void TWPartition::Wipe_Crypto_Key() {
+ Find_Actual_Block_Device();
+ if (Crypto_Key_Location.empty())
+ return;
+ else if (Crypto_Key_Location == "footer") {
+ int fd = open(Actual_Block_Device.c_str(), O_RDWR);
+ if (fd < 0) {
+ gui_print_color("warning", "Unable to open '%s' to wipe crypto key\n", Actual_Block_Device.c_str());
+ return;
+ }
+
+ unsigned int block_count;
+ if ((ioctl(fd, BLKGETSIZE, &block_count)) == -1) {
+ gui_print_color("warning", "Unable to get block size for wiping crypto footer.\n");
+ } else {
+ int newlen = Length < 0 ? -Length : CRYPT_FOOTER_OFFSET;
+ off64_t offset = ((off64_t)block_count * 512) - newlen;
+ if (lseek64(fd, offset, SEEK_SET) == -1) {
+ gui_print_color("warning", "Unable to lseek64 for wiping crypto footer.\n");
+ } else {
+ void* buffer = malloc(newlen);
+ if (!buffer) {
+ gui_print_color("warning", "Failed to malloc for wiping crypto footer.\n");
+ } else {
+ memset(buffer, 0, newlen);
+ int ret = write(fd, buffer, newlen);
+ if (ret != newlen) {
+ gui_print_color("warning", "Failed to wipe crypto footer.\n");
+ } else {
+ LOGINFO("Successfully wiped crypto footer.\n");
+ }
+ free(buffer);
+ }
+ }
+ }
+ close(fd);
+ } else {
+ if (TWFunc::IOCTL_Get_Block_Size(Crypto_Key_Location.c_str()) >= 16384LLU) {
+ string Command = "dd of='" + Crypto_Key_Location + "' if=/dev/zero bs=16384 count=1";
+ TWFunc::Exec_Cmd(Command);
+ } else {
+ LOGINFO("Crypto key location reports size < 16K so not wiping crypto footer.\n");
+ }
+ }
+}
+
bool TWPartition::Backup_Tar(PartitionSettings *part_settings, pid_t *tar_fork_pid) {
string Full_FileName;
twrpTar tar;
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index 4ebe742..6b5ee1c 100755
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -466,7 +466,7 @@
printf(" Alternate_Block_Device: %s\n", Part->Alternate_Block_Device.c_str());
if (!Part->Decrypted_Block_Device.empty())
printf(" Decrypted_Block_Device: %s\n", Part->Decrypted_Block_Device.c_str());
- if (!Part->Crypto_Key_Location.empty() && Part->Crypto_Key_Location != "footer")
+ if (!Part->Crypto_Key_Location.empty())
printf(" Crypto_Key_Location: %s\n", Part->Crypto_Key_Location.c_str());
if (Part->Length != 0)
printf(" Length: %i\n", Part->Length);
diff --git a/partitions.hpp b/partitions.hpp
index a8fd70b..c124457 100644
--- a/partitions.hpp
+++ b/partitions.hpp
@@ -181,7 +181,7 @@
unsigned long long IOCTL_Get_Block_Size(); // Finds the partition size using ioctl
bool Find_Partition_Size(); // Finds the partition size from /proc/partitions
unsigned long long Get_Size_Via_du(string Path, bool Display_Error); // Uses du to get sizes
- bool Wipe_EXT23(string File_System); // Formats as ext3 or ext2
+ bool Wipe_EXTFS(string File_System); // Create an ext2/ext3/ext4 filesystem
bool Wipe_EXT4(); // Formats using ext4, uses make_ext4fs when present
bool Wipe_FAT(); // Formats as FAT if mkfs.fat exits otherwise rm -rf wipe
bool Wipe_EXFAT(); // Formats as EXFAT
@@ -191,6 +191,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
+ 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
bool Raw_Read_Write(PartitionSettings *part_settings);
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index 7696aff..de82879 100644
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -41,6 +41,9 @@
RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/adbd
endif
RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/e2fsck
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 28; echo $$?),0)
+ RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/e2fsdroid
+endif
RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/mke2fs
RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/tune2fs
RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/resize2fs