From 25bdbcf5261d571f58d0ed53fe59a35f4a2c1901 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 12 Oct 2017 02:57:18 +0800 Subject: [PATCH] Add new file operations --- jni/Android.mk | 6 +- jni/daemon/bootstages.c | 9 +- jni/external/Android.mk | 8 ++ jni/include/utils.h | 35 ++++-- jni/magiskinit.c | 118 ++--------------- jni/utils/file.c | 272 ++++++++++++++++++++++++++++++++++++++++ jni/utils/img.c | 2 +- jni/utils/misc.c | 99 --------------- jni/utils/xwrap.c | 1 + 9 files changed, 326 insertions(+), 224 deletions(-) create mode 100644 jni/utils/file.c diff --git a/jni/Android.mk b/jni/Android.mk index 41c0f66c5..516efffb1 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -40,6 +40,7 @@ LOCAL_SRC_FILES := \ utils/xwrap.c \ utils/list.c \ utils/img.c \ + utils/file.c \ magiskhide/magiskhide.c \ magiskhide/proc_monitor.c \ magiskhide/hide_utils.c \ @@ -92,11 +93,12 @@ include $(BUILD_EXECUTABLE) ifeq ($(TARGET_ARCH_ABI), arm64-v8a) include $(CLEAR_VARS) LOCAL_MODULE := magiskinit -LOCAL_STATIC_LIBRARIES := libsepol -LOCAL_C_INCLUDES := jni/include $(LIBSEPOL) +LOCAL_STATIC_LIBRARIES := libsepol libselinux_static +LOCAL_C_INCLUDES := jni/include $(LIBSEPOL) $(LIBSELINUX) LOCAL_SRC_FILES := \ magiskinit.c \ magiskboot/boot_utils.c \ + utils/file.c \ utils/xwrap.c \ magiskpolicy/rules.c \ magiskpolicy/sepolicy.c \ diff --git a/jni/daemon/bootstages.c b/jni/daemon/bootstages.c index d9b2714ef..d2c8d3ca1 100644 --- a/jni/daemon/bootstages.c +++ b/jni/daemon/bootstages.c @@ -523,7 +523,7 @@ static int prepare_img() { snprintf(buf, PATH_MAX, "%s/%s/remove", MOUNTPOINT, entry->d_name); if (access(buf, F_OK) == 0) { snprintf(buf, PATH_MAX, "%s/%s", MOUNTPOINT, entry->d_name); - exec_command_sync(BBPATH "/rm", "-rf", buf, NULL); + rm_rf(buf); continue; } snprintf(buf, PATH_MAX, "%s/%s/disable", MOUNTPOINT, entry->d_name); @@ -608,10 +608,9 @@ void post_fs_data(int client) { else if (access("/data/user_de/0/com.topjohnwu.magisk/install", F_OK) == 0) bin_path = "/data/user_de/0/com.topjohnwu.magisk/install"; if (bin_path) { - exec_command_sync("rm", "-rf", DATABIN, NULL); - exec_command_sync("cp", "-r", bin_path, DATABIN, NULL); - exec_command_sync("rm", "-rf", bin_path, NULL); - exec_command_sync("chmod", "-R", "755", bin_path, NULL); + rm_rf(DATABIN); + cp_afc(bin_path, DATABIN); + rm_rf(bin_path); // Lazy.... use shell blob to match files exec_command_sync("sh", "-c", "mv /data/magisk/stock_boot* /data", NULL); } diff --git a/jni/external/Android.mk b/jni/external/Android.mk index dae2530af..41138688a 100644 --- a/jni/external/Android.mk +++ b/jni/external/Android.mk @@ -14,6 +14,14 @@ LOCAL_C_INCLUDES := $(LIBSELINUX) LOCAL_SRC_FILES := stubs/selinux_stub.c include $(BUILD_SHARED_LIBRARY) +# libselinux_static.a (stub) +include $(CLEAR_VARS) +LOCAL_MODULE:= libselinux_static +LOCAL_C_INCLUDES := $(LIBSELINUX) +LOCAL_SRC_FILES := stubs/selinux_stub.c +include $(BUILD_STATIC_LIBRARY) + + # libfdt include $(CLEAR_VARS) LOCAL_MODULE:= libfdt diff --git a/jni/include/utils.h b/jni/include/utils.h index b7ccd2579..eacb28aa9 100644 --- a/jni/include/utils.h +++ b/jni/include/utils.h @@ -6,8 +6,6 @@ #include #include -#include -#include #include #include @@ -18,8 +16,6 @@ #define UID_SYSTEM (get_system_uid()) #define UID_RADIO (get_radio_uid()) -extern int quit_signals[]; - // xwrap.c FILE *xfopen(const char *pathname, const char *mode); @@ -69,6 +65,8 @@ int xmkdir_p(const char *pathname, mode_t mode); // misc.c +extern int quit_signals[]; + unsigned get_shell_uid(); unsigned get_system_uid(); unsigned get_radio_uid(); @@ -82,16 +80,37 @@ void unlock_blocks(); void setup_sighandlers(void (*handler)(int)); int exec_command(int err, int *fd, void (*setupenv)(struct vector*), const char *argv0, ...); int exec_command_sync(char *const argv0, ...); -int mkdir_p(const char *pathname, mode_t mode); int bind_mount(const char *from, const char *to); int open_new(const char *filename); -int cp_afc(const char *source, const char *target); -void fclone_attr(const int sourcefd, const int targetfd); -void clone_attr(const char *source, const char *target); void get_client_cred(int fd, struct ucred *cred); int switch_mnt_ns(int pid); int fork_dont_care(); +// file.c + +extern char **excl_list; + +struct file_attr { + struct stat st; + char con[128]; +}; + +int mkdir_p(const char *pathname, mode_t mode); +void rm_rf(const char *path); +void frm_rf(int dirfd); +void mv_f(const char *source, const char *destination); +void mv_dir(int src, int dest); +void cp_afc(const char *source, const char *destination); +void clone_dir(int src, int dest); +int getattr(const char *path, struct file_attr *a); +int getattrat(int dirfd, const char *pathname, struct file_attr *a); +int fgetattr(int fd, struct file_attr *a); +int setattr(const char *path, struct file_attr *a); +int setattrat(int dirfd, const char *pathname, struct file_attr *a); +int fsetattr(int fd, struct file_attr *a); +void fclone_attr(const int sourcefd, const int targetfd); +void clone_attr(const char *source, const char *target); + // img.c #define round_size(a) ((((a) / 32) + 2) * 32) diff --git a/jni/magiskinit.c b/jni/magiskinit.c index 35980f749..0e1ccae9b 100644 --- a/jni/magiskinit.c +++ b/jni/magiskinit.c @@ -25,6 +25,7 @@ #include +#include "utils.h" #include "magiskpolicy.h" struct cmdline { @@ -46,114 +47,6 @@ extern void mmap_ro(const char *filename, void **buf, size_t *size); extern void mmap_rw(const char *filename, void **buf, size_t *size); extern void *patch_init_rc(char *data, uint32_t *size); -static void clone_dir(int src, int dest) { - struct dirent *entry; - DIR *dir; - int srcfd, destfd, newsrc, newdest; - struct stat st; - char buf[PATH_MAX]; - ssize_t size; - - dir = fdopendir(src); - while ((entry = readdir(dir))) { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) - continue; - fstatat(src, entry->d_name, &st, AT_SYMLINK_NOFOLLOW); - switch (entry->d_type) { - case DT_DIR: - mkdirat(dest, entry->d_name, st.st_mode & 0777); - fchownat(dest, entry->d_name, st.st_uid, st.st_gid, 0); - // Don't clone recursive if it's /system - if (strcmp(entry->d_name, "system") == 0) - continue; - newsrc = openat(src, entry->d_name, O_RDONLY | O_CLOEXEC); - newdest = openat(dest, entry->d_name, O_RDONLY | O_CLOEXEC); - clone_dir(newsrc, newdest); - close(newsrc); - close(newdest); - break; - case DT_REG: - destfd = openat(dest, entry->d_name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, st.st_mode & 0777); - srcfd = openat(src, entry->d_name, O_RDONLY | O_CLOEXEC); - sendfile(destfd, srcfd, 0, st.st_size); - fchownat(dest, entry->d_name, st.st_uid, st.st_gid, 0); - close(destfd); - close(srcfd); - break; - case DT_LNK: - size = readlinkat(src, entry->d_name, buf, sizeof(buf)); - buf[size] = '\0'; - symlinkat(buf, dest, entry->d_name); - fchownat(dest, entry->d_name, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW); - break; - } - } -} - -static void mv_dir(int src, int dest) { - struct dirent *entry; - DIR *dir; - int newsrc, newdest; - struct stat st; - char buf[PATH_MAX]; - ssize_t size; - - dir = fdopendir(src); - while ((entry = readdir(dir))) { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) - continue; - fstatat(src, entry->d_name, &st, AT_SYMLINK_NOFOLLOW); - switch (entry->d_type) { - case DT_DIR: - mkdirat(dest, entry->d_name, st.st_mode & 0777); - fchownat(dest, entry->d_name, st.st_uid, st.st_gid, 0); - newsrc = openat(src, entry->d_name, O_RDONLY | O_CLOEXEC); - newdest = openat(dest, entry->d_name, O_RDONLY | O_CLOEXEC); - mv_dir(newsrc, newdest); - close(newsrc); - close(newdest); - break; - case DT_REG: - renameat(src, entry->d_name, dest, entry->d_name); - fchmodat(dest, entry->d_name, st.st_mode & 0777, 0); - fchownat(dest, entry->d_name, st.st_uid, st.st_gid, 0); - break; - case DT_LNK: - size = readlinkat(src, entry->d_name, buf, sizeof(buf)); - buf[size] = '\0'; - symlinkat(buf, dest, entry->d_name); - fchownat(dest, entry->d_name, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW); - break; - } - unlinkat(src, entry->d_name, AT_REMOVEDIR); - } -} - -static void rm_rf(int path) { - struct dirent *entry; - int newfd; - DIR *dir = fdopendir(path); - - while ((entry = readdir(dir))) { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) - continue; - switch (entry->d_type) { - case DT_DIR: - // Preserve overlay - if (strcmp(entry->d_name, "overlay") == 0) - continue; - newfd = openat(path, entry->d_name, O_RDONLY | O_CLOEXEC); - rm_rf(newfd); - close(newfd); - unlinkat(path, entry->d_name, AT_REMOVEDIR); - break; - default: - unlinkat(path, entry->d_name, 0); - break; - } - } -} - static void parse_cmdline(struct cmdline *cmd) { char *tok; char buffer[4096]; @@ -364,7 +257,10 @@ int main(int argc, char *argv[]) { // Normal boot mode // Clear rootfs int root = open("/", O_RDONLY | O_CLOEXEC); - rm_rf(root); + + // Exclude overlay folder + excl_list = (char *[]) { "overlay", NULL }; + frm_rf(root); mkdir("/sys", 0755); mount("sysfs", "/sys", "sysfs", 0, NULL); @@ -378,7 +274,11 @@ int main(int argc, char *argv[]) { mkdir("/system_root", 0755); mount(dev.path, "/system_root", "ext4", MS_RDONLY, NULL); int system_root = open("/system_root", O_RDONLY | O_CLOEXEC); + + // Exclude system folder + excl_list = (char *[]) { "system", NULL }; clone_dir(system_root, root); + mkdir("/system", 0755); mount("/system_root/system", "/system", NULL, MS_BIND, NULL); int overlay = open("/overlay", O_RDONLY | O_CLOEXEC); diff --git a/jni/utils/file.c b/jni/utils/file.c new file mode 100644 index 000000000..163abb5ae --- /dev/null +++ b/jni/utils/file.c @@ -0,0 +1,272 @@ +/* file.c - Contains all files related utilities + */ + +#include +#include +#include +#include +#include + +#include "utils.h" + +char **excl_list = (char *[]) { NULL }; + +static int is_excl(const char *name) { + for (int i = 0; excl_list[i]; ++i) { + if (strcmp(name, excl_list[i]) == 0) + return 1; + } + return 0; +} + +int mkdir_p(const char *pathname, mode_t mode) { + char *path = strdup(pathname), *p; + errno = 0; + for (p = path + 1; *p; ++p) { + if (*p == '/') { + *p = '\0'; + if (mkdir(path, mode) == -1) { + if (errno != EEXIST) + return -1; + } + *p = '/'; + } + } + if (mkdir(path, mode) == -1) { + if (errno != EEXIST) + return -1; + } + free(path); + return 0; +} + +void rm_rf(const char *path) { + int fd = xopen(path, O_RDONLY | O_CLOEXEC); + frm_rf(fd); + close(fd); + rmdir(path); +} + +void frm_rf(int dirfd) { + struct dirent *entry; + int newfd; + DIR *dir = fdopendir(dirfd); + + while ((entry = readdir(dir))) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + if (is_excl(entry->d_name)) + continue; + switch (entry->d_type) { + case DT_DIR: + newfd = openat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC); + frm_rf(newfd); + close(newfd); + unlinkat(dirfd, entry->d_name, AT_REMOVEDIR); + break; + default: + unlinkat(dirfd, entry->d_name, 0); + break; + } + } +} + +/* This will only on the same file system */ +void mv_f(const char *source, const char *destination) { + struct stat st; + xlstat(source, &st); + int src, dest; + struct file_attr a; + + if (S_ISDIR(st.st_mode)) { + xmkdir_p(destination, st.st_mode & 0777); + src = xopen(source, O_RDONLY | O_CLOEXEC); + dest = xopen(destination, O_RDONLY | O_CLOEXEC); + fclone_attr(src, dest); + mv_dir(src, dest); + close(src); + close(dest); + } else{ + getattr(source, &a); + rename(source, destination); + setattr(destination, &a); + } + rmdir(source); +} + +/* This will only on the same file system */ +void mv_dir(int src, int dest) { + struct dirent *entry; + DIR *dir; + int newsrc, newdest; + struct file_attr a; + + dir = fdopendir(src); + while ((entry = readdir(dir))) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + if (is_excl(entry->d_name)) + continue; + getattrat(src, entry->d_name, &a); + switch (entry->d_type) { + case DT_DIR: + mkdirat(dest, entry->d_name, a.st.st_mode & 0777); + newsrc = openat(src, entry->d_name, O_RDONLY | O_CLOEXEC); + newdest = openat(dest, entry->d_name, O_RDONLY | O_CLOEXEC); + fsetattr(newdest, &a); + mv_dir(newsrc, newdest); + close(newsrc); + close(newdest); + unlinkat(src, entry->d_name, AT_REMOVEDIR); + break; + case DT_LNK: + case DT_REG: + renameat(src, entry->d_name, dest, entry->d_name); + setattrat(dest, entry->d_name, &a); + break; + } + } +} + +void cp_afc(const char *source, const char *destination) { + int src, dest; + struct file_attr a; + getattr(source, &a); + + if (S_ISDIR(a.st.st_mode)) { + xmkdir_p(destination, a.st.st_mode & 0777); + src = xopen(source, O_RDONLY | O_CLOEXEC); + dest = xopen(destination, O_RDONLY | O_CLOEXEC); + fsetattr(dest, &a); + clone_dir(src, dest); + close(src); + close(dest); + } else{ + unlink(destination); + if (S_ISREG(a.st.st_mode)) { + src = xopen(source, O_RDONLY); + dest = xopen(destination, O_WRONLY | O_CREAT | O_TRUNC); + xsendfile(dest, src, NULL, a.st.st_size); + fsetattr(src, &a); + close(src); + close(dest); + } else if (S_ISLNK(a.st.st_mode)) { + char buf[PATH_MAX]; + xreadlink(source, buf, sizeof(buf)); + xsymlink(buf, destination); + setattr(destination, &a); + } + } +} + +void clone_dir(int src, int dest) { + struct dirent *entry; + DIR *dir; + int srcfd, destfd, newsrc, newdest; + char buf[PATH_MAX]; + ssize_t size; + struct file_attr a; + + dir = fdopendir(src); + while ((entry = readdir(dir))) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + if (is_excl(entry->d_name)) + continue; + getattrat(src, entry->d_name, &a); + switch (entry->d_type) { + case DT_DIR: + mkdirat(dest, entry->d_name, a.st.st_mode & 0777); + setattrat(dest, entry->d_name, &a); + newsrc = openat(src, entry->d_name, O_RDONLY | O_CLOEXEC); + newdest = openat(dest, entry->d_name, O_RDONLY | O_CLOEXEC); + clone_dir(newsrc, newdest); + close(newsrc); + close(newdest); + break; + case DT_REG: + destfd = openat(dest, entry->d_name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, a.st.st_mode & 0777); + srcfd = openat(src, entry->d_name, O_RDONLY | O_CLOEXEC); + sendfile(destfd, srcfd, 0, a.st.st_size); + fsetattr(destfd, &a); + close(destfd); + close(srcfd); + break; + case DT_LNK: + size = readlinkat(src, entry->d_name, buf, sizeof(buf)); + buf[size] = '\0'; + symlinkat(buf, dest, entry->d_name); + setattrat(dest, entry->d_name, &a); + break; + } + } +} + +int getattr(const char *path, struct file_attr *a) { + int fd = open(path, O_PATH | O_NOFOLLOW | O_CLOEXEC); + if (fd < 0) + return -1; + int ret = fgetattr(fd, a); + close(fd); + return ret; +} + +int getattrat(int dirfd, const char *pathname, struct file_attr *a) { + int fd = openat(dirfd, pathname, O_PATH | O_NOFOLLOW | O_CLOEXEC); + if (fd < 0) + return -1; + int ret = fgetattr(fd, a); + close(fd); + return ret; +} + +int fgetattr(int fd, struct file_attr *a) { + if (fstat(fd, &a->st) < 0) + return -1; + char *con = ""; + if (fgetfilecon(fd, &con) < 0) + return -1; + strcpy(a->con, con); + freecon(con); + return 0; +} + +int setattr(const char *path, struct file_attr *a) { + int fd = open(path, O_PATH | O_NOFOLLOW | O_CLOEXEC); + if (fd < 0) + return -1; + int ret = fsetattr(fd, a); + close(fd); + return ret; +} + +int setattrat(int dirfd, const char *pathname, struct file_attr *a) { + int fd = openat(dirfd, pathname, O_PATH | O_NOFOLLOW | O_CLOEXEC); + if (fd < 0) + return -1; + int ret = fsetattr(fd, a); + close(fd); + return ret; +} + +int fsetattr(int fd, struct file_attr *a) { + if (fchmod(fd, a->st.st_mode & 0777) < 0) + return -1; + if (fchown(fd, a->st.st_uid, a->st.st_gid) < 0) + return -1; + if (strlen(a->con) && fsetfilecon(fd, a->con) < 0) + return -1; + return 0; +} + +void clone_attr(const char *source, const char *target) { + struct file_attr a; + getattr(source, &a); + setattr(target, &a); +} + +void fclone_attr(const int sourcefd, const int targetfd) { + struct file_attr a; + fgetattr(sourcefd, &a); + fsetattr(targetfd, &a); +} diff --git a/jni/utils/img.c b/jni/utils/img.c index 5a80781ef..845518d44 100644 --- a/jni/utils/img.c +++ b/jni/utils/img.c @@ -176,7 +176,7 @@ int merge_img(const char *source, const char *target) { snprintf(buffer, sizeof(buffer), "%s/%s", TARGET_TMP, entry->d_name); if (access(buffer, F_OK) == 0) { LOGI("Upgrade module: %s\n", entry->d_name); - exec_command_sync(BBPATH "/rm", "-rf", buffer, NULL); + rm_rf(buffer); } else { LOGI("New module: %s\n", entry->d_name); } diff --git a/jni/utils/misc.c b/jni/utils/misc.c index 3cc44eed3..30dfbd626 100644 --- a/jni/utils/misc.c +++ b/jni/utils/misc.c @@ -6,19 +6,14 @@ #include #include #include -#include -#include #include #include #include -#include #include #include -#include #include #include #include -#include #include "logging.h" #include "utils.h" @@ -281,27 +276,6 @@ int exec_command(int err, int *fd, void (*setupenv)(struct vector*), const char return pid; } -int mkdir_p(const char *pathname, mode_t mode) { - char *path = strdup(pathname), *p; - errno = 0; - for (p = path + 1; *p; ++p) { - if (*p == '/') { - *p = '\0'; - if (mkdir(path, mode) == -1) { - if (errno != EEXIST) - return -1; - } - *p = '/'; - } - } - if (mkdir(path, mode) == -1) { - if (errno != EEXIST) - return -1; - } - free(path); - return 0; -} - int bind_mount(const char *from, const char *to) { int ret = xmount(from, to, NULL, MS_BIND, NULL); #ifdef MAGISK_DEBUG @@ -316,79 +290,6 @@ int open_new(const char *filename) { return xopen(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); } -int cp_afc(const char *source, const char *target) { - struct stat buf; - xlstat(source, &buf); - - if (S_ISDIR(buf.st_mode)) { - DIR *dir; - struct dirent *entry; - char *s_path, *t_path; - - if (!(dir = xopendir(source))) - return 1; - - s_path = xmalloc(PATH_MAX); - t_path = xmalloc(PATH_MAX); - - mkdir_p(target, 0755); - clone_attr(source, target); - - while ((entry = xreaddir(dir))) { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) - continue; - snprintf(s_path, PATH_MAX, "%s/%s", source, entry->d_name); - snprintf(t_path, PATH_MAX, "%s/%s", target, entry->d_name); - cp_afc(s_path, t_path); - } - free(s_path); - free(t_path); - - closedir(dir); - } else{ - unlink(target); - if (S_ISREG(buf.st_mode)) { - int sfd, tfd; - sfd = xopen(source, O_RDONLY); - tfd = xopen(target, O_WRONLY | O_CREAT | O_TRUNC); - xsendfile(tfd, sfd, NULL, buf.st_size); - fclone_attr(sfd, tfd); - close(sfd); - close(tfd); - } else if (S_ISLNK(buf.st_mode)) { - char buffer[PATH_MAX]; - xreadlink(source, buffer, sizeof(buffer)); - xsymlink(buffer, target); - clone_attr(source, target); - } else { - return 1; - } - } - return 0; -} - -void clone_attr(const char *source, const char *target) { - struct stat buf; - lstat(target, &buf); - chmod(target, buf.st_mode & 0777); - chown(target, buf.st_uid, buf.st_gid); - char *con; - lgetfilecon(source, &con); - lsetfilecon(target, con); - free(con); -} - -void fclone_attr(const int sourcefd, const int targetfd) { - struct stat buf; - fstat(sourcefd, &buf); - fchmod(targetfd, buf.st_mode & 0777); - fchown(targetfd, buf.st_uid, buf.st_gid); - char *con; - fgetfilecon(sourcefd, &con); - fsetfilecon(targetfd, con); - free(con); -} - void get_client_cred(int fd, struct ucred *cred) { socklen_t ucred_length = sizeof(*cred); if(getsockopt(fd, SOL_SOCKET, SO_PEERCRED, cred, &ucred_length)) diff --git a/jni/utils/xwrap.c b/jni/utils/xwrap.c index 78e8eb10d..a2544d98d 100644 --- a/jni/utils/xwrap.c +++ b/jni/utils/xwrap.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include