From d15fff95b9267971d4141adf34b8f4753bc98ecb Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Mon, 27 Nov 2017 15:37:28 +0800 Subject: [PATCH] Use inotify to monitor files --- jni/Android.mk | 1 + jni/core/bootstages.c | 7 +- jni/core/daemon.c | 144 --------------------------------------- jni/core/magiskinit.c | 25 +++---- jni/core/socket.c | 152 ++++++++++++++++++++++++++++++++++++++++++ jni/include/daemon.h | 5 ++ jni/include/magisk.h | 1 - jni/include/utils.h | 1 + jni/utils/file.c | 19 ++++++ 9 files changed, 192 insertions(+), 163 deletions(-) create mode 100644 jni/core/socket.c diff --git a/jni/Android.mk b/jni/Android.mk index c9dadda23..21d797665 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -31,6 +31,7 @@ LOCAL_SRC_FILES := \ core/daemon.c \ core/log_monitor.c \ core/bootstages.c \ + core/socket.c \ utils/misc.c \ utils/vector.c \ utils/xwrap.c \ diff --git a/jni/core/bootstages.c b/jni/core/bootstages.c index cf836149c..df512a24f 100644 --- a/jni/core/bootstages.c +++ b/jni/core/bootstages.c @@ -575,9 +575,6 @@ void post_fs(int client) { write_int(client, 0); close(client); - // Allow magiskinit to full patch - close(creat(PATCHSTART, 0)); - // Uninstall or core only mode if (access(UNINSTALLER, F_OK) == 0 || access(DISABLEFILE, F_OK) == 0) goto unblock; @@ -744,9 +741,7 @@ void late_start(int client) { if (buf2 == NULL) buf2 = xmalloc(PATH_MAX); // Wait till the full patch is done - while (access(PATCHDONE, F_OK) == -1) - usleep(500); /* Wait 0.5ms */ - unlink(PATCHDONE); + wait_till_exists(PATCHDONE); // Run scripts after full patch, most reliable way to run scripts LOGI("* Running service.d scripts\n"); diff --git a/jni/core/daemon.c b/jni/core/daemon.c index 6dcaea7bb..db9db27a3 100644 --- a/jni/core/daemon.c +++ b/jni/core/daemon.c @@ -13,9 +13,6 @@ #include #include #include -#include -#include -#include #include #include "magisk.h" @@ -95,14 +92,6 @@ static void *request_handler(void *args) { return NULL; } -/* Setup the address and return socket fd */ -static int setup_socket(struct sockaddr_un *sun) { - int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); - memset(sun, 0, sizeof(*sun)); - sun->sun_family = AF_LOCAL; - memcpy(sun->sun_path, REQUESTOR_DAEMON_PATH, sizeof(REQUESTOR_DAEMON_PATH) - 1); - return fd; -} static void *start_magisk_hide(void *args) { launch_magiskhide(-1); @@ -199,136 +188,3 @@ int connect_daemon() { } return fd; } - -/* - * Receive a file descriptor from a Unix socket. - * Contributed by @mkasick - * - * Returns the file descriptor on success, or -1 if a file - * descriptor was not actually included in the message - * - * On error the function terminates by calling exit(-1) - */ -int recv_fd(int sockfd) { - // Need to receive data from the message, otherwise don't care about it. - char iovbuf; - - struct iovec iov = { - .iov_base = &iovbuf, - .iov_len = 1, - }; - - char cmsgbuf[CMSG_SPACE(sizeof(int))]; - - struct msghdr msg = { - .msg_iov = &iov, - .msg_iovlen = 1, - .msg_control = cmsgbuf, - .msg_controllen = sizeof(cmsgbuf), - }; - - xrecvmsg(sockfd, &msg, MSG_WAITALL); - - // Was a control message actually sent? - switch (msg.msg_controllen) { - case 0: - // No, so the file descriptor was closed and won't be used. - return -1; - case sizeof(cmsgbuf): - // Yes, grab the file descriptor from it. - break; - default: - goto error; - } - - struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); - - if (cmsg == NULL || - cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || - cmsg->cmsg_level != SOL_SOCKET || - cmsg->cmsg_type != SCM_RIGHTS) { -error: - LOGE("unable to read fd"); - exit(-1); - } - - return *(int *)CMSG_DATA(cmsg); -} - -/* - * Send a file descriptor through a Unix socket. - * Contributed by @mkasick - * - * On error the function terminates by calling exit(-1) - * - * fd may be -1, in which case the dummy data is sent, - * but no control message with the FD is sent. - */ -void send_fd(int sockfd, int fd) { - // Need to send some data in the message, this will do. - struct iovec iov = { - .iov_base = "", - .iov_len = 1, - }; - - struct msghdr msg = { - .msg_iov = &iov, - .msg_iovlen = 1, - }; - - char cmsgbuf[CMSG_SPACE(sizeof(int))]; - - if (fd != -1) { - // Is the file descriptor actually open? - if (fcntl(fd, F_GETFD) == -1) { - if (errno != EBADF) { - PLOGE("unable to send fd"); - } - // It's closed, don't send a control message or sendmsg will EBADF. - } else { - // It's open, send the file descriptor in a control message. - msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); - - struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); - - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - - *(int *)CMSG_DATA(cmsg) = fd; - } - } - - xsendmsg(sockfd, &msg, 0); -} - -int read_int(int fd) { - int val; - xxread(fd, &val, sizeof(int)); - return val; -} - -void write_int(int fd, int val) { - if (fd < 0) return; - xwrite(fd, &val, sizeof(int)); -} - -char* read_string(int fd) { - int len = read_int(fd); - if (len > PATH_MAX || len < 0) { - LOGE("invalid string length %d", len); - exit(1); - } - char* val = xmalloc(sizeof(char) * (len + 1)); - xxread(fd, val, len); - val[len] = '\0'; - return val; -} - -void write_string(int fd, const char* val) { - if (fd < 0) return; - int len = strlen(val); - write_int(fd, len); - xwrite(fd, val, len); -} diff --git a/jni/core/magiskinit.c b/jni/core/magiskinit.c index 46c07de97..22f32cb69 100644 --- a/jni/core/magiskinit.c +++ b/jni/core/magiskinit.c @@ -340,6 +340,17 @@ static int dump_magiskrc(const char *path, mode_t mode) { return 0; } +static void magisk_init_daemon() { + // Fork a new process for full patch + setsid(); + sepol_allow("su", ALL, ALL, ALL); + wait_till_exists("/dev/.coldboot_done"); + dump_policydb(SELINUX_LOAD); + close(open(PATCHDONE, O_RDONLY | O_CREAT, 0)); + destroy_policydb(); + exit(0); +} + int main(int argc, char *argv[]) { umask(0); @@ -423,18 +434,8 @@ int main(int argc, char *argv[]) { umount("/vendor"); - if (fork() == 0) { - // Fork a new process for full patch - setsid(); - sepol_allow("su", ALL, ALL, ALL); - while (access(PATCHSTART, W_OK) == -1) - usleep(500); /* Wait 0.5ms */ - unlink(PATCHSTART); - dump_policydb(SELINUX_LOAD); - close(open(PATCHDONE, O_RDONLY | O_CREAT, 0)); - destroy_policydb(); - return 0; - } + if (fork() == 0) + magisk_init_daemon(); // Finally, give control back! execv("/init", argv); diff --git a/jni/core/socket.c b/jni/core/socket.c new file mode 100644 index 000000000..75b1b037b --- /dev/null +++ b/jni/core/socket.c @@ -0,0 +1,152 @@ +/* socket.c - All socket related operations + */ + +#include + +#include "daemon.h" +#include "logging.h" +#include "utils.h" +#include "magisk.h" + +/* Setup the address and return socket fd */ +int setup_socket(struct sockaddr_un *sun) { + int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); + memset(sun, 0, sizeof(*sun)); + sun->sun_family = AF_LOCAL; + memcpy(sun->sun_path, REQUESTOR_DAEMON_PATH, sizeof(REQUESTOR_DAEMON_PATH) - 1); + return fd; +} + + +/* + * Receive a file descriptor from a Unix socket. + * Contributed by @mkasick + * + * Returns the file descriptor on success, or -1 if a file + * descriptor was not actually included in the message + * + * On error the function terminates by calling exit(-1) + */ +int recv_fd(int sockfd) { + // Need to receive data from the message, otherwise don't care about it. + char iovbuf; + + struct iovec iov = { + .iov_base = &iovbuf, + .iov_len = 1, + }; + + char cmsgbuf[CMSG_SPACE(sizeof(int))]; + + struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = cmsgbuf, + .msg_controllen = sizeof(cmsgbuf), + }; + + xrecvmsg(sockfd, &msg, MSG_WAITALL); + + // Was a control message actually sent? + switch (msg.msg_controllen) { + case 0: + // No, so the file descriptor was closed and won't be used. + return -1; + case sizeof(cmsgbuf): + // Yes, grab the file descriptor from it. + break; + default: + goto error; + } + + struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); + + if (cmsg == NULL || + cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || + cmsg->cmsg_level != SOL_SOCKET || + cmsg->cmsg_type != SCM_RIGHTS) { +error: + LOGE("unable to read fd"); + exit(-1); + } + + return *(int *)CMSG_DATA(cmsg); +} + +/* + * Send a file descriptor through a Unix socket. + * Contributed by @mkasick + * + * On error the function terminates by calling exit(-1) + * + * fd may be -1, in which case the dummy data is sent, + * but no control message with the FD is sent. + */ +void send_fd(int sockfd, int fd) { + // Need to send some data in the message, this will do. + struct iovec iov = { + .iov_base = "", + .iov_len = 1, + }; + + struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + char cmsgbuf[CMSG_SPACE(sizeof(int))]; + + if (fd != -1) { + // Is the file descriptor actually open? + if (fcntl(fd, F_GETFD) == -1) { + if (errno != EBADF) { + PLOGE("unable to send fd"); + } + // It's closed, don't send a control message or sendmsg will EBADF. + } else { + // It's open, send the file descriptor in a control message. + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + + struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); + + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + *(int *)CMSG_DATA(cmsg) = fd; + } + } + + xsendmsg(sockfd, &msg, 0); +} + +int read_int(int fd) { + int val; + xxread(fd, &val, sizeof(int)); + return val; +} + +void write_int(int fd, int val) { + if (fd < 0) return; + xwrite(fd, &val, sizeof(int)); +} + +char* read_string(int fd) { + int len = read_int(fd); + if (len > PATH_MAX || len < 0) { + LOGE("invalid string length %d", len); + exit(1); + } + char* val = xmalloc(sizeof(char) * (len + 1)); + xxread(fd, val, len); + val[len] = '\0'; + return val; +} + +void write_string(int fd, const char* val) { + if (fd < 0) return; + int len = strlen(val); + write_int(fd, len); + xwrite(fd, val, len); +} diff --git a/jni/include/daemon.h b/jni/include/daemon.h index 6f6685b4a..c34b80526 100644 --- a/jni/include/daemon.h +++ b/jni/include/daemon.h @@ -5,6 +5,7 @@ #define _DAEMON_H_ #include +#include extern pthread_t sepol_patch; extern int is_restart; @@ -42,6 +43,10 @@ typedef enum { void start_daemon(); int connect_daemon(); void auto_start_magiskhide(); + +// socket.c + +int setup_socket(struct sockaddr_un *sun); int recv_fd(int sockfd); void send_fd(int sockfd, int fd); int read_int(int fd); diff --git a/jni/include/magisk.h b/jni/include/magisk.h index 4f3edbab6..b5b86c571 100644 --- a/jni/include/magisk.h +++ b/jni/include/magisk.h @@ -17,7 +17,6 @@ #define LASTLOG "/cache/last_magisk.log" #define DEBUG_LOG "/data/magisk_debug.log" #define UNBLOCKFILE "/dev/.magisk.unblock" -#define PATCHSTART "/dev/.magisk.patch.start" #define PATCHDONE "/dev/.magisk.patch.done" #define DISABLEFILE "/cache/.disable_magisk" #define UNINSTALLER "/cache/magisk_uninstaller.sh" diff --git a/jni/include/utils.h b/jni/include/utils.h index 62368539b..0b5d13ff9 100644 --- a/jni/include/utils.h +++ b/jni/include/utils.h @@ -89,6 +89,7 @@ int bind_mount(const char *from, const char *to); void get_client_cred(int fd, struct ucred *cred); int switch_mnt_ns(int pid); int fork_dont_care(); +void wait_till_exists(const char *target); // file.c diff --git a/jni/utils/file.c b/jni/utils/file.c index 312dfea8e..308bd0376 100644 --- a/jni/utils/file.c +++ b/jni/utils/file.c @@ -6,8 +6,10 @@ #include #include #include +#include #include #include +#include #include #ifndef NO_SELINUX @@ -216,6 +218,23 @@ void clone_dir(int src, int dest) { } } +void wait_till_exists(const char *target) { + if (access(target, F_OK) == 0) + return; + int fd = inotify_init(); + char *dir = dirname(target); + char crap[PATH_MAX]; + inotify_add_watch(fd, dir, IN_CREATE); + while (1) { + struct inotify_event event; + read(fd, &event, sizeof(event)); + read(fd, crap, event.len); + if (access(target, F_OK) == 0) + break; + } + close(fd); +} + int getattr(const char *path, struct file_attr *a) { if (xlstat(path, &a->st) == -1) return -1;