From 0c99c4d93f638d5cde9a232321af791c54be278b Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 3 May 2020 22:49:54 -0700 Subject: [PATCH] More complete support for fstab in dt --- native/jni/init/getinfo.cpp | 10 ++- native/jni/init/init.hpp | 39 +++++++--- native/jni/init/mount.cpp | 144 +++++++++++++++++++++--------------- native/jni/init/rootdir.cpp | 58 +++++++-------- native/jni/utils/files.cpp | 7 +- native/jni/utils/misc.cpp | 8 -- native/jni/utils/misc.hpp | 1 - 7 files changed, 151 insertions(+), 116 deletions(-) diff --git a/native/jni/init/getinfo.cpp b/native/jni/init/getinfo.cpp index 4a36300a4..c30c1f3da 100644 --- a/native/jni/init/getinfo.cpp +++ b/native/jni/init/getinfo.cpp @@ -12,11 +12,9 @@ using namespace std; -#define DEFAULT_DT_DIR "/proc/device-tree/firmware/android" - static void parse_cmdline(const std::function &fn) { char cmdline[4096]; - int fd = open("/proc/cmdline", O_RDONLY | O_CLOEXEC); + int fd = xopen("/proc/cmdline", O_RDONLY | O_CLOEXEC); cmdline[read(fd, cmdline, sizeof(cmdline))] = '\0'; close(fd); @@ -125,7 +123,10 @@ void load_kernel_info(cmdline *cmd) { } else if (key == "enter_recovery") { enter_recovery = value[0] == '1'; } else if (key == "androidboot.hardware") { + strcpy(cmd->hardware, value); kirin = strstr(value, "kirin") || strstr(value, "hi3660") || strstr(value, "hi6250"); + } else if (key == "androidboot.hardware.platform") { + strcpy(cmd->hardware_plat, value); } }); @@ -154,8 +155,11 @@ void load_kernel_info(cmdline *cmd) { if (cmd->dt_dir[0] == '\0') strcpy(cmd->dt_dir, DEFAULT_DT_DIR); + LOGD("Device info:\n"); LOGD("skip_initramfs=[%d]\n", cmd->skip_initramfs); LOGD("force_normal_boot=[%d]\n", cmd->force_normal_boot); LOGD("slot=[%s]\n", cmd->slot); LOGD("dt_dir=[%s]\n", cmd->dt_dir); + LOGD("hardware=[%s]\n", cmd->hardware); + LOGD("hardware.platform=[%s]\n", cmd->hardware_plat); } diff --git a/native/jni/init/init.hpp b/native/jni/init/init.hpp index 0f4f67a25..038112f40 100644 --- a/native/jni/init/init.hpp +++ b/native/jni/init/init.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -11,7 +12,9 @@ struct cmdline { bool skip_initramfs; bool force_normal_boot; char slot[3]; - char dt_dir[128]; + char dt_dir[64]; + char hardware[32]; + char hardware_plat[32]; }; struct raw_data { @@ -31,6 +34,30 @@ struct raw_data { } }; +struct fstab_entry { + std::string dev; + std::string mnt_point; + std::string type; + std::string mnt_flags; + std::string fsmgr_flags; + + fstab_entry() = default; + fstab_entry(const fstab_entry &o) = delete; + fstab_entry(fstab_entry &&o) = default; +}; + +#define INIT_SOCKET "MAGISKINIT" +#define DEFAULT_DT_DIR "/proc/device-tree/firmware/android" + +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 setup_tmp(const char *path, const raw_data &self, const raw_data &config); + +using str_pairs = std::initializer_list>; +int raw_data_patch(void *addr, size_t sz, str_pairs list); + /*************** * Base classes ***************/ @@ -52,6 +79,8 @@ public: cmd(cmd), argv(argv), mount_list{"/sys", "/proc"} {} virtual ~BaseInit() = default; virtual void start() = 0; + void read_dt_fstab(std::map &fstab); + void dt_early_mount(); }; class MagiskInit : public BaseInit { @@ -158,11 +187,3 @@ public: exec_init(); } }; - -#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 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 8e65d6b80..fe2c49f30 100644 --- a/native/jni/init/mount.cpp +++ b/native/jni/init/mount.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -21,10 +22,6 @@ struct devinfo { static vector dev_list; -static char partname[32]; -static char fstype[32]; -static char block_dev[64]; - static void parse_device(devinfo *dev, const char *uevent) { dev->partname[0] = '\0'; parse_prop_file(uevent, [=](string_view key, string_view value) -> bool { @@ -55,6 +52,11 @@ static void collect_devices() { } } +static struct { + char partname[32]; + char block_dev[64]; +} blk_info; + static int64_t setup_block(bool write_block = true) { if (dev_list.empty()) collect_devices(); @@ -63,13 +65,13 @@ static int64_t setup_block(bool write_block = true) { for (int tries = 0; tries < 3; ++tries) { for (auto &dev : dev_list) { - if (strcasecmp(dev.partname, partname) == 0) { + if (strcasecmp(dev.partname, blk_info.partname) == 0) { if (write_block) { - sprintf(block_dev, "/dev/block/%s", dev.devname); + sprintf(blk_info.block_dev, "/dev/block/%s", dev.devname); } - LOGD("Found %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor); + LOGD("Setup %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor); dev_t rdev = makedev(dev.major, dev.minor); - mknod(block_dev, S_IFBLK | 0600, rdev); + mknod(blk_info.block_dev, S_IFBLK | 0600, rdev); return rdev; } } @@ -90,35 +92,69 @@ static bool is_lnk(const char *name) { return S_ISLNK(st.st_mode); } -static bool read_dt_fstab(cmdline *cmd, const char *name) { - char path[128]; - int fd; - sprintf(path, "%s/fstab/%s/dev", cmd->dt_dir, name); - if ((fd = open(path, O_RDONLY | O_CLOEXEC)) >= 0) { - read(fd, path, sizeof(path)); - close(fd); - path[strcspn(path, "\r\n")] = '\0'; - // Some custom treble use different names, so use what we read - char *part = rtrim(strrchr(path, '/') + 1); - sprintf(partname, "%s%s", part, strend(part, cmd->slot) ? cmd->slot : ""); - sprintf(path, "%s/fstab/%s/type", cmd->dt_dir, name); - if ((fd = xopen(path, O_RDONLY | O_CLOEXEC)) >= 0) { - read(fd, fstype, 32); - close(fd); - fstype[strcspn(fstype, "\r\n")] = '\0'; - return true; - } - } - return false; +static string rtrim(string &&str) { + // Trim space, newline, and null byte from end of string + while (memchr(" \n\r", str[str.length() - 1], 4)) + str.pop_back(); + return std::move(str); } -#define mount_root(name) \ -if (!is_lnk("/" #name) && read_dt_fstab(cmd, #name)) { \ - LOGD("Early mount " #name "\n"); \ - setup_block(); \ - xmkdir("/" #name, 0755); \ - xmount(block_dev, "/" #name, fstype, MS_RDONLY, nullptr); \ - mount_list.emplace_back("/" #name); \ +#define read_info(val) \ +if (access(#val, F_OK) == 0) {\ + entry.val = rtrim(full_read(#val)); \ +} + +void BaseInit::read_dt_fstab(map &fstab) { + if (access(cmd->dt_dir, F_OK) != 0) + return; + chdir(cmd->dt_dir); + run_finally cr([]{ chdir("/"); }); + + if (access("fstab", F_OK) != 0) + return; + chdir("fstab"); + + auto dir = xopen_dir("."); + for (dirent *dp; (dp = xreaddir(dir.get()));) { + if (dp->d_type != DT_DIR) + continue; + chdir(dp->d_name); + run_finally f([]{ chdir(".."); }); + + if (access("status", F_OK) == 0) { + auto status = rtrim(full_read("status")); + if (status != "okay" && status != "ok") + continue; + } + + fstab_entry entry; + + read_info(dev); + read_info(mnt_point) else { + entry.mnt_point = "/"; + entry.mnt_point += dp->d_name; + } + read_info(type); + read_info(mnt_flags); + read_info(fsmgr_flags); + + fstab.emplace(entry.mnt_point, std::move(entry)); + } +} + +void BaseInit::dt_early_mount() { + map fstab; + read_dt_fstab(fstab); + for (const auto &[_, entry] : fstab) { + if (is_lnk(entry.mnt_point.data())) + continue; + // Derive partname from dev + sprintf(blk_info.partname, "%s%s", basename(entry.dev.data()), cmd->slot); + setup_block(); + xmkdir(entry.mnt_point.data(), 0755); + xmount(blk_info.block_dev, entry.mnt_point.data(), entry.type.data(), MS_RDONLY, nullptr); + mount_list.push_back(entry.mnt_point); + } } static void switch_root(const string &path) { @@ -152,17 +188,17 @@ static void switch_root(const string &path) { static void mount_persist(const char *dev_base, const char *mnt_base) { string mnt_point = mnt_base + "/persist"s; - strcpy(partname, "persist"); - xrealpath(dev_base, block_dev); - char *s = block_dev + strlen(block_dev); + strcpy(blk_info.partname, "persist"); + xrealpath(dev_base, blk_info.block_dev); + char *s = blk_info.block_dev + strlen(blk_info.block_dev); strcpy(s, "/persist"); if (setup_block(false) < 0) { // Fallback to cache - strcpy(partname, "cache"); + strcpy(blk_info.partname, "cache"); strcpy(s, "/cache"); if (setup_block(false) < 0) { // Try NVIDIA's BS - strcpy(partname, "CAC"); + strcpy(blk_info.partname, "CAC"); if (setup_block(false) < 0) return; } @@ -170,19 +206,16 @@ static void mount_persist(const char *dev_base, const char *mnt_base) { mnt_point = mnt_base + "/cache"s; } xmkdir(mnt_point.data(), 0755); - xmount(block_dev, mnt_point.data(), "ext4", 0, nullptr); + xmount(blk_info.block_dev, mnt_point.data(), "ext4", 0, nullptr); } void RootFSInit::early_mount() { full_read("/init", self.buf, self.sz); - LOGD("Reverting /init\n"); + LOGD("Restoring /init\n"); rename("/.backup/init", "/init"); - mount_root(system); - mount_root(vendor); - mount_root(product); - mount_root(odm); + dt_early_mount(); xmkdir("/dev/mnt", 0755); mount_persist("/dev/block", "/dev/mnt"); @@ -201,12 +234,12 @@ void SARBase::backup_files() { void SARBase::mount_system_root() { LOGD("Early mount system_root\n"); - sprintf(partname, "system%s", cmd->slot); - strcpy(block_dev, "/dev/root"); + sprintf(blk_info.partname, "system%s", cmd->slot); + strcpy(blk_info.block_dev, "/dev/root"); auto dev = setup_block(false); if (dev < 0) { // Try NVIDIA naming scheme - strcpy(partname, "APP"); + strcpy(blk_info.partname, "APP"); dev = setup_block(false); if (dev < 0) { // We don't really know what to do at this point... @@ -230,9 +263,7 @@ void SARInit::early_mount() { mount_system_root(); switch_root("/system_root"); - mount_root(vendor); - mount_root(product); - mount_root(odm); + dt_early_mount(); } void SARFirstStageInit::early_mount() { @@ -262,15 +293,12 @@ void BaseInit::cleanup() { } static void patch_socket_name(const char *path) { + char rstr[16]; + gen_rand_str(rstr, sizeof(rstr)); 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); - } - } + raw_data_patch(buf, size, { make_pair(MAIN_SOCKET, rstr) }); munmap(buf, size); } diff --git a/native/jni/init/rootdir.cpp b/native/jni/init/rootdir.cpp index 08eb285fe..1a098a0d3 100644 --- a/native/jni/init/rootdir.cpp +++ b/native/jni/init/rootdir.cpp @@ -81,19 +81,28 @@ static void load_overlay_rc(const char *overlay) { } } +int raw_data_patch(void *addr, size_t sz, str_pairs list) { + int count = 0; + for (uint8_t *p = (uint8_t *)addr, *eof = (uint8_t *)addr + sz; p < eof; ++p) { + for (auto &[from, to] : list) { + if (memcmp(p, from.data(), from.length() + 1) == 0) { + LOGD("Replace [%s] -> [%s]\n", from.data(), to.data()); + memset(p, 0, from.length()); + memcpy(p, to.data(), to.length()); + ++count; + p += from.length(); + } + } + } + return count; +} + void RootFSInit::setup_rootfs() { if (patch_sepolicy("/sepolicy")) { char *addr; size_t size; mmap_rw("/init", addr, size); - for (char *p = addr; p < addr + size; ++p) { - if (memcmp(p, SPLIT_PLAT_CIL, sizeof(SPLIT_PLAT_CIL)) == 0) { - // Force init to load /sepolicy - LOGD("Remove from init: " SPLIT_PLAT_CIL "\n"); - memset(p, 'x', sizeof(SPLIT_PLAT_CIL) - 1); - break; - } - } + raw_data_patch(addr, size, {make_pair(SPLIT_PLAT_CIL, "xxx")}); munmap(addr, size); } @@ -259,43 +268,26 @@ void SARBase::patch_rootdir() { // Patch init raw_data init; - bool redirect = false; int src = xopen("/init", O_RDONLY | O_CLOEXEC); fd_full_read(src, init.buf, init.sz); - for (uint8_t *p = init.buf, *eof = init.buf + init.sz; p < eof;) { - if (memcmp(p, SPLIT_PLAT_CIL, sizeof(SPLIT_PLAT_CIL)) == 0) { - LOGD("Remove from init: " SPLIT_PLAT_CIL "\n"); - memset(p, 'x', sizeof(SPLIT_PLAT_CIL) - 1); - p += sizeof(SPLIT_PLAT_CIL); - } else if (memcmp(p, MONOPOLICY, sizeof(MONOPOLICY)) == 0) { - LOGD("Patch init [" MONOPOLICY "] -> [%s]\n", sepol); - strcpy(reinterpret_cast(p), sepol); - redirect = true; - p += sizeof(MONOPOLICY); - } else { - ++p; - } - } + int patch_count = raw_data_patch(init.buf, init.sz, { + make_pair(SPLIT_PLAT_CIL, "xxx"), /* Force loading monolithic sepolicy */ + make_pair(MONOPOLICY, sepol) /* Redirect /sepolicy to custom path */ + }); xmkdir(ROOTOVL, 0); - int dest = xopen(ROOTOVL "/init", O_CREAT | O_WRONLY | O_CLOEXEC); + int dest = xopen(ROOTOVL "/init", O_CREAT | O_WRONLY | O_CLOEXEC, 0); xwrite(dest, init.buf, init.sz); fclone_attr(src, dest); close(src); close(dest); - if (!redirect) { + if (patch_count != 2 && access(LIBSELINUX, F_OK) == 0) { // init is dynamically linked, need to patch libselinux raw_data lib; full_read(LIBSELINUX, lib.buf, lib.sz); - for (uint8_t *p = lib.buf, *eof = lib.buf + lib.sz; p < eof; ++p) { - if (memcmp(p, MONOPOLICY, sizeof(MONOPOLICY)) == 0) { - LOGD("Patch libselinux.so [" MONOPOLICY "] -> [%s]\n", sepol); - strcpy(reinterpret_cast(p), sepol); - break; - } - } + raw_data_patch(lib.buf, lib.sz, {make_pair(MONOPOLICY, sepol)}); xmkdirs(dirname(ROOTOVL LIBSELINUX), 0755); - dest = xopen(ROOTOVL LIBSELINUX, O_CREAT | O_WRONLY | O_CLOEXEC); + dest = xopen(ROOTOVL LIBSELINUX, O_CREAT | O_WRONLY | O_CLOEXEC, 0); xwrite(dest, lib.buf, lib.sz); close(dest); clone_attr(LIBSELINUX, ROOTOVL LIBSELINUX); diff --git a/native/jni/utils/files.cpp b/native/jni/utils/files.cpp index 196dd5a8f..e6abc4300 100644 --- a/native/jni/utils/files.cpp +++ b/native/jni/utils/files.cpp @@ -302,11 +302,10 @@ void full_read(const char *filename, void **buf, size_t *size) { } string fd_full_read(int fd) { + char buf[4096]; string str; - auto len = lseek(fd, 0, SEEK_END); - str.resize(len); - lseek(fd, 0, SEEK_SET); - xxread(fd, str.data(), len); + for (ssize_t len; (len = xread(fd, buf, sizeof(buf))) > 0;) + str.insert(str.end(), buf, buf + len); return str; } diff --git a/native/jni/utils/misc.cpp b/native/jni/utils/misc.cpp index 05dc3d5a2..7d720566f 100644 --- a/native/jni/utils/misc.cpp +++ b/native/jni/utils/misc.cpp @@ -164,14 +164,6 @@ bool ends_with(const std::string_view &s1, const std::string_view &s2) { return l1 < l2 ? false : s1.compare(l1 - l2, l2, s2) == 0; } -char *rtrim(char *str) { - int len = strlen(str); - while (len > 0 && str[len - 1] == ' ') - --len; - str[len] = '\0'; - return str; -} - /* * Bionic's atoi runs through strtol(). * Use our own implementation for faster conversion. diff --git a/native/jni/utils/misc.hpp b/native/jni/utils/misc.hpp index bbb2a427a..85060b609 100644 --- a/native/jni/utils/misc.hpp +++ b/native/jni/utils/misc.hpp @@ -97,7 +97,6 @@ bool ends_with(const std::string_view &s1, const std::string_view &s2); int fork_dont_care(); int fork_no_zombie(); int strend(const char *s1, const char *s2); -char *rtrim(char *str); void init_argv0(int argc, char **argv); void set_nice_name(const char *name); uint32_t binary_gcd(uint32_t u, uint32_t v);