diff --git a/module/jni/include/utils.hpp b/module/jni/include/utils.hpp index 7fc57e4..f8b86e5 100644 --- a/module/jni/include/utils.hpp +++ b/module/jni/include/utils.hpp @@ -4,6 +4,7 @@ #include #include "logging.hpp" #include "zygisk.hpp" +#include "mountinfo_parser.hpp" #define DCL_HOOK_FUNC(ret, func, ...) \ ret (*old_##func)(__VA_ARGS__) = nullptr; \ @@ -36,4 +37,5 @@ namespace Utils int isUserAppUID(int uid); bool hookPLTByName(zygisk::Api *api, const std::string &libName, const std::string &symbolName, void *hookFunc, void **origFunc); int forkAndInvoke(const std::function &lambda); + const char *getExtErrorsBehavior(const Parsers::mountinfo_entry &entry); } diff --git a/module/jni/modules.cpp b/module/jni/modules.cpp index 6107788..13f9e6d 100644 --- a/module/jni/modules.cpp +++ b/module/jni/modules.cpp @@ -93,28 +93,26 @@ void doRemount() if (mount.getMountPoint() == "/data") { const auto &superOptions = mount.getSuperOptions(); + if (!superOptions.contains("errors")) + break; + + // Remount /data only if errors behavior is not the same as superblock's + const char *sb_errors = Utils::getExtErrorsBehavior(mount); + if (!sb_errors || superOptions.at("errors") == sb_errors) + break; + const auto &mountOptions = mount.getMountOptions(); - - // If errors=remount-ro, remount it with errors=continue - if (superOptions.contains("errors") && superOptions.at("errors") == "remount-ro") + unsigned long flags = MS_REMOUNT; + for (const auto &flagName : mount_flags_procfs) { - unsigned long flags = MS_REMOUNT; - for (const auto &flagName : mount_flags_procfs) - { - if (mountOptions.contains(flagName.first)) - flags |= flagName.second; - } - - if (::mount(NULL, "/data", NULL, flags, "errors=continue") == 0) - { - LOGD("mount(NULL, \"/data\", NULL, 0x%lx, \"errors=continue\") returned 0", flags); - } - else - { - LOGW("mount(NULL, \"/data\", NULL, 0x%lx, \"errors=continue\") returned -1: %d (%s)", flags, errno, strerror(errno)); - } + if (mountOptions.contains(flagName.first)) + flags |= flagName.second; } + if (::mount(NULL, "/data", NULL, flags, (std::string("errors=") + sb_errors).c_str()) == 0) + LOGD("mount(NULL, \"/data\", NULL, 0x%lx, ...) returned 0", flags); + else + LOGW("mount(NULL, \"/data\", NULL, 0x%lx, ...) returned -1: %d (%s)", flags, errno, strerror(errno)); break; } } diff --git a/module/jni/utils.cpp b/module/jni/utils.cpp index e71794f..a3fc4d0 100644 --- a/module/jni/utils.cpp +++ b/module/jni/utils.cpp @@ -1,11 +1,13 @@ +#include #include +#include #include #include -#include #include #include #include #include +#include #include "map_parser.hpp" #include "utils.hpp" @@ -80,3 +82,48 @@ int Utils::forkAndInvoke(const std::function &lambda) waitpid(pid, &status, 0); return status; } + +constexpr off_t EXT_SUPERBLOCK_OFFSET = 0x400; +constexpr off_t EXT_MAGIC_OFFSET = 0x38; +constexpr off_t EXT_ERRORS_OFFSET = 0x3C; +constexpr uint16_t EXT_MAGIC = 0xEF53; + +const char *Utils::getExtErrorsBehavior(const Parsers::mountinfo_entry &entry) +{ + auto fs_type = entry.getFilesystemType(); + if (fs_type != "ext2" && fs_type != "ext3" && fs_type != "ext4") + return nullptr; + + std::ifstream file(entry.getMountSource(), std::ios::binary); + if (!file) + return nullptr; + + uint16_t magic; + file.seekg(EXT_SUPERBLOCK_OFFSET + EXT_MAGIC_OFFSET, std::ios::beg); + file.read(reinterpret_cast(&magic), sizeof(magic)); + if (!file || file.gcount() != sizeof(magic)) + return nullptr; + magic = le16toh(magic); + + if (magic != EXT_MAGIC) + return nullptr; + + uint16_t errors; + file.seekg(EXT_SUPERBLOCK_OFFSET + EXT_ERRORS_OFFSET, std::ios::beg); + file.read(reinterpret_cast(&errors), sizeof(errors)); + if (!file || file.gcount() != sizeof(errors)) + return nullptr; + errors = le16toh(errors); + + switch (errors) + { + case 1: + return "continue"; + case 2: + return "remount-ro"; + case 3: + return "panic"; + default: + return nullptr; + } +}