From 8d0dc37ec0ff362e1b3c4bc1b341051ded578fe3 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 19 Oct 2021 23:46:38 -0700 Subject: [PATCH] Use SO_PEERSEC to get client secontext --- native/jni/core/daemon.cpp | 45 ++++++++++++++-------------------- native/jni/core/socket.cpp | 14 ++++++++--- native/jni/include/daemon.hpp | 6 ++--- native/jni/include/socket.hpp | 7 +++++- native/jni/su/su_daemon.cpp | 8 +++--- native/jni/zygisk/deny/cli.cpp | 2 +- native/jni/zygisk/entry.cpp | 8 +++--- 7 files changed, 47 insertions(+), 43 deletions(-) diff --git a/native/jni/core/daemon.cpp b/native/jni/core/daemon.cpp index 8ba0f3aff..92d1f08d8 100644 --- a/native/jni/core/daemon.cpp +++ b/native/jni/core/daemon.cpp @@ -130,26 +130,7 @@ static void poll_ctrl_handler(pollfd *pfd) { } } -static bool verify_client(pid_t pid) { - // Verify caller is the same as server - char path[32]; - sprintf(path, "/proc/%d/exe", pid); - struct stat st; - return !(stat(path, &st) || st.st_dev != self_st.st_dev || st.st_ino != self_st.st_ino); -} - -static bool check_zygote(pid_t pid) { - char buf[32]; - sprintf(buf, "/proc/%d/attr/current", pid); - if (auto fp = open_file(buf, "r")) { - fscanf(fp.get(), "%s", buf); - return buf == "u:r:zygote:s0"sv; - } else { - return false; - } -} - -static void handle_request_async(int client, int code, ucred cred) { +static void handle_request_async(int client, int code, const sock_cred &cred) { switch (code) { case DENYLIST: denylist_handler(client, &cred); @@ -206,19 +187,29 @@ static void handle_request_sync(int client, int code) { } } +static bool is_client(pid_t pid) { + // Verify caller is the same as server + char path[32]; + sprintf(path, "/proc/%d/exe", pid); + struct stat st; + return !(stat(path, &st) || st.st_dev != self_st.st_dev || st.st_ino != self_st.st_ino); +} + static void handle_request(pollfd *pfd) { int client = xaccept4(pfd->fd, nullptr, nullptr, SOCK_CLOEXEC); // Verify client credentials - ucred cred; - get_client_cred(client, &cred); - - bool is_root = cred.uid == UID_ROOT; - bool is_client = verify_client(cred.pid); - bool is_zygote = !is_client && check_zygote(cred.pid); + sock_cred cred; + bool is_root; + bool is_zygote; int code; - if (!is_root && !is_zygote && !is_client) + if (!get_client_cred(client, &cred)) + goto done; + is_root = cred.uid == UID_ROOT; + is_zygote = cred.context == "u:r:zygote:s0"; + + if (!is_root && !is_zygote && !is_client(cred.pid)) goto done; code = read_int(client); diff --git a/native/jni/core/socket.cpp b/native/jni/core/socket.cpp index 08166de0a..939c3e866 100644 --- a/native/jni/core/socket.cpp +++ b/native/jni/core/socket.cpp @@ -20,9 +20,17 @@ socklen_t setup_sockaddr(sockaddr_un *sun, const char *name) { return socket_len(sun); } -void get_client_cred(int fd, ucred *cred) { - socklen_t len = sizeof(*cred); - getsockopt(fd, SOL_SOCKET, SO_PEERCRED, cred, &len); +bool get_client_cred(int fd, sock_cred *cred) { + socklen_t len = sizeof(ucred); + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, cred, &len) != 0) + return false; + char buf[4096]; + len = sizeof(buf); + if (getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &len) != 0) + return false; + buf[len] = '\0'; + cred->context = buf; + return true; } static int send_fds(int sockfd, void *cmsgbuf, size_t bufsz, const int *fds, int cnt) { diff --git a/native/jni/include/daemon.hpp b/native/jni/include/daemon.hpp index d218690e4..1a01cee6b 100644 --- a/native/jni/include/daemon.hpp +++ b/native/jni/include/daemon.hpp @@ -63,9 +63,9 @@ void android_logging(); void post_fs_data(int client); void late_start(int client); void boot_complete(int client); -void denylist_handler(int client, ucred *cred); -void su_daemon_handler(int client, ucred *credential); -void zygisk_handler(int client, ucred *cred); +void denylist_handler(int client, const sock_cred *cred); +void su_daemon_handler(int client, const sock_cred *cred); +void zygisk_handler(int client, const sock_cred *cred); std::vector zygisk_module_fds(bool is_64_bit); // Denylist diff --git a/native/jni/include/socket.hpp b/native/jni/include/socket.hpp index ee7afdcb1..ba35f0bb3 100644 --- a/native/jni/include/socket.hpp +++ b/native/jni/include/socket.hpp @@ -3,10 +3,15 @@ #include #include #include +#include #include +struct sock_cred : public ucred { + std::string context; +}; + socklen_t setup_sockaddr(sockaddr_un *sun, const char *name); -void get_client_cred(int fd, ucred *cred); +bool get_client_cred(int fd, sock_cred *cred); std::vector recv_fds(int sockfd); int recv_fd(int sockfd); int send_fds(int sockfd, const int *fds, int cnt); diff --git a/native/jni/su/su_daemon.cpp b/native/jni/su/su_daemon.cpp index ed696479d..6861a1b54 100644 --- a/native/jni/su/su_daemon.cpp +++ b/native/jni/su/su_daemon.cpp @@ -158,13 +158,13 @@ static void set_identity(unsigned uid) { } } -void su_daemon_handler(int client, struct ucred *credential) { - LOGD("su: request from pid=[%d], client=[%d]\n", credential->pid, client); +void su_daemon_handler(int client, const sock_cred *cred) { + LOGD("su: request from pid=[%d], client=[%d]\n", cred->pid, client); su_context ctx = { - .info = get_su_info(credential->uid), + .info = get_su_info(cred->uid), .req = su_request(), - .pid = credential->pid + .pid = cred->pid }; // Read su_request diff --git a/native/jni/zygisk/deny/cli.cpp b/native/jni/zygisk/deny/cli.cpp index 2d387fe68..6188ed08d 100644 --- a/native/jni/zygisk/deny/cli.cpp +++ b/native/jni/zygisk/deny/cli.cpp @@ -25,7 +25,7 @@ Actions: exit(1); } -void denylist_handler(int client, ucred *cred) { +void denylist_handler(int client, const sock_cred *cred) { if (client < 0) { revert_unmount(); return; diff --git a/native/jni/zygisk/entry.cpp b/native/jni/zygisk/entry.cpp index 469430b5d..894268c72 100644 --- a/native/jni/zygisk/entry.cpp +++ b/native/jni/zygisk/entry.cpp @@ -243,7 +243,7 @@ int remote_request_unmount() { // The following code runs in magiskd -static void setup_files(int client, ucred *cred) { +static void setup_files(int client, const sock_cred *cred) { LOGD("zygisk: setup files for pid=[%d]\n", cred->pid); char buf[256]; @@ -265,7 +265,7 @@ static void setup_files(int client, ucred *cred) { int cached_manager_app_id = -1; static time_t last_modified = 0; -static void get_process_info(int client, ucred *cred) { +static void get_process_info(int client, const sock_cred *cred) { AppInfo info{}; int uid = read_int(client); string process = read_string(client); @@ -315,7 +315,7 @@ static void get_process_info(int client, ucred *cred) { } } -static void do_unmount(int client, ucred *cred) { +static void do_unmount(int client, const sock_cred *cred) { if (denylist_enabled) { LOGD("zygisk: cleanup mount namespace for pid=[%d]\n", cred->pid); revert_daemon(cred->pid, client); @@ -334,7 +334,7 @@ static void send_log_pipe(int fd) { } } -void zygisk_handler(int client, ucred *cred) { +void zygisk_handler(int client, const sock_cred *cred) { int code = read_int(client); switch (code) { case ZYGISK_SETUP: