diff --git a/native/jni/Android.mk b/native/jni/Android.mk index a1b21d1b7..498edda1e 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -61,6 +61,7 @@ LOCAL_SRC_FILES := \ init/rootdir.cpp \ init/getinfo.cpp \ init/twostage.cpp \ + core/socket.cpp \ magiskpolicy/api.cpp \ magiskpolicy/magiskpolicy.cpp \ magiskpolicy/rules.cpp \ diff --git a/native/jni/core/bootstages.cpp b/native/jni/core/bootstages.cpp index a0c664978..24564c2f4 100644 --- a/native/jni/core/bootstages.cpp +++ b/native/jni/core/bootstages.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -19,7 +20,6 @@ using namespace std; -static char buf[PATH_MAX], buf2[PATH_MAX]; static vector module_list; static bool no_secure_dir = false; static bool pfs_done = false; @@ -74,7 +74,6 @@ private: string get_path(); void insert(node_entry *&); void clone_skeleton(); - int get_path(char *path); }; bool node_entry::vendor_root = false; @@ -97,16 +96,12 @@ bool node_entry::is_root() { } string node_entry::get_path() { - get_path(buf); - return buf; -} - -int node_entry::get_path(char *path) { - int len = 0; + string path; if (parent) - len = parent->get_path(path); - len += sprintf(path + len, "/%s", name.c_str()); - return len; + path = parent->get_path(); + path += "/"; + path += name; + return path; } void node_entry::insert(node_entry *&node) { @@ -129,9 +124,9 @@ void node_entry::insert(node_entry *&node) { void node_entry::create_module_tree(const char *module) { auto full_path = get_path(); - snprintf(buf, PATH_MAX, "%s/%s%s", MODULEROOT, module, full_path.c_str()); + auto cwd = MODULEROOT + "/"s + module + full_path; - auto dir = xopen_dir(buf); + auto dir = xopen_dir(cwd.data()); if (!dir) return; @@ -139,7 +134,7 @@ void node_entry::create_module_tree(const char *module) { if (faccessat(dirfd(dir.get()), ".replace", F_OK, 0) == 0) { if (is_root()) { // Root nodes should not be replaced - rm_rf(buf); + rm_rf(cwd.data()); } else if (status < IS_MODULE) { // Upgrade current node to current module this->module = module; @@ -154,9 +149,8 @@ void node_entry::create_module_tree(const char *module) { // Create new node auto node = new node_entry(this, module, entry->d_name, entry->d_type); - // buf = real path, buf2 = module path - snprintf(buf, PATH_MAX, "%s/%s", full_path.c_str(), entry->d_name); - snprintf(buf2, PATH_MAX, MODULEROOT "/%s%s/%s", module, full_path.c_str(), entry->d_name); + auto dest = full_path + "/" + entry->d_name; + auto src = cwd + "/" + entry->d_name; /* * Clone current directory in one of the following conditions: @@ -165,17 +159,17 @@ void node_entry::create_module_tree(const char *module) { * - Target file is a symlink (exclude special nodes) */ bool clone = false; - if (IS_LNK(node) || access(buf, F_OK) != 0) { + if (IS_LNK(node) || access(dest.data(), F_OK) != 0) { clone = true; } else if (!node->is_special()) { struct stat s; - xlstat(buf, &s); + xlstat(dest.data(), &s); if (S_ISLNK(s.st_mode)) clone = true; } if (clone && is_root()) { // Root nodes should not be cloned - rm_rf(buf2); + rm_rf(src.data()); delete node; continue; } @@ -189,7 +183,7 @@ void node_entry::create_module_tree(const char *module) { node->status = IS_INTER; } else { // Clone attributes from real path - clone_attr(buf, buf2); + clone_attr(dest.data(), src.data()); if (IS_DIR(node)) { // First mark as an intermediate node node->status = IS_INTER; @@ -209,8 +203,9 @@ void node_entry::create_module_tree(const char *module) { void node_entry::clone_skeleton() { // Clone the structure auto full_path = get_path(); - snprintf(buf, PATH_MAX, "%s%s", MIRRDIR, full_path.data()); - if (auto dir = xopen_dir(buf); dir) { + auto mirror_path = MAGISKTMP + "/" MIRRDIR + full_path; + + if (auto dir = xopen_dir(mirror_path.data()); dir) { for (dirent *entry; (entry = xreaddir(dir.get()));) { if (entry->d_name == "."sv || entry->d_name == ".."sv) continue; @@ -222,42 +217,41 @@ void node_entry::clone_skeleton() { if (status & IS_SKEL) { file_attr attr; - getattr(full_path.c_str(), &attr); - LOGI("mnt_tmpfs : %s\n", full_path.c_str()); - xmount("tmpfs", full_path.c_str(), "tmpfs", 0, nullptr); - setattr(full_path.c_str(), &attr); + getattr(full_path.data(), &attr); + LOGI("mnt_tmpfs : %s\n", full_path.data()); + xmount("tmpfs", full_path.data(), "tmpfs", 0, nullptr); + setattr(full_path.data(), &attr); } for (auto &child : children) { - snprintf(buf, PATH_MAX, "%s/%s", full_path.c_str(), child->name.c_str()); + auto dest = full_path + "/" + child->name; + string src; // Create the dummy file/directory if (IS_DIR(child)) - xmkdir(buf, 0755); + xmkdir(dest.data(), 0755); else if (IS_REG(child)) - close(creat(buf, 0644)); + close(creat(dest.data(), 0644)); // Links will be handled later if (child->status & IS_MODULE) { // Mount from module file to dummy file - snprintf(buf2, PATH_MAX, "%s/%s%s/%s", MODULEMNT, - child->module, full_path.c_str(), child->name.c_str()); + src = MAGISKTMP + "/" MODULEMNT "/" + child->module + full_path + "/" + child->name; } else if (child->status & (IS_SKEL | IS_INTER)) { // It's an intermediate folder, recursive clone child->clone_skeleton(); continue; } else if (child->status & IS_DUMMY) { // Mount from mirror to dummy file - snprintf(buf2, PATH_MAX, "%s%s/%s", MIRRDIR, full_path.c_str(), child->name.c_str()); + src = MAGISKTMP + "/" MIRRDIR + full_path + "/" + child->name; } if (IS_LNK(child)) { // Copy symlinks directly - cp_afc(buf2, buf); - VLOGI("copy_link ", buf2, buf); + cp_afc(src.data(), dest.data()); + VLOGI("copy_link ", src.data(), dest.data()); } else { - snprintf(buf, PATH_MAX, "%s/%s", full_path.c_str(), child->name.c_str()); - bind_mount(buf2, buf); + bind_mount(src.data(), dest.data()); } } } @@ -265,9 +259,9 @@ void node_entry::clone_skeleton() { void node_entry::magic_mount() { if (status & IS_MODULE) { // Mount module item - auto real_path = get_path(); - snprintf(buf, PATH_MAX, "%s/%s%s", MODULEMNT, module, real_path.c_str()); - bind_mount(buf, real_path.c_str()); + auto dest = get_path(); + auto src = MAGISKTMP + "/" MODULEMNT "/" + module + dest; + bind_mount(src.data(), dest.data()); } else if (status & IS_SKEL) { // The node is labeled to be cloned with skeleton, lets do it clone_skeleton(); @@ -302,16 +296,19 @@ static int bind_mount(const char *from, const char *to, bool log) { return ret; } -#define MIRRMNT(part) MIRRDIR "/" #part -#define PARTBLK(part) BLOCKDIR "/" #part -#define DIR_IS(part) (me->mnt_dir == "/" #part ""sv) + +#define DIR_IS(part) (me->mnt_dir == "/" #part ""sv) +#define SETMIR(b, part) sprintf(b, "%s/" MIRRDIR "/" #part, MAGISKTMP.data()) +#define SETBLK(b, part) sprintf(b, "%s/" BLOCKDIR "/" #part, MAGISKTMP.data()) #define mount_mirror(part, flag) { \ xstat(me->mnt_fsname, &st); \ - mknod(PARTBLK(part), (st.st_mode & S_IFMT) | 0600, st.st_rdev); \ - xmkdir(MIRRMNT(part), 0755); \ - xmount(PARTBLK(part), MIRRMNT(part), me->mnt_type, flag, nullptr); \ - VLOGI("mount", PARTBLK(part), MIRRMNT(part)); \ + SETMIR(buf1, part); \ + SETBLK(buf2, part); \ + mknod(buf2, (st.st_mode & S_IFMT) | 0600, st.st_rdev); \ + xmkdir(buf1, 0755); \ + xmount(buf2, buf1, me->mnt_type, flag, nullptr); \ + VLOGI("mount", buf2, buf1); \ } static bool magisk_env() { @@ -320,11 +317,13 @@ static bool magisk_env() { string pkg; check_manager(&pkg); - char install_dir[128]; - sprintf(install_dir, "%s/0/%s/install", APP_DATA_DIR, pkg.data()); + char buf1[4096]; + char buf2[4096]; + + sprintf(buf1, "%s/0/%s/install", APP_DATA_DIR, pkg.data()); // Alternative binaries paths - const char *alt_bin[] = { "/cache/data_adb/magisk", "/data/magisk", install_dir }; + const char *alt_bin[] = { "/cache/data_adb/magisk", "/data/magisk", buf1 }; for (auto alt : alt_bin) { struct stat st; if (lstat(alt, &st) != -1) { @@ -348,14 +347,11 @@ static bool magisk_env() { unlink("/data/magisk_merge.img"); unlink("/data/magisk_debug.log"); - // Directories in tmpfs overlay - xmkdir(MIRRDIR, 0); - xmkdir(BLOCKDIR, 0); - xmkdir(BBPATH, 0755); - xmkdir(MODULEMNT, 0755); - - // Backwards compatibility for old Magisk Manager - xsymlink("./modules", MAGISKTMP "/img"); + sprintf(buf1, "%s/" MODULEMNT, MAGISKTMP.data()); + xmkdir(buf1, 0755); + // TODO: Remove. Backwards compatibility for old manager + sprintf(buf1, "%s/" INTLROOT "/img", MAGISKTMP.data()); + xsymlink("./modules", buf1); // Directories in /data/adb xmkdir(DATABIN, 0755); @@ -369,8 +365,9 @@ static bool magisk_env() { parse_mnt("/proc/mounts", [&](mntent *me) { if (DIR_IS(system_root)) { mount_mirror(system_root, MS_RDONLY); - xsymlink("./system_root/system", MIRRMNT(system)); - VLOGI("link", MIRRMNT(system_root) "/system", MIRRMNT(system)); + SETMIR(buf1, system); + xsymlink("./system_root/system", buf1); + VLOGI("link", "./system_root/system", buf1); system_as_root = true; } else if (!system_as_root && DIR_IS(system)) { mount_mirror(system, MS_RDONLY); @@ -385,18 +382,22 @@ static bool magisk_env() { } return true; }); - if (access(MIRRMNT(system), F_OK) != 0 && access(MIRRMNT(system_root), F_OK) == 0) { + SETMIR(buf1, system); + SETMIR(buf2, system_root); + if (access(buf1, F_OK) != 0 && access(buf2, F_OK) == 0) { // Pre-init mirrors - xsymlink("./system_root/system", MIRRMNT(system)); - VLOGI("link", MIRRMNT(system_root) "/system", MIRRMNT(system)); + xsymlink("./system_root/system", buf1); + VLOGI("link", "./system_root/system", buf1); } - if (access(MIRRMNT(vendor), F_OK) != 0) { - xsymlink("./system/vendor", MIRRMNT(vendor)); - VLOGI("link", MIRRMNT(system) "/vendor", MIRRMNT(vendor)); + SETMIR(buf1, vendor); + if (access(buf1, F_OK) != 0) { + xsymlink("./system/vendor", buf1); + VLOGI("link", "./system/vendor", buf1); } - if (access("/system/product", F_OK) == 0 && access(MIRRMNT(product), F_OK) != 0) { - xsymlink("./system/product", MIRRMNT(product)); - VLOGI("link", MIRRMNT(system) "/product", MIRRMNT(product)); + SETMIR(buf1, product); + if (access("/system/product", F_OK) == 0 && access(buf1, F_OK) != 0) { + xsymlink("./system/product", buf1); + VLOGI("link", "./system/product", buf1); } // Disable/remove magiskhide, resetprop @@ -407,9 +408,13 @@ static bool magisk_env() { if (access(DATABIN "/busybox", X_OK) == -1) return false; - LOGI("* Setting up internal busybox"); - cp_afc(DATABIN "/busybox", BBPATH "/busybox"); - exec_command_sync(BBPATH "/busybox", "--install", "-s", BBPATH); + + // TODO: Remove. Backwards compatibility for old manager + LOGI("* Setting up internal busybox\n"); + sprintf(buf1, "%s/" BBPATH "/busybox", MAGISKTMP.data()); + mkdir(dirname(buf1), 0755); + cp_afc(DATABIN "/busybox", buf1); + exec_command_sync(buf1, "--install", "-s", dirname(buf1)); return true; } @@ -417,22 +422,27 @@ static bool magisk_env() { static void prepare_modules() { // Upgrade modules if (auto dir = open_dir(MODULEUPGRADE); dir) { + int ufd = dirfd(dir.get()); + int mfd = xopen(MODULEROOT, O_RDONLY | O_CLOEXEC); for (dirent *entry; (entry = xreaddir(dir.get()));) { if (entry->d_type == DT_DIR) { if (entry->d_name == "."sv || entry->d_name == ".."sv) 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); + if (faccessat(mfd, entry->d_name, F_OK, 0) == 0) { + frm_rf(xopenat(mfd, entry->d_name, O_RDONLY | O_CLOEXEC)); + unlinkat(mfd, entry->d_name, AT_REMOVEDIR); + } LOGI("Upgrade / New module: %s\n", entry->d_name); - snprintf(buf2, sizeof(buf2), "%s/%s", MODULEUPGRADE, entry->d_name); - rename(buf2, buf); + renameat(ufd, entry->d_name, mfd, entry->d_name); } } + close(mfd); rm_rf(MODULEUPGRADE); } - bind_mount(MIRRDIR MODULEROOT, MODULEMNT, false); + auto src = MAGISKTMP + "/" MIRRDIR "/" MODULEROOT; + auto dest = MAGISKTMP + "/" MODULEMNT; + bind_mount(src.data(), dest.data(), false); restorecon(); chmod(SECURE_DIR, 0700); @@ -475,9 +485,9 @@ static void collect_modules() { if (faccessat(modfd, "remove", F_OK, 0) == 0) { LOGI("%s: remove\n", entry->d_name); - fd_pathat(modfd, "uninstall.sh", buf, sizeof(buf)); - if (access(buf, F_OK) == 0) - exec_script(buf); + auto uninstaller = MODULEROOT + "/"s + entry->d_name + "/uninstall.sh"; + if (access(uninstaller.data(), F_OK) == 0) + exec_script(uninstaller.data()); frm_rf(xdup(modfd)); unlinkat(dfd, entry->d_name, AT_REMOVEDIR); continue; @@ -492,51 +502,56 @@ static void collect_modules() { } static bool load_modules(node_entry *root) { - LOGI("* Loading modules\n"); + char buf1[4096]; + char buf2[4096]; + LOGI("* Loading modules\n"); bool has_modules = false; for (const auto &m : module_list) { - const auto module = m.data(); - char *name = buf + snprintf(buf, sizeof(buf), MODULEROOT "/%s/", module); + auto module = m.data(); + char *b1 = buf1 + sprintf(buf1, MODULEROOT "/%s/", module); // Read props - strcpy(name, "system.prop"); - if (access(buf, F_OK) == 0) { + strcpy(b1, "system.prop"); + if (access(buf1, F_OK) == 0) { LOGI("%s: loading [system.prop]\n", module); - load_prop_file(buf, false); + load_prop_file(buf1, false); } + // Copy sepolicy rules - strcpy(name, "sepolicy.rule"); - if (access(MIRRDIR "/persist", F_OK) == 0 && access(buf, F_OK) == 0) { - char *p = buf2 + snprintf(buf2, sizeof(buf2), MIRRDIR "/persist/magisk/%s", module); + strcpy(b1, "sepolicy.rule"); + char *b2 = buf2 + sprintf(buf2, "%s/" MIRRDIR "/persist", MAGISKTMP.data()); + if (access(buf2, F_OK) == 0 && access(buf1, F_OK) == 0) { + b2 += sprintf(b2, "/magisk/%s", module); xmkdirs(buf2, 0755); - strcpy(p, "/sepolicy.rule"); - cp_afc(buf, buf2); + strcpy(b2, "/sepolicy.rule"); + cp_afc(buf1, buf2); } // Check whether skip mounting - strcpy(name, "skip_mount"); - if (access(buf, F_OK) == 0) + strcpy(b1, "skip_mount"); + if (access(buf1, F_OK) == 0) continue; + // Double check whether the system folder exists - strcpy(name, "system"); - if (access(buf, F_OK) != 0) + strcpy(b1, "system"); + if (access(buf1, F_OK) != 0) continue; // Construct structure has_modules = true; LOGI("%s: constructing magic mount structure\n", module); // If /system/vendor exists in module, create a link outside - strcpy(name, "system/vendor"); - if (node_entry::vendor_root && access(buf, F_OK) == 0) { - snprintf(buf2, sizeof(buf2), "%s/%s/vendor", MODULEROOT, module); + strcpy(b1, "system/vendor"); + if (node_entry::vendor_root && access(buf1, F_OK) == 0) { + sprintf(buf2, MODULEROOT "/%s/vendor", module); unlink(buf2); xsymlink("./system/vendor", buf2); } // If /system/product exists in module, create a link outside - strcpy(name, "system/product"); - if (node_entry::product_root && access(buf, F_OK) == 0) { - snprintf(buf2, sizeof(buf2), "%s/%s/product", MODULEROOT, module); + strcpy(b1, "system/product"); + if (node_entry::product_root && access(buf1, F_OK) == 0) { + sprintf(buf2, MODULEROOT "/%s/product", module); unlink(buf2); xsymlink("./system/product", buf2); } @@ -729,14 +744,6 @@ void late_start(int client) { if (!pfs_done) return; - if (access(BBPATH, F_OK) != 0){ - LOGE("* post-fs-data mode is not triggered\n"); - unlock_blocks(); - magisk_env(); - prepare_modules(); - close(xopen(DISABLEFILE, O_RDONLY | O_CREAT | O_CLOEXEC, 0)); - } - auto_start_magiskhide(); LOGI("* Running service.d scripts\n"); diff --git a/native/jni/core/daemon.cpp b/native/jni/core/daemon.cpp index 940dfc7c1..f38583c12 100644 --- a/native/jni/core/daemon.cpp +++ b/native/jni/core/daemon.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -16,8 +17,11 @@ #include #include +using namespace std; + int SDK_INT = -1; bool RECOVERY_MODE = false; +string MAGISKTMP; static struct stat self_st; static void verify_client(int client, pid_t pid) { @@ -91,6 +95,10 @@ static void *request_handler(void *args) { } close(client); break; + case GET_PATH: + write_string(client, MAGISKTMP.data()); + close(client); + break; default: close(client); break; @@ -114,11 +122,19 @@ static void main_daemon() { setsid(); setcon("u:r:" SEPOL_PROC_DOMAIN ":s0"); + + // Get self stat + char path[4096]; + xreadlink("/proc/self/exe", path, sizeof(path)); + MAGISKTMP = dirname(path); + xstat("/proc/self/exe", &self_st); + restore_rootcon(); // Unmount pre-init patches - if (access(ROOTMNT, F_OK) == 0) { - file_readline(true, ROOTMNT, [](auto line) -> bool { + auto mount_list = MAGISKTMP + "/" ROOTMNT; + if (access(mount_list.data(), F_OK) == 0) { + file_readline(true, mount_list.data(), [](string_view line) -> bool { umount2(line.data(), MNT_DETACH); return true; }); @@ -126,9 +142,6 @@ static void main_daemon() { LOGI(NAME_WITH_VER(Magisk) " daemon started\n"); - // Get server stat - stat("/proc/self/exe", &self_st); - // Get API level parse_prop_file("/system/build.prop", [](auto key, auto val) -> bool { if (key == "ro.build.version.sdk") { @@ -148,7 +161,8 @@ static void main_daemon() { } // Load config status - parse_prop_file(MAGISKTMP "/config", [](auto key, auto val) -> bool { + auto config = MAGISKTMP + "/" INTLROOT "/config"; + parse_prop_file(config.data(), [](auto key, auto val) -> bool { if (key == "RECOVERYMODE" && val == "true") RECOVERY_MODE = true; return true; diff --git a/native/jni/core/magisk.cpp b/native/jni/core/magisk.cpp index 0c9d0e32d..418778098 100644 --- a/native/jni/core/magisk.cpp +++ b/native/jni/core/magisk.cpp @@ -37,7 +37,7 @@ Advanced Options (Internal APIs): --clone-attr SRC DEST clone permission, owner, and selinux context --clone SRC DEST clone SRC to DEST --sqlite SQL exec SQL commands to Magisk database - --path print internal tmpfs mount path + --path print Magisk tmpfs mount path Available applets: )EOF"); @@ -116,8 +116,10 @@ int magisk_main(int argc, char *argv[]) { write_int(fd, REMOVE_MODULES); return read_int(fd); } else if (argv[1] == "--path"sv) { - // TODO: hardcode /sbin for now, actual logic will be used for Android 11 - printf("/sbin\n"); + int fd = connect_daemon(); + write_int(fd, GET_PATH); + char *path = read_string(fd); + printf("%s\n", path); return 0; } #if 0 diff --git a/native/jni/core/restorecon.cpp b/native/jni/core/restorecon.cpp index 204cbc1d1..c64af5892 100644 --- a/native/jni/core/restorecon.cpp +++ b/native/jni/core/restorecon.cpp @@ -81,20 +81,17 @@ void restorecon() { } void restore_rootcon() { - setfilecon("/sbin", ROOT_CON); - setfilecon(MAGISKTMP, ROOT_CON); - setfilecon(MIRRDIR, ROOT_CON); - setfilecon(BLOCKDIR, ROOT_CON); + setfilecon(MAGISKTMP.data(), ROOT_CON); - auto dir = xopen_dir("/sbin"); + auto dir = xopen_dir(MAGISKTMP.data()); int dfd = dirfd(dir.get()); for (dirent *entry; (entry = xreaddir(dir.get()));) { if (entry->d_name == "."sv || entry->d_name == ".."sv) continue; - setfilecon_at(dfd, entry->d_name, ROOT_CON); + if (entry->d_name == "magisk"sv || entry->d_name == "magiskinit"sv) + setfilecon_at(dfd, entry->d_name, MAGISK_CON); + else + setfilecon_at(dfd, entry->d_name, ROOT_CON); } - - setfilecon("/sbin/magisk", MAGISK_CON); - setfilecon("/sbin/magiskinit", MAGISK_CON); } diff --git a/native/jni/core/socket.cpp b/native/jni/core/socket.cpp index 9dc654615..cdde5e5a4 100644 --- a/native/jni/core/socket.cpp +++ b/native/jni/core/socket.cpp @@ -1,12 +1,9 @@ -/* socket.c - All socket related operations - */ - #include #include #include #include -#include +#include #include #include diff --git a/native/jni/include/daemon.hpp b/native/jni/include/daemon.hpp index c346a809e..f231a178b 100644 --- a/native/jni/include/daemon.hpp +++ b/native/jni/include/daemon.hpp @@ -1,11 +1,11 @@ #pragma once #include -#include -#include #include #include +#include + // Commands require connecting to daemon enum { DO_NOTHING = 0, @@ -18,6 +18,7 @@ enum { MAGISKHIDE, SQLITE_CMD, REMOVE_MODULES, + GET_PATH, }; // Return codes for daemon @@ -32,25 +33,6 @@ enum { int connect_daemon(bool create = false); -// socket.cpp - -socklen_t setup_sockaddr(struct sockaddr_un *sun, const char *name); -int create_rand_socket(struct sockaddr_un *sun); -int socket_accept(int sockfd, int timeout); -void get_client_cred(int fd, struct ucred *cred); -int recv_fd(int sockfd); -void send_fd(int sockfd, int fd); -int read_int(int fd); -int read_int_be(int fd); -void write_int(int fd, int val); -void write_int_be(int fd, int val); -char *read_string(int fd); -char *read_string_be(int fd); -void write_string(int fd, const char *val); -void write_string_be(int fd, const char *val); -void write_key_value(int fd, const char *key, const char *val); -void write_key_token(int fd, const char *key, int tok); - /*************** * Boot Stages * ***************/ diff --git a/native/jni/include/magisk.hpp b/native/jni/include/magisk.hpp index dcffd7110..af338e372 100644 --- a/native/jni/include/magisk.hpp +++ b/native/jni/include/magisk.hpp @@ -1,19 +1,13 @@ #pragma once #include +#include #define MAIN_SOCKET "d30138f2310a9fb9c54a3e0c21f58591" #define JAVA_PACKAGE_NAME "com.topjohnwu.magisk" #define LOGFILE "/cache/magisk.log" #define UNBLOCKFILE "/dev/.magisk_unblock" #define DISABLEFILE "/cache/.disable_magisk" -#define MAGISKTMP "/sbin/.magisk" -#define MIRRDIR MAGISKTMP "/mirror" -#define BLOCKDIR MAGISKTMP "/block" -#define BBPATH MAGISKTMP "/busybox" -#define MODULEMNT MAGISKTMP "/modules" -#define ROOTOVL MAGISKTMP "/rootdir" -#define ROOTMNT ROOTOVL "/.mount_list" #define SECURE_DIR "/data/adb" #define MODULEROOT SECURE_DIR "/modules" #define MODULEUPGRADE SECURE_DIR "/modules_update" @@ -21,6 +15,16 @@ #define MAGISKDB SECURE_DIR "/magisk.db" #define MANAGERAPK DATABIN "/magisk.apk" +// tmpfs paths +extern std::string MAGISKTMP; +#define INTLROOT ".magisk" +#define MIRRDIR INTLROOT "/mirror" +#define BLOCKDIR INTLROOT "/block" +#define MODULEMNT INTLROOT "/modules" +#define BBPATH INTLROOT "/busybox" +#define ROOTOVL INTLROOT "/rootdir" +#define ROOTMNT ROOTOVL "/.mount_list" + constexpr const char *applet_names[] = { "su", "resetprop", "magiskhide", nullptr }; // Multi-call entrypoints diff --git a/native/jni/include/socket.hpp b/native/jni/include/socket.hpp new file mode 100644 index 000000000..8d15c7d6f --- /dev/null +++ b/native/jni/include/socket.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +socklen_t setup_sockaddr(struct sockaddr_un *sun, const char *name); +int create_rand_socket(struct sockaddr_un *sun); +int socket_accept(int sockfd, int timeout); +void get_client_cred(int fd, struct ucred *cred); +int recv_fd(int sockfd); +void send_fd(int sockfd, int fd); +int read_int(int fd); +int read_int_be(int fd); +void write_int(int fd, int val); +void write_int_be(int fd, int val); +char *read_string(int fd); +char *read_string_be(int fd); +void write_string(int fd, const char *val); +void write_string_be(int fd, const char *val); +void write_key_value(int fd, const char *key, const char *val); +void write_key_token(int fd, const char *key, int tok); diff --git a/native/jni/init/init.hpp b/native/jni/init/init.hpp index 4a5992458..23b6382df 100644 --- a/native/jni/init/init.hpp +++ b/native/jni/init/init.hpp @@ -5,7 +5,7 @@ #include #include -#include +#include struct cmdline { bool skip_initramfs; @@ -57,26 +57,25 @@ public: class MagiskInit : public BaseInit { protected: raw_data self; - const char *persist_dir; + std::string persist_dir; virtual void early_mount() = 0; bool patch_sepolicy(const char *file = "/sepolicy"); public: - MagiskInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}; + MagiskInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {} }; class SARBase : public MagiskInit { protected: raw_data config; std::vector overlays; + std::string tmp_dir; void backup_files(); void patch_rootdir(); void mount_system_root(); public: - SARBase(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) { - persist_dir = MIRRDIR "/persist/magisk"; - } + SARBase(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {} void start() override { early_mount(); patch_rootdir(); @@ -92,7 +91,9 @@ class ForcedFirstStageInit : public BaseInit { private: void prepare(); public: - ForcedFirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}; + ForcedFirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) { + LOGD("%s\n", __FUNCTION__); + }; void start() override { prepare(); exec_init("/system/bin/init"); @@ -103,7 +104,9 @@ class FirstStageInit : public BaseInit { private: void prepare(); public: - FirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}; + FirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) { + LOGD("%s\n", __FUNCTION__); + }; void start() override { prepare(); exec_init(); @@ -116,7 +119,9 @@ private: protected: void early_mount() override; public: - SARFirstStageInit(char *argv[], cmdline *cmd) : SARBase(argv, cmd) {}; + SARFirstStageInit(char *argv[], cmdline *cmd) : SARBase(argv, cmd) { + LOGD("%s\n", __FUNCTION__); + }; void start() override { early_mount(); traced_exec_init(); @@ -128,7 +133,9 @@ protected: void early_mount() override; void cleanup() override { /* Do not do any cleanup */ } public: - SecondStageInit(char *argv[]) : SARBase(argv, nullptr) {}; + SecondStageInit(char *argv[]) : SARBase(argv, nullptr) { + LOGD("%s\n", __FUNCTION__); + }; }; /* *********** @@ -139,7 +146,9 @@ class SARInit : public SARBase { protected: void early_mount() override; public: - SARInit(char *argv[], cmdline *cmd) : SARBase(argv, cmd) {}; + SARInit(char *argv[], cmdline *cmd) : SARBase(argv, cmd) { + LOGD("%s\n", __FUNCTION__); + }; }; /* ********** @@ -148,13 +157,12 @@ public: class RootFSInit : public MagiskInit { private: - int root = -1; void setup_rootfs(); protected: void early_mount() override; public: RootFSInit(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) { - persist_dir = "/dev/mnt/persist/magisk"; + LOGD("%s\n", __FUNCTION__); } void start() override { @@ -164,9 +172,10 @@ public: } }; +#define INIT_SOCKET "MAGISKINIT" + void load_kernel_info(cmdline *cmd); int dump_magisk(const char *path, mode_t mode); int magisk_proxy_main(int argc, char *argv[]); void setup_klog(); -void mount_sbin(); -socklen_t setup_sockaddr(struct sockaddr_un *sun); +void setup_tmp(const char *path, const raw_data &self, const raw_data &config); diff --git a/native/jni/init/mount.cpp b/native/jni/init/mount.cpp index 82bae2ba2..73887e00d 100644 --- a/native/jni/init/mount.cpp +++ b/native/jni/init/mount.cpp @@ -175,7 +175,6 @@ void RootFSInit::early_mount() { full_read("/init", self.buf, self.sz); LOGD("Reverting /init\n"); - root = xopen("/", O_RDONLY | O_CLOEXEC); rename("/.backup/init", "/init"); mount_root(system); @@ -186,7 +185,7 @@ void RootFSInit::early_mount() { xmkdir("/dev/mnt", 0755); mount_persist("/dev/block", "/dev/mnt"); mount_list.emplace_back("/dev/mnt/persist"); - mount_list.emplace_back("/dev/mnt/cache"); + persist_dir = "/dev/mnt/persist/magisk"; } void SARBase::backup_files() { @@ -261,13 +260,45 @@ void BaseInit::cleanup() { mount_list.shrink_to_fit(); } -void mount_sbin() { - LOGD("Mount /sbin tmpfs overlay\n"); - xmount("tmpfs", "/sbin", "tmpfs", 0, "mode=755"); +static void patch_socket_name(const char *path) { + char *buf; + size_t size; + mmap_rw(path, buf, size); + for (int i = 0; i < size; ++i) { + if (memcmp(buf + i, MAIN_SOCKET, sizeof(MAIN_SOCKET)) == 0) { + gen_rand_str(buf + i, 16); + i += sizeof(MAIN_SOCKET); + } + } + munmap(buf, size); +} - xmkdir(MAGISKTMP, 0755); +void setup_tmp(const char *path, const raw_data &self, const raw_data &config) { + LOGD("Setup Magisk tmp at %s\n", path); + xmount("tmpfs", path, "tmpfs", 0, "mode=755"); + + chdir(path); + + xmkdir(INTLROOT, 0755); xmkdir(MIRRDIR, 0); xmkdir(BLOCKDIR, 0); mount_persist(BLOCKDIR, MIRRDIR); + + int fd = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0); + xwrite(fd, config.buf, config.sz); + close(fd); + fd = xopen("magiskinit", O_WRONLY | O_CREAT, 0755); + xwrite(fd, self.buf, self.sz); + close(fd); + dump_magisk("magisk", 0755); + patch_socket_name("magisk"); + + // Create applet symlinks + for (int i = 0; applet_names[i]; ++i) + xsymlink("./magisk", applet_names[i]); + xsymlink("./magiskinit", "magiskpolicy"); + xsymlink("./magiskinit", "supolicy"); + + chdir("/"); } diff --git a/native/jni/init/rootdir.cpp b/native/jni/init/rootdir.cpp index 632fab0d6..212f37b64 100644 --- a/native/jni/init/rootdir.cpp +++ b/native/jni/init/rootdir.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "init.hpp" #include "magiskrc.inc" @@ -18,19 +19,6 @@ using namespace std; -static void patch_socket_name(const char *path) { - char *buf; - size_t size; - mmap_rw(path, buf, size); - for (int i = 0; i < size; ++i) { - if (memcmp(buf + i, MAIN_SOCKET, sizeof(MAIN_SOCKET)) == 0) { - gen_rand_str(buf + i, 16); - i += sizeof(MAIN_SOCKET); - } - } - munmap(buf, size); -} - static vector rc_list; static void patch_init_rc(FILE *rc) { @@ -153,15 +141,14 @@ bool MagiskInit::patch_sepolicy(const char *file) { sepol_allow(SEPOL_PROC_DOMAIN, ALL, ALL, ALL); // Custom rules - if (auto dir = xopen_dir(persist_dir); dir) { - char path[4096]; + if (auto dir = xopen_dir(persist_dir.data()); dir) { for (dirent *entry; (entry = xreaddir(dir.get()));) { if (entry->d_name == "."sv || entry->d_name == ".."sv) continue; - snprintf(path, sizeof(path), "%s/%s/sepolicy.rule", persist_dir, entry->d_name); - if (access(path, R_OK) == 0) { - LOGD("Loading custom sepolicy patch: %s\n", path); - load_rule_file(path); + auto rule = persist_dir + "/" + entry->d_name + "/sepolicy.rule"; + if (access(rule.data(), R_OK) == 0) { + LOGD("Loading custom sepolicy patch: %s\n", rule.data()); + load_rule_file(rule.data()); } } } @@ -178,30 +165,6 @@ bool MagiskInit::patch_sepolicy(const char *file) { return patch_init; } -static void sbin_overlay(const raw_data &self, const raw_data &config) { - mount_sbin(); - - // Dump binaries - xmkdir(MAGISKTMP, 0755); - int fd = xopen(MAGISKTMP "/config", O_WRONLY | O_CREAT, 0000); - xwrite(fd, config.buf, config.sz); - close(fd); - fd = xopen("/sbin/magiskinit", O_WRONLY | O_CREAT, 0755); - xwrite(fd, self.buf, self.sz); - close(fd); - dump_magisk("/sbin/magisk", 0755); - patch_socket_name("/sbin/magisk"); - - // Create applet symlinks - char path[64]; - for (int i = 0; applet_names[i]; ++i) { - sprintf(path, "/sbin/%s", applet_names[i]); - xsymlink("./magisk", path); - } - xsymlink("./magiskinit", "/sbin/magiskpolicy"); - xsymlink("./magiskinit", "/sbin/supolicy"); -} - static void recreate_sbin(const char *mirror, bool use_bind_mount) { auto dp = xopen_dir(mirror); int src = dirfd(dp.get()); @@ -233,12 +196,6 @@ static void recreate_sbin(const char *mirror, bool use_bind_mount) { } } -#define ROOTMIR MIRRDIR "/system_root" -#define ROOTBLK BLOCKDIR "/system_root" -#define MONOPOLICY "/sepolicy" -#define PATCHPOLICY "/sbin/.se" -#define LIBSELINUX "/system/" LIBNAME "/libselinux.so" - static string magic_mount_list; static void magic_mount(const string &sdir, const string &ddir = "") { @@ -262,8 +219,20 @@ static void magic_mount(const string &sdir, const string &ddir = "") { } } +#define ROOTMIR MIRRDIR "/system_root" +#define ROOTBLK BLOCKDIR "/system_root" +#define MONOPOLICY "/sepolicy" +#define PATCHPOLICY "/sbin/.se" +#define LIBSELINUX "/system/" LIBNAME "/libselinux.so" + void SARBase::patch_rootdir() { - sbin_overlay(self, config); + // TODO: dynamic paths + tmp_dir = "/sbin"; + + setup_tmp(tmp_dir.data(), self, config); + persist_dir = tmp_dir + "/" MIRRDIR "/persist"; + + chdir(tmp_dir.data()); // Mount system_root mirror struct stat st; @@ -273,8 +242,9 @@ void SARBase::patch_rootdir() { if (xmount(ROOTBLK, ROOTMIR, "ext4", MS_RDONLY, nullptr)) xmount(ROOTBLK, ROOTMIR, "erofs", MS_RDONLY, nullptr); - // Recreate original sbin structure - recreate_sbin(ROOTMIR "/sbin", true); + // Recreate original sbin structure if necessary + if (tmp_dir == "/sbin") + recreate_sbin(ROOTMIR "/sbin", true); // Patch init raw_data init; @@ -332,20 +302,21 @@ void SARBase::patch_rootdir() { patch_sepolicy(PATCHPOLICY); // Handle overlay - struct sockaddr_un sun{}; - socklen_t len = setup_sockaddr(&sun); - int socketfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (connect(socketfd, (struct sockaddr*) &sun, len) == 0) { + struct sockaddr_un sun; + int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (connect(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET)) == 0) { LOGD("ACK init tracer to write backup files\n"); + // Let tracer know where tmp_dir is + write_string(sockfd, tmp_dir.data()); + // Wait for tracer to finish copying files int ack; - // Wait for init tracer finish copying files - read(socketfd, &ack, sizeof(ack)); + read(sockfd, &ack, sizeof(ack)); } else { LOGD("Restore backup files locally\n"); restore_folder(ROOTOVL, overlays); overlays.clear(); } - close(socketfd); + close(sockfd); if (access(ROOTOVL "/sbin", F_OK) == 0) { file_attr a; getattr("/sbin", &a); @@ -362,9 +333,11 @@ void SARBase::patch_rootdir() { // Mount rootdir magic_mount(ROOTOVL); - dest = xopen(ROOTMNT, O_WRONLY | O_CREAT | O_CLOEXEC); + dest = xopen(ROOTMNT, O_WRONLY | O_CREAT | O_CLOEXEC, 0); write(dest, magic_mount_list.data(), magic_mount_list.length()); close(dest); + + chdir("/"); } int magisk_proxy_main(int argc, char *argv[]) { @@ -381,7 +354,7 @@ int magisk_proxy_main(int argc, char *argv[]) { unlink("/sbin/magisk"); rm_rf("/.backup"); - sbin_overlay(self, config); + setup_tmp("/sbin", self, config); // Create symlinks pointing back to /root recreate_sbin("/root", false); diff --git a/native/jni/init/twostage.cpp b/native/jni/init/twostage.cpp index 8fecbef4f..4c8c6f633 100644 --- a/native/jni/init/twostage.cpp +++ b/native/jni/init/twostage.cpp @@ -1,8 +1,10 @@ #include #include +#include #include #include +#include #include "init.hpp" @@ -103,14 +105,6 @@ static inline long xptrace(int request, pid_t pid, void *addr = nullptr, intptr_ return xptrace(request, pid, addr, reinterpret_cast(data)); } -#define INIT_SOCKET "MAGISKINIT" - -socklen_t setup_sockaddr(struct sockaddr_un *sun) { - sun->sun_family = AF_LOCAL; - strcpy(sun->sun_path + 1, INIT_SOCKET); - return sizeof(sa_family_t) + sizeof(INIT_SOCKET); -} - void SARFirstStageInit::traced_exec_init() { int pid = getpid(); @@ -132,11 +126,6 @@ void SARFirstStageInit::traced_exec_init() { // Re-exec init exec_init(); } else { - // Close all file descriptors and stop logging - no_logging(); - for (int i = 0; i < 20; ++i) - close(i); - // Attach to parent to trace exec xptrace(PTRACE_ATTACH, pid); waitpid(pid, nullptr, __WALL | __WNOTHREAD); @@ -155,18 +144,22 @@ void SARFirstStageInit::traced_exec_init() { xumount2("/dev", MNT_DETACH); // Establish socket for 2nd stage ack - struct sockaddr_un sun{}; + struct sockaddr_un sun; int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); - xbind(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun)); + xbind(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET)); xlisten(sockfd, 1); + // Resume init xptrace(PTRACE_DETACH, pid); // Wait for second stage ack int client = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC); // Write backup files - int cfg = xopen(MAGISKTMP "/config", O_WRONLY | O_CREAT, 0000); + char *tmp_dir = read_string(client); + chdir(tmp_dir); + free(tmp_dir); + int cfg = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0); xwrite(cfg, config.buf, config.sz); close(cfg); restore_folder(ROOTOVL, overlays);