From eb32b1ff00878e7b01453450fcd04ecb9fcbba52 Mon Sep 17 00:00:00 2001 From: Ethan Yonker Date: Mon, 18 May 2015 10:23:03 -0500 Subject: Mount system as read-only by default Mounting system as rw can prevent future OTA updates. The purpose of this patch set is to prevent TWRP from mounting sytem as rw on the first boot. Device maintainers should update their twrp.fstab files on these devices to include an additional line: /system_image emmc /dev/block/../system This line will allow TWRP to create a raw system image backup to ensure that the user can return to an original state for future OTA updates. Change-Id: I8929d85bc3a5b96cc564bc7f734b58d5612ec833 --- data.cpp | 2 + gui/action.cpp | 54 +++++++++++++++ gui/devices/1080x1920/res/ui.xml | 1 + gui/devices/320x320/res/ui.xml | 3 +- gui/devices/480x800/res/ui.xml | 1 + gui/devices/landscape/res/landscape.xml | 98 +++++++++++++++++++++++++++ gui/devices/portrait/res/portrait.xml | 113 ++++++++++++++++++++++++++++++++ gui/devices/watch/res/watch.xml | 111 +++++++++++++++++++++++++++++++ gui/objects.hpp | 2 + partition.cpp | 56 ++++++++++++++-- partitionmanager.cpp | 6 +- partitions.hpp | 3 + twrp.cpp | 16 ++++- 13 files changed, 459 insertions(+), 7 deletions(-) diff --git a/data.cpp b/data.cpp index 0ce4ddc3c..eb8b55341 100644 --- a/data.cpp +++ b/data.cpp @@ -852,6 +852,8 @@ void DataManager::SetDefaultValues() mConstValues.insert(make_pair("tw_has_mtp", "0")); mConstValues.insert(make_pair("tw_mtp_enabled", "0")); #endif + mValues.insert(make_pair("tw_mount_system_ro", make_pair("1", 1))); + mValues.insert(make_pair("tw_never_show_system_ro_page", make_pair("0", 1))); pthread_mutex_unlock(&m_valuesLock); } diff --git a/gui/action.cpp b/gui/action.cpp index 342551247..7ecd0b46a 100644 --- a/gui/action.cpp +++ b/gui/action.cpp @@ -196,6 +196,8 @@ GUIAction::GUIAction(xml_node<>* node) ADD_ACTION(startmtp); ADD_ACTION(stopmtp); ADD_ACTION(cancelbackup); + ADD_ACTION(checkpartitionlifetimewrites); + ADD_ACTION(mountsystemtoggle); // remember actions that run in the caller thread for (mapFunc::const_iterator it = mf.begin(); it != mf.end(); ++it) @@ -1737,3 +1739,55 @@ int GUIAction::getKeyByName(std::string key) return atol(key.c_str()); } + +int GUIAction::checkpartitionlifetimewrites(std::string arg) +{ + int op_status = 0; + TWPartition* sys = PartitionManager.Find_Partition_By_Path(arg); + + operation_start("Check Partition Lifetime Writes"); + if (sys) { + if (sys->Check_Lifetime_Writes() != 0) + DataManager::SetValue("tw_lifetime_writes", 1); + else + DataManager::SetValue("tw_lifetime_writes", 0); + op_status = 0; // success + } else { + DataManager::SetValue("tw_lifetime_writes", 1); + op_status = 1; // fail + } + + operation_end(op_status); + return 0; +} + +int GUIAction::mountsystemtoggle(std::string arg) +{ + int op_status = 0; + bool remount_system = PartitionManager.Is_Mounted_By_Path("/system"); + + operation_start("Toggle System Mount"); + if (!PartitionManager.UnMount_By_Path("/system", true)) { + op_status = 1; // fail + } else { + TWPartition* Part = PartitionManager.Find_Partition_By_Path("/system"); + if (Part) { + if (DataManager::GetIntValue("tw_mount_system_ro")) { + DataManager::SetValue("tw_mount_system_ro", 0); + Part->Change_Mount_Read_Only(false); + } else { + DataManager::SetValue("tw_mount_system_ro", 1); + Part->Change_Mount_Read_Only(true); + } + if (remount_system) { + Part->Mount(true); + } + op_status = 0; // success + } else { + op_status = 1; // fail + } + } + + operation_end(op_status); + return 0; +} diff --git a/gui/devices/1080x1920/res/ui.xml b/gui/devices/1080x1920/res/ui.xml index 3135a03dc..a611d0582 100644 --- a/gui/devices/1080x1920/res/ui.xml +++ b/gui/devices/1080x1920/res/ui.xml @@ -86,6 +86,7 @@ + diff --git a/gui/devices/320x320/res/ui.xml b/gui/devices/320x320/res/ui.xml index 5495b7717..1dec40504 100644 --- a/gui/devices/320x320/res/ui.xml +++ b/gui/devices/320x320/res/ui.xml @@ -174,6 +174,7 @@ + @@ -189,7 +190,7 @@ - + diff --git a/gui/devices/480x800/res/ui.xml b/gui/devices/480x800/res/ui.xml index 3c320a7eb..984454109 100644 --- a/gui/devices/480x800/res/ui.xml +++ b/gui/devices/480x800/res/ui.xml @@ -82,6 +82,7 @@ + diff --git a/gui/devices/landscape/res/landscape.xml b/gui/devices/landscape/res/landscape.xml index 25b9b17e7..12c66290b 100644 --- a/gui/devices/landscape/res/landscape.xml +++ b/gui/devices/landscape/res/landscape.xml @@ -989,6 +989,27 @@ + + + + + Only mount system read-only + + + + + + + + + Only mount system read-only + + + tw_lifetime_writes=2 + system_readonly_check + + + main @@ -1035,6 +1056,31 @@ + + + /system + + + + + + + + mount + + + + + + + + + tw_back=mount + system_readonly + + + + @@ -3596,5 +3642,57 @@ + + + + + + + TWRP has detected an unmodified system partition. + + + + + TWRP can leave your system partition unmodified to make it easier for you to take official updates. + + + + + TWRP will be unable to prevent the stock ROM from replacing TWRP and will not offer to root your device. + + + + + Installing zips or performing adb operations may still modify the system partition. + + + + + + Never show this screen during boot again + + + + + + Keep Read Only + + tw_mount_system_ro=1 + tw_page_done=1 + %tw_back% + + + + + Swipe to Allow Modifications + + tw_mount_system_ro=0 + tw_page_done=1 + %tw_back% + + + + + diff --git a/gui/devices/portrait/res/portrait.xml b/gui/devices/portrait/res/portrait.xml index bd235981d..997da9d23 100644 --- a/gui/devices/portrait/res/portrait.xml +++ b/gui/devices/portrait/res/portrait.xml @@ -2105,6 +2105,27 @@ decrypt + + + + + Only mount system read-only + + + + + + + + + Only mount system read-only + + + tw_lifetime_writes=2 + system_readonly_check + + + main @@ -2161,6 +2182,31 @@ + + + /system + + + + + + + + mount + + + + + + + + + tw_back=mount + system_readonly + + + + @@ -3607,5 +3653,72 @@ + + + + + + + TWRP has detected an unmodified system partition. + + + + + TWRP can leave your system partition unmodified + + + + + to make it easier for you to take official updates. + + + + + TWRP will be unable to prevent the stock ROM from + + + + + replacing TWRP and will not offer to root your device. + + + + + Installing zips or performing adb operations may still + + + + + modify the system partition. + + + + + + Never show this screen during boot again + + + + + + Keep Read Only + + tw_mount_system_ro=1 + tw_page_done=1 + %tw_back% + + + + + Swipe to Allow Modifications + + tw_mount_system_ro=0 + tw_page_done=1 + %tw_back% + + + + + diff --git a/gui/devices/watch/res/watch.xml b/gui/devices/watch/res/watch.xml index 872c47b6b..f0f383dcb 100644 --- a/gui/devices/watch/res/watch.xml +++ b/gui/devices/watch/res/watch.xml @@ -2113,6 +2113,27 @@ decrypt + + + + + Only mount system read-only + + + + + + + + + Only mount system read-only + + + tw_lifetime_writes=2 + system_readonly_check + + + main @@ -2168,6 +2189,31 @@ + + + /system + + + + + + + + mount + + + + + + + + + tw_back=mount + system_readonly + + + + @@ -3596,5 +3642,70 @@ + + + + + + + TWRP has detected an unmodified system partition. + + + + + TWRP can leave your system partition unmodified + + + + + to make it easier for you to take official updates. + + + + + TWRP will be unable to prevent the stock ROM from + + + + + replacing TWRP and will not offer to root your device. + + + + + Installing zips or performing adb operations may still + + + + + modify the system partition. + + + + + + Never show this screen during boot again + + + + + + Keep Read Only + + tw_mount_system_ro=1 + tw_page_done=1 + %tw_back% + + + + + Swipe to Allow Modifications + + tw_mount_system_ro=0 + tw_page_done=1 + %tw_back% + + + diff --git a/gui/objects.hpp b/gui/objects.hpp index e70053e3b..ee0f08b8f 100644 --- a/gui/objects.hpp +++ b/gui/objects.hpp @@ -359,6 +359,8 @@ protected: int stopmtp(std::string arg); int flashimage(std::string arg); int cancelbackup(std::string arg); + int checkpartitionlifetimewrites(std::string arg); + int mountsystemtoggle(std::string arg); int simulate; }; diff --git a/partition.cpp b/partition.cpp index 248ee9bc2..2f9f41a69 100644 --- a/partition.cpp +++ b/partition.cpp @@ -155,6 +155,7 @@ TWPartition::TWPartition() { Crypto_Key_Location = "footer"; MTP_Storage_ID = 0; Can_Flash_Img = false; + Mount_Read_Only = false; } TWPartition::~TWPartition(void) { @@ -258,6 +259,7 @@ bool TWPartition::Process_Fstab_Line(string Line, bool Display_Error) { Storage_Name = Display_Name; Wipe_Available_in_GUI = true; Can_Be_Backed_Up = true; + Mount_Read_Only = true; } else if (Mount_Point == "/data") { UnMount(false); // added in case /data is mounted as tmpfs for qcom hardware decrypt Display_Name = "Data"; @@ -390,6 +392,11 @@ bool TWPartition::Process_Fstab_Line(string Line, bool Display_Error) { Display_Name = "Recovery"; Backup_Display_Name = Display_Name; Can_Flash_Img = true; + } else if (Mount_Point == "/system_image") { + Display_Name = "System Image"; + Backup_Display_Name = Display_Name; + Can_Flash_Img = false; + Can_Be_Backed_Up = true; } } @@ -936,6 +943,7 @@ bool TWPartition::Is_Mounted(void) { bool TWPartition::Mount(bool Display_Error) { int exfat_mounted = 0; + unsigned long flags = Mount_Flags; if (Is_Mounted()) { return true; @@ -964,9 +972,15 @@ bool TWPartition::Mount(bool Display_Error) { #endif } } + + if (Mount_Read_Only) + flags |= MS_RDONLY; + if (Fstab_File_System == "yaffs2") { // mount an MTD partition as a YAFFS2 filesystem. - const unsigned long flags = MS_NOATIME | MS_NODEV | MS_NODIRATIME; + flags = MS_NOATIME | MS_NODEV | MS_NODIRATIME; + if (Mount_Read_Only) + flags |= MS_RDONLY; if (mount(Actual_Block_Device.c_str(), Mount_Point.c_str(), Fstab_File_System.c_str(), flags, NULL) < 0) { if (mount(Actual_Block_Device.c_str(), Mount_Point.c_str(), Fstab_File_System.c_str(), flags | MS_RDONLY, NULL) < 0) { if (Display_Error) @@ -1008,8 +1022,8 @@ bool TWPartition::Mount(bool Display_Error) { mount_fs = "texfat"; if (!exfat_mounted && - mount(Actual_Block_Device.c_str(), Mount_Point.c_str(), mount_fs.c_str(), Mount_Flags, Mount_Options.c_str()) != 0 && - mount(Actual_Block_Device.c_str(), Mount_Point.c_str(), mount_fs.c_str(), Mount_Flags, NULL) != 0) { + mount(Actual_Block_Device.c_str(), Mount_Point.c_str(), mount_fs.c_str(), flags, Mount_Options.c_str()) != 0 && + mount(Actual_Block_Device.c_str(), Mount_Point.c_str(), mount_fs.c_str(), flags, NULL) != 0) { #ifdef TW_NO_EXFAT_FUSE if (Current_File_System == "exfat") { LOGINFO("Mounting exfat failed, trying vfat...\n"); @@ -1018,7 +1032,7 @@ bool TWPartition::Mount(bool Display_Error) { LOGERR("Unable to mount '%s'\n", Mount_Point.c_str()); else LOGINFO("Unable to mount '%s'\n", Mount_Point.c_str()); - LOGINFO("Actual block device: '%s', current file system: '%s', flags: 0x%8x, options: '%s'\n", Actual_Block_Device.c_str(), Current_File_System.c_str(), Mount_Flags, Mount_Options.c_str()); + LOGINFO("Actual block device: '%s', current file system: '%s', flags: 0x%8x, options: '%s'\n", Actual_Block_Device.c_str(), Current_File_System.c_str(), flags, Mount_Options.c_str()); return false; } } else { @@ -2138,3 +2152,37 @@ bool TWPartition::Flash_Image_FI(string Filename) { TWFunc::Exec_Cmd(Command); return true; } + +void TWPartition::Change_Mount_Read_Only(bool new_value) { + Mount_Read_Only = new_value; +} + +int TWPartition::Check_Lifetime_Writes() { + bool original_read_only = Mount_Read_Only; + int ret = 1; + + Mount_Read_Only = true; + if (Mount(false)) { + Find_Actual_Block_Device(); + string block = basename(Actual_Block_Device.c_str()); + string file = "/sys/fs/" + Current_File_System + "/" + block + "/lifetime_write_kbytes"; + string result; + if (TWFunc::Path_Exists(file)) { + if (TWFunc::read_file(file, result) != 0) { + LOGINFO("Check_Lifetime_Writes of '%s' failed to read_file\n", file.c_str()); + } else { + LOGINFO("Check_Lifetime_Writes result: '%s'\n", result.c_str()); + if (result == "0") { + ret = 0; + } + } + } else { + LOGINFO("Check_Lifetime_Writes file does not exist '%s'\n", file.c_str()); + } + UnMount(true); + } else { + LOGINFO("Check_Lifetime_Writes failed to mount '%s'\n", Mount_Point.c_str()); + } + Mount_Read_Only = original_read_only; + return ret; +} diff --git a/partitionmanager.cpp b/partitionmanager.cpp index ffc17c3a4..055f73697 100644 --- a/partitionmanager.cpp +++ b/partitionmanager.cpp @@ -880,9 +880,13 @@ int TWPartitionManager::Run_Restore(string Restore_Name) { restore_path = Restore_List.substr(start_pos, end_pos - start_pos); restore_part = Find_Partition_By_Path(restore_path); if (restore_part != NULL) { - partition_count++; + if (restore_part->Mount_Read_Only) { + LOGERR("Cannot restore %s -- mounted read only.\n", restore_part->Backup_Display_Name.c_str()); + return false; + } if (check_md5 > 0 && !restore_part->Check_MD5(Restore_Name)) return false; + partition_count++; total_restore_size += restore_part->Get_Restore_Size(Restore_Name); if (restore_part->Has_SubPartition) { std::vector::iterator subpart; diff --git a/partitions.hpp b/partitions.hpp index f74fac9a1..1489a8ec2 100644 --- a/partitions.hpp +++ b/partitions.hpp @@ -70,6 +70,8 @@ public: bool Update_Size(bool Display_Error); // Updates size information void Recreate_Media_Folder(); // Recreates the /data/media folder bool Flash_Image(string Filename); // Flashes an image to the partition + void Change_Mount_Read_Only(bool new_value); // Changes Mount_Read_Only to new_value + int Check_Lifetime_Writes(); public: string Current_File_System; // Current file system @@ -167,6 +169,7 @@ private: bool Ignore_Blkid; // Ignore blkid results due to superblocks lying to us on certain devices / partitions bool Retain_Layout_Version; // Retains the .layout_version file during a wipe (needed on devices like Sony Xperia T where /data and /data/media are separate partitions) bool Can_Flash_Img; // Indicates if this partition can have images flashed to it via the GUI + bool Mount_Read_Only; // Only mount this partition as read-only friend class TWPartitionManager; friend class DataManager; diff --git a/twrp.cpp b/twrp.cpp index 0c012d7ec..b7fc9815d 100644 --- a/twrp.cpp +++ b/twrp.cpp @@ -332,13 +332,27 @@ int main(int argc, char **argv) { PartitionManager.Disable_MTP(); #endif + // Check if system has never been changed + if (DataManager::GetIntValue("tw_mount_system_ro") != 0 && DataManager::GetIntValue("tw_never_show_system_ro_page") == 0) { + TWPartition* sys = PartitionManager.Find_Partition_By_Path("/system"); + if (sys && sys->Check_Lifetime_Writes() == 0) { + LOGINFO("System writes is 0, show system_readonly page\n"); + DataManager::SetValue("tw_back", "main"); + if (gui_startPage("system_readonly", 1, 1) != 0) { + LOGERR("Failed to start system_readonly GUI page.\n"); + } + } else { + DataManager::SetValue("tw_mount_system_ro", 0); + } + } + // Launch the main GUI gui_start(); // Disable flashing of stock recovery TWFunc::Disable_Stock_Recovery_Replace(); // Check for su to see if the device is rooted or not - if (PartitionManager.Mount_By_Path("/system", false)) { + if (PartitionManager.Mount_By_Path("/system", false) && DataManager::GetIntValue("tw_mount_system_ro") == 0) { if (TWFunc::Path_Exists("/supersu/su") && !TWFunc::Path_Exists("/system/bin/su") && !TWFunc::Path_Exists("/system/xbin/su") && !TWFunc::Path_Exists("/system/bin/.ext/.su")) { // Device doesn't have su installed DataManager::SetValue("tw_busy", 1); -- cgit v1.2.3