Remove usage of magisk.img

Mounting ext4 images causes tons of issues, such as unmountable with broken F2FS drivers.
Resizing is also very complicated and does not work properly on all devices.
Each step in either measuring free space, resizing, and shrinking the image is a
point of failure, and either step's failure could cause the module system completely broken.

The new method is to directly store modules into /data/adb/modules, and for module installation
on boot /data/adb/modules_update. Several compatibility layers has been done: the new path is
bind mounted to the old path (/sbin/.magisk/img), and the helper functions in util_functions.sh
will now transparently make existing modules install to the new location without any changes.

MagiskHide is also updated to unmount module files stored in this new location.
This commit is contained in:
topjohnwu 2019-02-12 02:14:57 -05:00
parent cfa28f0c4a
commit 1321f097b8
6 changed files with 84 additions and 125 deletions

View File

@ -19,12 +19,11 @@
#include <magisk.h> #include <magisk.h>
#include <db.h> #include <db.h>
#include <utils.h> #include <utils.h>
#include <img.h>
#include <daemon.h> #include <daemon.h>
#include <resetprop.h> #include <resetprop.h>
#include <selinux.h> #include <selinux.h>
#include <flags.h>
#include <logcat.h> #include <logcat.h>
#include <flags.h>
using namespace std; using namespace std;
@ -32,7 +31,7 @@ static char buf[PATH_MAX], buf2[PATH_MAX];
static vector<string> module_list; static vector<string> module_list;
static bool seperate_vendor; static bool seperate_vendor;
char *system_block, *vendor_block, *magiskloop; char *system_block, *vendor_block, *data_block;
static int bind_mount(const char *from, const char *to); static int bind_mount(const char *from, const char *to);
extern void auto_start_magiskhide(); extern void auto_start_magiskhide();
@ -135,7 +134,7 @@ void node_entry::create_module_tree(const char *module) {
struct dirent *entry; struct dirent *entry;
auto full_path = get_path(); auto full_path = get_path();
snprintf(buf, PATH_MAX, "%s/%s%s", MOUNTPOINT, module, full_path.c_str()); snprintf(buf, PATH_MAX, "%s/%s%s", MODULEROOT, module, full_path.c_str());
if (!(dir = xopendir(buf))) if (!(dir = xopendir(buf)))
return; return;
@ -169,7 +168,7 @@ void node_entry::create_module_tree(const char *module) {
node->status = IS_MODULE; node->status = IS_MODULE;
} else if (IS_DIR(node)) { } else if (IS_DIR(node)) {
// Check if marked as replace // Check if marked as replace
snprintf(buf2, PATH_MAX, "%s/%s%s/.replace", MOUNTPOINT, module, buf); snprintf(buf2, PATH_MAX, "%s/%s%s/.replace", MODULEROOT, module, buf);
if (access(buf2, F_OK) == 0) { if (access(buf2, F_OK) == 0) {
// Replace everything, mark as leaf // Replace everything, mark as leaf
node->status = IS_MODULE; node->status = IS_MODULE;
@ -236,7 +235,7 @@ void node_entry::clone_skeleton() {
continue; continue;
} else if (child->status & IS_MODULE) { } else if (child->status & IS_MODULE) {
// Mount from module file to dummy file // Mount from module file to dummy file
snprintf(buf2, PATH_MAX, "%s/%s%s/%s", MOUNTPOINT, snprintf(buf2, PATH_MAX, "%s/%s%s/%s", MODULEROOT,
child->module, full_path.c_str(), child->name.c_str()); child->module, full_path.c_str(), child->name.c_str());
} else if (child->status & (IS_SKEL | IS_INTER)) { } else if (child->status & (IS_SKEL | IS_INTER)) {
// It's an intermediate folder, recursive clone // It's an intermediate folder, recursive clone
@ -262,7 +261,7 @@ void node_entry::magic_mount() {
if (status & IS_MODULE) { if (status & IS_MODULE) {
// Mount module item // Mount module item
auto real_path = get_path(); auto real_path = get_path();
snprintf(buf, PATH_MAX, "%s/%s%s", MOUNTPOINT, module, real_path.c_str()); snprintf(buf, PATH_MAX, "%s/%s%s", MODULEROOT, module, real_path.c_str());
bind_mount(buf, real_path.c_str()); bind_mount(buf, real_path.c_str());
} else if (status & IS_SKEL) { } else if (status & IS_SKEL) {
// The node is labeled to be cloned with skeleton, lets do it // The node is labeled to be cloned with skeleton, lets do it
@ -338,7 +337,7 @@ static void exec_common_script(const char* stage) {
static void exec_module_script(const char* stage) { static void exec_module_script(const char* stage) {
for (const auto &m : module_list) { for (const auto &m : module_list) {
const auto module = m.c_str(); const auto module = m.c_str();
snprintf(buf2, PATH_MAX, "%s/%s/%s.sh", MOUNTPOINT, module, stage); snprintf(buf2, PATH_MAX, "%s/%s/%s.sh", MODULEROOT, module, stage);
if (access(buf2, F_OK) == -1) if (access(buf2, F_OK) == -1)
continue; continue;
LOGI("%s: exec [%s.sh]\n", module, stage); LOGI("%s: exec [%s.sh]\n", module, stage);
@ -418,18 +417,21 @@ static bool magisk_env() {
// Remove legacy stuffs // Remove legacy stuffs
unlink("/data/magisk.img"); unlink("/data/magisk.img");
unlink("/data/magisk_debug.log"); unlink("/data/magisk_debug.log");
unlink(SECURE_DIR "/magisk.img");
unlink(SECURE_DIR "/magisk_merge.img");
// Symlink for legacy path users // Legacy support
symlink(MAGISKTMP, "/sbin/.core"); symlink(MAGISKTMP, "/sbin/.core");
xmkdir(MAGISKTMP "/img", 0755);
// Create directories in tmpfs overlay // Create directories in tmpfs overlay
xmkdirs(MIRRDIR "/system", 0755); xmkdirs(MIRRDIR "/system", 0755);
xmkdir(MIRRDIR "/bin", 0755); xmkdir(MIRRDIR "/bin", 0755);
xmkdir(BBPATH, 0755); xmkdir(BBPATH, 0755);
xmkdir(MOUNTPOINT, 0755);
xmkdir(BLOCKDIR, 0755); xmkdir(BLOCKDIR, 0755);
// Boot script directories // /data/adb directories
xmkdir(MODULEROOT, 0755);
xmkdir(SECURE_DIR "/post-fs-data.d", 0755); xmkdir(SECURE_DIR "/post-fs-data.d", 0755);
xmkdir(SECURE_DIR "/service.d", 0755); xmkdir(SECURE_DIR "/service.d", 0755);
@ -454,6 +456,9 @@ static bool magisk_env() {
xmkdir(MIRRDIR "/vendor", 0755); xmkdir(MIRRDIR "/vendor", 0755);
xmount(vendor_block, MIRRDIR "/vendor", buf2, MS_RDONLY, nullptr); xmount(vendor_block, MIRRDIR "/vendor", buf2, MS_RDONLY, nullptr);
VLOGI("mount", vendor_block, MIRRDIR "/vendor"); VLOGI("mount", vendor_block, MIRRDIR "/vendor");
} else if (str_contains(line, " /data ")) {
sscanf(line.c_str(), "%s", buf);
data_block = strdup(buf);
} else if (SDK_INT >= 24 && } else if (SDK_INT >= 24 &&
str_contains(line, " /proc ") && !str_contains(line, "hidepid=2")) { str_contains(line, " /proc ") && !str_contains(line, "hidepid=2")) {
// Enforce hidepid // Enforce hidepid
@ -482,16 +487,43 @@ static bool magisk_env() {
return true; return true;
} }
static void upgrade_modules() {
DIR *dir;
struct dirent *entry;
if ((dir = opendir(MODULEUPGRADE))) {
while ((entry = xreaddir(dir))) {
if (entry->d_type == DT_DIR) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
// Cleanup old module if exists
snprintf(buf, sizeof(buf), "%s/%s", MODULEROOT, entry->d_name);
if (access(buf, F_OK) == 0)
rm_rf(buf);
LOGI("Upgrade / New module: %s\n", entry->d_name);
snprintf(buf2, sizeof(buf2), "%s/%s", MODULEUPGRADE, entry->d_name);
rename(buf2, buf);
}
}
closedir(dir);
rm_rf(MODULEUPGRADE);
}
// Legacy support
bind_mount(MODULEROOT, MAGISKTMP "/img");
xmkdir(LEGACYCORE, 0755);
symlink(SECURE_DIR "/post-fs-data.d", LEGACYCORE "/post-fs-data.d");
symlink(SECURE_DIR "/service.d", LEGACYCORE "/service.d");
}
static void collect_modules() { static void collect_modules() {
chdir(MOUNTPOINT); chdir(MODULEROOT);
rm_rf("lost+found");
DIR *dir = xopendir("."); DIR *dir = xopendir(".");
struct dirent *entry; struct dirent *entry;
while ((entry = xreaddir(dir))) { while ((entry = xreaddir(dir))) {
if (entry->d_type == DT_DIR) { if (entry->d_type == DT_DIR) {
if (strcmp(entry->d_name, ".") == 0 || if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0 || strcmp(entry->d_name, "..") == 0 ||
strcmp(entry->d_name, ".core") == 0 || strcmp(entry->d_name, ".core") == 0)
strcmp(entry->d_name, "lost+found") == 0)
continue; continue;
chdir(entry->d_name); chdir(entry->d_name);
if (access("remove", F_OK) == 0) { if (access("remove", F_OK) == 0) {
@ -510,47 +542,6 @@ static void collect_modules() {
chdir("/"); chdir("/");
} }
static bool prepare_img() {
const char *alt_img[] =
{ "/cache/magisk.img", "/data/magisk_merge.img", "/data/adb/magisk_merge.img" };
for (auto &alt : alt_img) {
if (merge_img(alt, MAINIMG)) {
LOGE("Image merge %s -> " MAINIMG " failed!\n", alt);
return false;
}
}
if (access(MAINIMG, F_OK) == -1) {
if (create_img(MAINIMG, 64))
return false;
}
LOGI("* Mounting " MAINIMG "\n");
magiskloop = mount_image(MAINIMG, MOUNTPOINT);
if (magiskloop == nullptr)
return false;
// Migrate legacy boot scripts
struct stat st;
if (lstat(LEGACY_CORE "/post-fs-data.d", &st) == 0 && S_ISDIR(st.st_mode)) {
cp_afc(LEGACY_CORE "/post-fs-data.d", SECURE_DIR "/post-fs-data.d");
rm_rf(LEGACY_CORE "/post-fs-data.d");
}
if (lstat(LEGACY_CORE "/service.d", &st) == 0 && S_ISDIR(st.st_mode)) {
cp_afc(LEGACY_CORE "/service.d", SECURE_DIR "/service.d");
rm_rf(LEGACY_CORE "/service.d");
}
// Links for legacy paths
xmkdir(LEGACY_CORE, 0755);
symlink(SECURE_DIR "/post-fs-data.d", LEGACY_CORE "/post-fs-data.d");
symlink(SECURE_DIR "/service.d", LEGACY_CORE "/service.d");
collect_modules();
return trim_img(MAINIMG, MOUNTPOINT, magiskloop) == 0;
}
static void install_apk(const char *apk) { static void install_apk(const char *apk) {
setfilecon(apk, "u:object_r:" SEPOL_FILE_DOMAIN ":s0"); setfilecon(apk, "u:object_r:" SEPOL_FILE_DOMAIN ":s0");
while (true) { while (true) {
@ -688,24 +679,20 @@ void post_fs_data(int client) {
start_logcat(); start_logcat();
// Run common scripts
LOGI("* Running post-fs-data.d scripts\n"); LOGI("* Running post-fs-data.d scripts\n");
exec_common_script("post-fs-data"); exec_common_script("post-fs-data");
upgrade_modules();
// Core only mode // Core only mode
if (access(DISABLEFILE, F_OK) == 0) if (access(DISABLEFILE, F_OK) == 0)
core_only(); core_only();
if (!prepare_img()) {
LOGE("* Magisk image mount failed, switch to core-only mode\n");
free(magiskloop);
magiskloop = nullptr;
creat(DISABLEFILE, 0644);
}
restorecon(); restorecon();
chmod(SECURE_DIR, 0700); chmod(SECURE_DIR, 0700);
collect_modules();
// Execute module scripts // Execute module scripts
LOGI("* Running module post-fs-data scripts\n"); LOGI("* Running module post-fs-data scripts\n");
exec_module_script("post-fs-data"); exec_module_script("post-fs-data");
@ -726,17 +713,17 @@ void post_fs_data(int client) {
for (const auto &m : module_list) { for (const auto &m : module_list) {
const auto module = m.c_str(); const auto module = m.c_str();
// Read props // Read props
snprintf(buf, PATH_MAX, "%s/%s/system.prop", MOUNTPOINT, module); snprintf(buf, PATH_MAX, "%s/%s/system.prop", MODULEROOT, module);
if (access(buf, F_OK) == 0) { if (access(buf, F_OK) == 0) {
LOGI("%s: loading [system.prop]\n", module); LOGI("%s: loading [system.prop]\n", module);
load_prop_file(buf, false); load_prop_file(buf, false);
} }
// Check whether enable auto_mount // Check whether enable auto_mount
snprintf(buf, PATH_MAX, "%s/%s/auto_mount", MOUNTPOINT, module); snprintf(buf, PATH_MAX, "%s/%s/auto_mount", MODULEROOT, module);
if (access(buf, F_OK) == -1) if (access(buf, F_OK) == -1)
continue; continue;
// Double check whether the system folder exists // Double check whether the system folder exists
snprintf(buf, PATH_MAX, "%s/%s/system", MOUNTPOINT, module); snprintf(buf, PATH_MAX, "%s/%s/system", MODULEROOT, module);
if (access(buf, F_OK) == -1) if (access(buf, F_OK) == -1)
continue; continue;
@ -744,9 +731,9 @@ void post_fs_data(int client) {
has_modules = true; has_modules = true;
LOGI("%s: constructing magic mount structure\n", module); LOGI("%s: constructing magic mount structure\n", module);
// If /system/vendor exists in module, create a link outside // If /system/vendor exists in module, create a link outside
snprintf(buf, PATH_MAX, "%s/%s/system/vendor", MOUNTPOINT, module); snprintf(buf, PATH_MAX, "%s/%s/system/vendor", MODULEROOT, module);
if (access(buf, F_OK) == 0) { if (access(buf, F_OK) == 0) {
snprintf(buf2, PATH_MAX, "%s/%s/vendor", MOUNTPOINT, module); snprintf(buf2, PATH_MAX, "%s/%s/vendor", MODULEROOT, module);
unlink(buf2); unlink(buf2);
xsymlink(buf, buf2); xsymlink(buf, buf2);
} }

View File

@ -18,16 +18,18 @@
#define BLOCKDIR MAGISKTMP "/block" #define BLOCKDIR MAGISKTMP "/block"
#define MIRRDIR MAGISKTMP "/mirror" #define MIRRDIR MAGISKTMP "/mirror"
#define BBPATH MAGISKTMP "/busybox" #define BBPATH MAGISKTMP "/busybox"
#define MOUNTPOINT MAGISKTMP "/img"
#define LEGACY_CORE MOUNTPOINT "/.core"
#define SECURE_DIR "/data/adb" #define SECURE_DIR "/data/adb"
#define MAINIMG SECURE_DIR "/magisk.img" #define MODULEROOT SECURE_DIR "/modules"
#define MODULEUPGRADE SECURE_DIR "/modules_update"
#define DATABIN SECURE_DIR "/magisk" #define DATABIN SECURE_DIR "/magisk"
#define MAGISKDB SECURE_DIR "/magisk.db" #define MAGISKDB SECURE_DIR "/magisk.db"
#define SIMPLEMOUNT SECURE_DIR "/magisk_simple" #define SIMPLEMOUNT SECURE_DIR "/magisk_simple"
#define BOOTCOUNT SECURE_DIR "/.boot_count" #define BOOTCOUNT SECURE_DIR "/.boot_count"
#define MANAGERAPK DATABIN "/magisk.apk" #define MANAGERAPK DATABIN "/magisk.apk"
// Legacy crap
#define LEGACYCORE MODULEROOT "/.core"
// selinux consts // selinux consts
#define SELINUX_PATH "/sys/fs/selinux" #define SELINUX_PATH "/sys/fs/selinux"
#define SELINUX_ENFORCE SELINUX_PATH "/enforce" #define SELINUX_ENFORCE SELINUX_PATH "/enforce"

View File

@ -233,7 +233,7 @@ int rm_list(int client) {
return ret; return ret;
} }
#define LEGACY_LIST MOUNTPOINT "/.core/hidelist" #define LEGACY_LIST MODULEROOT "/.core/hidelist"
static int collect_list(void *, int, char **data, char**) { static int collect_list(void *, int, char **data, char**) {
LOGI("hide_list: [%s]\n", data[0]); LOGI("hide_list: [%s]\n", data[0]);

View File

@ -26,7 +26,7 @@
using namespace std; using namespace std;
extern char *system_block, *vendor_block, *magiskloop; extern char *system_block, *vendor_block, *data_block;
// Workaround for the lack of pthread_cancel // Workaround for the lack of pthread_cancel
static void term_thread(int) { static void term_thread(int) {
@ -91,10 +91,10 @@ static void hide_daemon(int pid) {
// Re-read mount infos // Re-read mount infos
mounts = file_to_vector("mounts"); mounts = file_to_vector("mounts");
// Unmount everything under /system, /vendor, and loop mounts // Unmount everything under /system, /vendor, and data mounts
for (auto &s : mounts) { for (auto &s : mounts) {
if ((str_contains(s, " /system/") || str_contains(s, " /vendor/")) && if ((str_contains(s, " /system/") || str_contains(s, " /vendor/")) &&
(str_contains(s, system_block) || str_contains(s, vendor_block) || str_contains(s, magiskloop))) { (str_contains(s, system_block) || str_contains(s, vendor_block) || str_contains(s, data_block))) {
sscanf(s.c_str(), "%*s %4096s", buffer); sscanf(s.c_str(), "%*s %4096s", buffer);
lazy_unmount(buffer); lazy_unmount(buffer);
} }

View File

@ -162,7 +162,8 @@ void restorecon() {
if (write(fd, ADB_CON, sizeof(ADB_CON)) >= 0) if (write(fd, ADB_CON, sizeof(ADB_CON)) >= 0)
lsetfilecon(SECURE_DIR, ADB_CON); lsetfilecon(SECURE_DIR, ADB_CON);
close(fd); close(fd);
fd = xopen(MOUNTPOINT, O_RDONLY | O_CLOEXEC); lsetfilecon(MODULEROOT, MAGISK_CON);
fd = xopen(MODULEROOT, O_RDONLY | O_CLOEXEC);
restore_syscon(fd); restore_syscon(fd);
close(fd); close(fd);
fd = xopen(DATABIN, O_RDONLY | O_CLOEXEC); fd = xopen(DATABIN, O_RDONLY | O_CLOEXEC);

View File

@ -52,7 +52,8 @@ abort() {
resolve_vars() { resolve_vars() {
MAGISKBIN=$NVBASE/magisk MAGISKBIN=$NVBASE/magisk
IMG=$NVBASE/magisk.img POSTFSDATAD=$NVBASE/post-fs-data.d
SERVICED=$NVBASE/service.d
} }
###################### ######################
@ -351,7 +352,9 @@ find_manager_apk() {
set_perm() { set_perm() {
chown $2:$3 $1 || return 1 chown $2:$3 $1 || return 1
chmod $4 $1 || return 1 chmod $4 $1 || return 1
[ -z $5 ] && chcon 'u:object_r:system_file:s0' $1 || chcon $5 $1 || return 1 CON=$5
[ -z $CON ] && CON=u:object_r:system_file:s0
chcon $CON $1 || return 1
} }
set_perm_recursive() { set_perm_recursive() {
@ -370,64 +373,30 @@ mktouch() {
} }
request_size_check() { request_size_check() {
reqSizeM=`du -ms $1 | cut -f1` reqSizeM=`du -ms "$1" | cut -f1`
} }
request_zip_size_check() { request_zip_size_check() {
reqSizeM=`unzip -l "$1" | tail -n 1 | awk '{ print int(($1 - 1) / 1048576 + 1) }'` reqSizeM=`unzip -l "$1" | tail -n 1 | awk '{ print int(($1 - 1) / 1048576 + 1) }'`
} }
check_filesystem() {
curSizeM=`wc -c < $1`
curSizeM=$((curSizeM / 1048576))
local DF=`df -Pk $2 | grep $2`
curUsedM=`echo $DF | awk '{ print int($3 / 1024) }'`
curFreeM=`echo $DF | awk '{ print int($4 / 1024) }'`
}
mount_snippet() {
MAGISKLOOP=`$MAGISKBIN/magisk imgtool mount $IMG $MOUNTPATH`
is_mounted $MOUNTPATH || abort "! $IMG mount failed..."
}
mount_magisk_img() {
[ -z $reqSizeM ] && reqSizeM=0
mkdir -p $MOUNTPATH 2>/dev/null
if [ -f "$IMG" ]; then
ui_print "- Found $IMG"
mount_snippet
check_filesystem $IMG $MOUNTPATH
if [ $reqSizeM -gt $curFreeM ]; then
newSizeM=$(((curSizeM + reqSizeM - curFreeM) / 32 * 32 + 64))
ui_print "- Resizing $IMG to ${newSizeM}M"
$MAGISKBIN/magisk imgtool umount $MOUNTPATH $MAGISKLOOP
$MAGISKBIN/magisk imgtool resize $IMG $newSizeM >&2
mount_snippet
fi
ui_print "- Mount $IMG to $MOUNTPATH"
else
newSizeM=$((reqSizeM / 32 * 32 + 64))
ui_print "- Creating $IMG with size ${newSizeM}M"
$MAGISKBIN/magisk imgtool create $IMG $newSizeM >&2
mount_snippet
fi
}
unmount_magisk_img() {
check_filesystem $IMG $MOUNTPATH
newSizeM=$((curUsedM / 32 * 32 + 64))
$MAGISKBIN/magisk imgtool umount $MOUNTPATH $MAGISKLOOP
if [ $curSizeM -gt $newSizeM ]; then
ui_print "- Shrinking $IMG to ${newSizeM}M"
$MAGISKBIN/magisk imgtool resize $IMG $newSizeM >&2
fi
}
################################## ##################################
# Backwards Compatibile Functions # Backwards Compatibile Functions
################################## ##################################
get_outfd() { setup_flashable; } get_outfd() { setup_flashable; }
mount_magisk_img() {
$BOOTMODE && MODULE_BASE=modules_update || MODULE_BASE=modules
MODULEPATH=$NVBASE/$MODULE_BASE
mkdir -p $MODULEPATH 2>/dev/null
ln -s $MODULEPATH $MOUNTPATH
}
unmount_magisk_img() {
rm -f $MODULEPATH 2>/dev/null
}
####### #######
# main # main
####### #######