diff --git a/native/jni/core/bootstages.cpp b/native/jni/core/bootstages.cpp index ac202bc22..8aa55d8b0 100644 --- a/native/jni/core/bootstages.cpp +++ b/native/jni/core/bootstages.cpp @@ -14,6 +14,7 @@ #include #include "core.hpp" +#include "zygisk/deny/deny.hpp" using namespace std; diff --git a/native/jni/core/daemon.cpp b/native/jni/core/daemon.cpp index 5aaab0859..256997455 100644 --- a/native/jni/core/daemon.cpp +++ b/native/jni/core/daemon.cpp @@ -86,20 +86,20 @@ void clear_poll() { static void poll_ctrl_handler(pollfd *pfd) { int code = read_int(pfd->fd); switch (code) { - case POLL_CTRL_NEW: { - pollfd new_fd; - poll_callback cb; - xxread(pfd->fd, &new_fd, sizeof(new_fd)); - xxread(pfd->fd, &cb, sizeof(cb)); - register_poll(&new_fd, cb); - break; - } - case POLL_CTRL_RM: { - int fd = read_int(pfd->fd); - bool auto_close = read_int(pfd->fd); - unregister_poll(fd, auto_close); - break; - } + case POLL_CTRL_NEW: { + pollfd new_fd; + poll_callback cb; + xxread(pfd->fd, &new_fd, sizeof(new_fd)); + xxread(pfd->fd, &cb, sizeof(cb)); + register_poll(&new_fd, cb); + break; + } + case POLL_CTRL_RM: { + int fd = read_int(pfd->fd); + bool auto_close = read_int(pfd->fd); + unregister_poll(fd, auto_close); + break; + } } } @@ -133,61 +133,63 @@ static void poll_ctrl_handler(pollfd *pfd) { } } -static void handle_request_async(int client, int code, const sock_cred &cred) { +static void handle_request_async(int client, DaemonRequest code, const sock_cred &cred) { + // using enum DAEMON_REQUEST; switch (code) { - case DENYLIST: + case DaemonRequest::DENYLIST: denylist_handler(client, &cred); break; - case SUPERUSER: + case DaemonRequest::SUPERUSER: su_daemon_handler(client, &cred); break; - case POST_FS_DATA: + case DaemonRequest::POST_FS_DATA: post_fs_data(client); break; - case LATE_START: + case DaemonRequest::LATE_START: late_start(client); break; - case BOOT_COMPLETE: + case DaemonRequest::BOOT_COMPLETE: boot_complete(client); break; - case SQLITE_CMD: + case DaemonRequest::SQLITE_CMD: exec_sql(client); break; - case REMOVE_MODULES: + case DaemonRequest::REMOVE_MODULES: remove_modules(); write_int(client, 0); close(client); reboot(); break; - case ZYGISK_REQUEST: - case ZYGISK_PASSTHROUGH: + case DaemonRequest::ZYGISK_REQUEST: zygisk_handler(client, &cred); break; default: - close(client); - break; + __builtin_unreachable(); } } -static void handle_request_sync(int client, int code) { +static void handle_request_sync(int client, DaemonRequest code) { + // using enum DAEMON_REQUEST; switch (code) { - case CHECK_VERSION: + case DaemonRequest::CHECK_VERSION: write_string(client, MAGISK_VERSION ":MAGISK"); break; - case CHECK_VERSION_CODE: + case DaemonRequest::CHECK_VERSION_CODE: write_int(client, MAGISK_VER_CODE); break; - case GET_PATH: + case DaemonRequest::GET_PATH: write_string(client, MAGISKTMP.data()); break; - case START_DAEMON: + case DaemonRequest::START_DAEMON: setup_logfile(true); break; - case STOP_DAEMON: + case DaemonRequest::STOP_DAEMON: denylist_handler(-1, nullptr); write_int(client, 0); // Terminate the daemon! exit(0); + default: + __builtin_unreachable(); } } @@ -195,11 +197,17 @@ 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; + struct stat st{}; return !(stat(path, &st) || st.st_dev != self_st.st_dev || st.st_ino != self_st.st_ino); } +inline static void write_response(int client, DaemonResponse res) { + write_int(client, static_cast>(res)); +} + static void handle_request(pollfd *pfd) { +// using enum DAEMON_REQUEST; +// using enum DAEMON_RESPONSE; int client = xaccept4(pfd->fd, nullptr, nullptr, SOCK_CLOEXEC); // Verify client credentials @@ -207,6 +215,7 @@ static void handle_request(pollfd *pfd) { bool is_root; bool is_zygote; int code; + DaemonRequest req; if (!get_client_cred(client, &cred)) goto done; @@ -217,44 +226,46 @@ static void handle_request(pollfd *pfd) { goto done; code = read_int(client); - if (code < 0 || (code & DAEMON_CODE_MASK) >= DAEMON_CODE_END) + static_assert(is_scoped_enum_v); + + if (code < 0 || code >= DaemonRequest::END || code == DaemonRequest::_SYNC_BARRIER_) goto done; + req = static_cast(code); + // Check client permissions - switch (code) { - case POST_FS_DATA: - case LATE_START: - case BOOT_COMPLETE: - case SQLITE_CMD: - case GET_PATH: - case DENYLIST: - case STOP_DAEMON: + switch (req) { + case DaemonRequest::POST_FS_DATA: + case DaemonRequest::LATE_START: + case DaemonRequest::BOOT_COMPLETE: + case DaemonRequest::SQLITE_CMD: + case DaemonRequest::GET_PATH: + case DaemonRequest::DENYLIST: + case DaemonRequest::STOP_DAEMON: if (!is_root) { - write_int(client, ROOT_REQUIRED); + write_response(client, DaemonResponse::ROOT_REQUIRED); goto done; } break; - case REMOVE_MODULES: + case DaemonRequest::REMOVE_MODULES: if (!is_root && cred.uid != UID_SHELL) { - write_int(client, 1); + write_response(client, DaemonResponse::ROOT_REQUIRED); goto done; } break; - case ZYGISK_REQUEST: - if (!is_zygote) { - write_int(client, DAEMON_ERROR); - goto done; - } + default: break; } - if (code & SYNC_FLAG) { - handle_request_sync(client, code); + write_response(client, DaemonResponse::OK); + + if (req < DaemonRequest::_SYNC_BARRIER_) { + handle_request_sync(client, req); goto done; } // Handle complex requests in another thread - exec_task([=] { handle_request_async(client, code, cred); }); + exec_task([=] { handle_request_async(client, req, cred); }); return; done: @@ -376,7 +387,7 @@ static void daemon_entry() { sockaddr_un sun{}; socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET); fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (xbind(fd, (sockaddr*) &sun, len)) + if (xbind(fd, (sockaddr *) &sun, len)) exit(1); xlisten(fd, 10); @@ -391,11 +402,12 @@ static void daemon_entry() { poll_loop(); } -int connect_daemon(bool create) { +int connect_daemon(DaemonRequest req, bool create) { +// using enum DAEMON_RESPONSE; sockaddr_un sun{}; socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET); int fd = xsocket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (connect(fd, (sockaddr*) &sun, len)) { + if (connect(fd, (sockaddr *) &sun, len)) { if (!create || getuid() != UID_ROOT) { LOGE("No daemon is currently running!\n"); close(fd); @@ -407,8 +419,27 @@ int connect_daemon(bool create) { daemon_entry(); } - while (connect(fd, (struct sockaddr*) &sun, len)) + while (connect(fd, (struct sockaddr *) &sun, len)) usleep(10000); } + write_int(fd, static_cast(req)); + int ret = read_int(fd); + auto res = (ret < DaemonResponse::ERROR || ret >= DaemonResponse::END) ? DaemonResponse::ERROR + : static_cast(ret); + switch (res) { + case DaemonResponse::OK: + break; + case DaemonResponse::ERROR: + LOGE("Daemon error\n"); + exit(-1); + case DaemonResponse::ROOT_REQUIRED: + LOGE("Root is required for this operation\n"); + exit(-1); + case DaemonResponse::INVALID_REQUEST: + LOGE("Invalid request\n"); + exit(-1); + case DaemonResponse::END: + __builtin_unreachable(); + } return fd; } diff --git a/native/jni/core/magisk.cpp b/native/jni/core/magisk.cpp index b27af63fe..6247632a5 100644 --- a/native/jni/core/magisk.cpp +++ b/native/jni/core/magisk.cpp @@ -50,20 +50,19 @@ Available applets: } int magisk_main(int argc, char *argv[]) { +// using enum DAEMON_REQUEST; if (argc < 2) usage(); if (argv[1] == "-c"sv) { printf(MAGISK_VERSION ":MAGISK (" str(MAGISK_VER_CODE) ")\n"); return 0; } else if (argv[1] == "-v"sv) { - int fd = connect_daemon(); - write_int(fd, CHECK_VERSION); + int fd = connect_daemon(DaemonRequest::CHECK_VERSION); string v = read_string(fd); printf("%s\n", v.data()); return 0; } else if (argv[1] == "-V"sv) { - int fd = connect_daemon(); - write_int(fd, CHECK_VERSION_CODE); + int fd = connect_daemon(DaemonRequest::CHECK_VERSION_CODE); printf("%d\n", read_int(fd)); return 0; } else if (argv[1] == "--list"sv) { @@ -76,37 +75,32 @@ int magisk_main(int argc, char *argv[]) { } else if (argv[1] == "--restorecon"sv) { restorecon(); return 0; - } else if (argc >= 4 && argv[1] == "--clone-attr"sv) {; + } else if (argc >= 4 && argv[1] == "--clone-attr"sv) { clone_attr(argv[2], argv[3]); return 0; } else if (argc >= 4 && argv[1] == "--clone"sv) { cp_afc(argv[2], argv[3]); return 0; } else if (argv[1] == "--daemon"sv) { - int fd = connect_daemon(true); - write_int(fd, START_DAEMON); + int fd = connect_daemon(DaemonRequest::START_DAEMON, true); + close(fd); return 0; } else if (argv[1] == "--stop"sv) { - int fd = connect_daemon(); - write_int(fd, STOP_DAEMON); + int fd = connect_daemon(DaemonRequest::STOP_DAEMON); return read_int(fd); } else if (argv[1] == "--post-fs-data"sv) { - int fd = connect_daemon(true); - write_int(fd, POST_FS_DATA); + int fd = connect_daemon(DaemonRequest::POST_FS_DATA, true); return read_int(fd); } else if (argv[1] == "--service"sv) { - int fd = connect_daemon(true); - write_int(fd, LATE_START); + int fd = connect_daemon(DaemonRequest::LATE_START, true); return read_int(fd); } else if (argv[1] == "--boot-complete"sv) { - int fd = connect_daemon(true); - write_int(fd, BOOT_COMPLETE); + int fd = connect_daemon(DaemonRequest::BOOT_COMPLETE, true); return read_int(fd); } else if (argv[1] == "--denylist"sv) { return denylist_cli(argc - 1, argv + 1); - }else if (argc >= 3 && argv[1] == "--sqlite"sv) { - int fd = connect_daemon(); - write_int(fd, SQLITE_CMD); + } else if (argc >= 3 && argv[1] == "--sqlite"sv) { + int fd = connect_daemon(DaemonRequest::SQLITE_CMD); write_string(fd, argv[2]); string res; for (;;) { @@ -116,12 +110,10 @@ int magisk_main(int argc, char *argv[]) { printf("%s\n", res.data()); } } else if (argv[1] == "--remove-modules"sv) { - int fd = connect_daemon(); - write_int(fd, REMOVE_MODULES); + int fd = connect_daemon(DaemonRequest::REMOVE_MODULES); return read_int(fd); } else if (argv[1] == "--path"sv) { - int fd = connect_daemon(); - write_int(fd, GET_PATH); + int fd = connect_daemon(DaemonRequest::GET_PATH); string path = read_string(fd); printf("%s\n", path.data()); return 0; diff --git a/native/jni/include/daemon.hpp b/native/jni/include/daemon.hpp index 5968d6df8..d0db7c7ab 100644 --- a/native/jni/include/daemon.hpp +++ b/native/jni/include/daemon.hpp @@ -9,20 +9,17 @@ #include -// Daemon command code flags/masks -enum : int { - SYNC_FLAG = (1 << 30), - DAEMON_CODE_MASK = std::numeric_limits::max() >> 1 -}; - // Daemon command codes -enum : int { - START_DAEMON = SYNC_FLAG | 0, - CHECK_VERSION = SYNC_FLAG | 1, - CHECK_VERSION_CODE = SYNC_FLAG | 2, - GET_PATH = SYNC_FLAG | 3, - STOP_DAEMON = SYNC_FLAG | 4, - SUPERUSER = 5, +enum class DaemonRequest: int { + START_DAEMON, + CHECK_VERSION, + CHECK_VERSION_CODE, + GET_PATH, + STOP_DAEMON, + + _SYNC_BARRIER_, + + SUPERUSER, POST_FS_DATA, LATE_START, BOOT_COMPLETE, @@ -30,16 +27,16 @@ enum : int { SQLITE_CMD, REMOVE_MODULES, ZYGISK_REQUEST, - ZYGISK_PASSTHROUGH, - DAEMON_CODE_END, + END, }; // Return codes for daemon -enum : int { - DAEMON_ERROR = -1, - DAEMON_SUCCESS = 0, +enum class DaemonResponse: int { + ERROR = -1, + OK = 0, ROOT_REQUIRED, - DAEMON_LAST + INVALID_REQUEST, + END }; struct module_info { @@ -55,7 +52,7 @@ extern int app_process_32; extern int app_process_64; extern std::vector *module_list; -int connect_daemon(bool create = false); +int connect_daemon(DaemonRequest req, bool create = false); // Poll control using poll_callback = void(*)(pollfd*); @@ -81,5 +78,4 @@ void zygisk_handler(int client, const sock_cred *cred); // Denylist void initialize_denylist(); -int disable_deny(); int denylist_cli(int argc, char **argv); diff --git a/native/jni/init/rootdir.cpp b/native/jni/init/rootdir.cpp index e434ad4fd..2e04d2452 100644 --- a/native/jni/init/rootdir.cpp +++ b/native/jni/init/rootdir.cpp @@ -240,7 +240,7 @@ void SARBase::patch_rootdir() { make_pair(SPLIT_PLAT_CIL, "xxx"), /* Force loading monolithic sepolicy */ make_pair(MONOPOLICY, sepol) /* Redirect /sepolicy to custom path */ }); - if (avd_hack) { + if constexpr (avd_hack) { // Force disable early mount on original init init.patch({ make_pair("android,fstab", "xxx") }); } diff --git a/native/jni/su/su.cpp b/native/jni/su/su.cpp index 6cc1af2d4..bb8f606f2 100644 --- a/native/jni/su/su.cpp +++ b/native/jni/su/su.cpp @@ -159,10 +159,7 @@ int su_client_main(int argc, char *argv[]) { int ptmx, fd; // Connect to client - fd = connect_daemon(); - - // Tell the daemon we are su - write_int(fd, SUPERUSER); + fd = connect_daemon(DaemonRequest::SUPERUSER); // Send su_request xwrite(fd, &su_req, sizeof(su_req_base)); diff --git a/native/jni/utils/misc.hpp b/native/jni/utils/misc.hpp index 8a8828dcc..d242122a1 100644 --- a/native/jni/utils/misc.hpp +++ b/native/jni/utils/misc.hpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include "xwrap.hpp" #define UID_ROOT 0 #define UID_SHELL 2000 @@ -197,3 +199,32 @@ void exec_command_async(Args &&...args) { }; exec_command(exec); } + +template > +struct __is_scoped_enum_helper : std::false_type {}; + +template +struct __is_scoped_enum_helper<_Tp, true> +: public std::bool_constant > > {}; + +template +struct is_scoped_enum + : public __is_scoped_enum_helper<_Tp> {}; + +template +inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value; + +template requires( is_scoped_enum_v ) +constexpr inline auto operator <=> (std::underlying_type_t a, Enum b) { + return a <=> static_cast>(b); +} + +template requires( is_scoped_enum_v ) +constexpr inline auto operator != (std::underlying_type_t a, Enum b) { + return a != static_cast>(b); +} + +template requires( is_scoped_enum_v ) +constexpr inline auto operator == (std::underlying_type_t a, Enum b) { + return a == static_cast>(b); +} diff --git a/native/jni/zygisk/deny/cli.cpp b/native/jni/zygisk/deny/cli.cpp index 98f26de4e..b0cbafa3e 100644 --- a/native/jni/zygisk/deny/cli.cpp +++ b/native/jni/zygisk/deny/cli.cpp @@ -32,31 +32,40 @@ void denylist_handler(int client, const sock_cred *cred) { return; } - int req = read_int(client); - int res = DAEMON_ERROR; + DenyResponse res = DenyResponse::ERROR; - switch (req) { - case ENFORCE_DENY: - res = enable_deny(); - break; - case DISABLE_DENY: - res = disable_deny(); - break; - case ADD_LIST: - res = add_list(client); - break; - case RM_LIST: - res = rm_list(client); - break; - case LS_LIST: - ls_list(client); - return; - case DENY_STATUS: - res = (zygisk_enabled && denylist_enforced) ? DENY_IS_ENFORCED : DENY_NOT_ENFORCED; - break; + int code = read_int(client); + auto req = static_cast(code); + + if (code < 0 || code >= DenyRequest::END) { + goto done; } - write_int(client, res); + switch (req) { + case DenyRequest::ENFORCE: + res = enable_deny(); + break; + case DenyRequest::DISABLE: + res = disable_deny(); + break; + case DenyRequest::ADD: + res = add_list(client); + break; + case DenyRequest::REMOVE: + res = rm_list(client); + break; + case DenyRequest::LIST: + ls_list(client); + return; + case DenyRequest::STATUS: + res = (zygisk_enabled && denylist_enforced) ? DenyResponse::ENFORCED + : DenyResponse::NOT_ENFORCED; + break; + case DenyRequest::END: + __builtin_unreachable(); + } +done: + write_int(client, static_cast(res)); close(client); } @@ -64,19 +73,19 @@ int denylist_cli(int argc, char **argv) { if (argc < 2) usage(); - int req; + DenyRequest req; if (argv[1] == "enable"sv) - req = ENFORCE_DENY; + req = DenyRequest::ENFORCE; else if (argv[1] == "disable"sv) - req = DISABLE_DENY; + req = DenyRequest::DISABLE; else if (argv[1] == "add"sv) - req = ADD_LIST; + req = DenyRequest::ADD; else if (argv[1] == "rm"sv) - req = RM_LIST; + req = DenyRequest::REMOVE; else if (argv[1] == "ls"sv) - req = LS_LIST; + req = DenyRequest::LIST; else if (argv[1] == "status"sv) - req = DENY_STATUS; + req = DenyRequest::STATUS; else if (argv[1] == "exec"sv && argc > 2) { xunshare(CLONE_NEWNS); xmount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr); @@ -88,56 +97,54 @@ int denylist_cli(int argc, char **argv) { } // Send request - int fd = connect_daemon(); - write_int(fd, DENYLIST); - write_int(fd, req); - if (req == ADD_LIST || req == RM_LIST) { + int fd = deny_request(req); + if (req == DenyRequest::ADD || req == DenyRequest::REMOVE) { write_string(fd, argv[2]); write_string(fd, argv[3] ? argv[3] : ""); } // Get response int code = read_int(fd); - switch (code) { - case DAEMON_SUCCESS: - break; - case DENY_NOT_ENFORCED: + auto res = (code < 0 || code >= DenyResponse::END) ? DenyResponse::ERROR + : static_cast(code); + switch (res) { + case DenyResponse::NOT_ENFORCED: fprintf(stderr, "Denylist is not enforced\n"); goto return_code; - case DENY_IS_ENFORCED: + case DenyResponse::ENFORCED: fprintf(stderr, "Denylist is enforced\n"); goto return_code; - case DENYLIST_ITEM_EXIST: + case DenyResponse::ITEM_EXIST: fprintf(stderr, "Target already exists in denylist\n"); goto return_code; - case DENYLIST_ITEM_NOT_EXIST: + case DenyResponse::ITEM_NOT_EXIST: fprintf(stderr, "Target does not exist in denylist\n"); goto return_code; - case DENY_NO_NS: + case DenyResponse::NO_NS: fprintf(stderr, "The kernel does not support mount namespace\n"); goto return_code; - case DENYLIST_INVALID_PKG: + case DenyResponse::INVALID_PKG: fprintf(stderr, "Invalid package / process name\n"); goto return_code; - case ROOT_REQUIRED: - fprintf(stderr, "Root is required for this operation\n"); - goto return_code; - case DAEMON_ERROR: - default: - fprintf(stderr, "Daemon error\n"); - return DAEMON_ERROR; + case DenyResponse::ERROR: + fprintf(stderr, "deny: Daemon error\n"); + return -1; + case DenyResponse::OK: + break; + case DenyResponse::END: + __builtin_unreachable(); } - if (req == LS_LIST) { - string res; + if (req == DenyRequest::LIST) { + string out; for (;;) { - read_string(fd, res); - if (res.empty()) + read_string(fd, out); + if (out.empty()) break; - printf("%s\n", res.data()); + printf("%s\n", out.data()); } } return_code: - return req == DENY_STATUS ? (code == DENY_IS_ENFORCED ? 0 : 1) : code != DAEMON_SUCCESS; + return req == DenyRequest::STATUS ? res != DenyResponse::ENFORCED : res != DenyResponse::OK; } diff --git a/native/jni/zygisk/deny/deny.hpp b/native/jni/zygisk/deny/deny.hpp index 41433888c..d87d97399 100644 --- a/native/jni/zygisk/deny/deny.hpp +++ b/native/jni/zygisk/deny/deny.hpp @@ -10,11 +10,36 @@ #define ISOLATED_MAGIC "isolated" +enum class DenyRequest : int { + ENFORCE, + DISABLE, + ADD, + REMOVE, + LIST, + STATUS, + + END +}; + +enum class DenyResponse: int { + OK, + ENFORCED, + NOT_ENFORCED, + ITEM_EXIST, + ITEM_NOT_EXIST, + INVALID_PKG, + NO_NS, + ERROR, + + END +}; + + // CLI entries -int enable_deny(); -int disable_deny(); -int add_list(int client); -int rm_list(int client); +DenyResponse enable_deny(); +DenyResponse disable_deny(); +DenyResponse add_list(int client); +DenyResponse rm_list(int client); void ls_list(int client); // Utility functions @@ -25,20 +50,8 @@ void revert_unmount(); extern std::atomic denylist_enforced; extern std::atomic cached_manager_app_id; -enum : int { - ENFORCE_DENY, - DISABLE_DENY, - ADD_LIST, - RM_LIST, - LS_LIST, - DENY_STATUS, -}; - -enum : int { - DENY_IS_ENFORCED = DAEMON_LAST + 1, - DENY_NOT_ENFORCED, - DENYLIST_ITEM_EXIST, - DENYLIST_ITEM_NOT_EXIST, - DENYLIST_INVALID_PKG, - DENY_NO_NS, -}; +inline int deny_request(DenyRequest req) { + int fd = connect_daemon(DaemonRequest::DENYLIST); + write_int(fd, static_cast>(req)); + return fd; +} diff --git a/native/jni/zygisk/deny/utils.cpp b/native/jni/zygisk/deny/utils.cpp index 6ed961737..37bdd1382 100644 --- a/native/jni/zygisk/deny/utils.cpp +++ b/native/jni/zygisk/deny/utils.cpp @@ -226,20 +226,20 @@ error: return false; } -static int add_list(const char *pkg, const char *proc) { +static DenyResponse add_list(const char *pkg, const char *proc) { if (proc[0] == '\0') proc = pkg; if (!validate(pkg, proc)) - return DENYLIST_INVALID_PKG; + return DenyResponse::INVALID_PKG; { mutex_guard lock(data_lock); if (!ensure_data()) - return DAEMON_ERROR; + return DenyResponse::ERROR; auto p = add_hide_set(pkg, proc); if (!p.second) - return DENYLIST_ITEM_EXIST; + return DenyResponse::ITEM_EXIST; update_pkg_uid(*p.first, false); } @@ -248,21 +248,21 @@ static int add_list(const char *pkg, const char *proc) { snprintf(sql, sizeof(sql), "INSERT INTO denylist (package_name, process) VALUES('%s', '%s')", pkg, proc); char *err = db_exec(sql); - db_err_cmd(err, return DAEMON_ERROR) - return DAEMON_SUCCESS; + db_err_cmd(err, return DenyResponse::ERROR) + return DenyResponse::OK; } -int add_list(int client) { +DenyResponse add_list(int client) { string pkg = read_string(client); string proc = read_string(client); return add_list(pkg.data(), proc.data()); } -static int rm_list(const char *pkg, const char *proc) { +static DenyResponse rm_list(const char *pkg, const char *proc) { { mutex_guard lock(data_lock); if (!ensure_data()) - return DAEMON_ERROR; + return DenyResponse::ERROR; bool remove = false; @@ -284,7 +284,7 @@ static int rm_list(const char *pkg, const char *proc) { } if (!remove) - return DENYLIST_ITEM_NOT_EXIST; + return DenyResponse::ITEM_NOT_EXIST; } char sql[4096]; @@ -294,11 +294,11 @@ static int rm_list(const char *pkg, const char *proc) { snprintf(sql, sizeof(sql), "DELETE FROM denylist WHERE package_name='%s' AND process='%s'", pkg, proc); char *err = db_exec(sql); - db_err_cmd(err, return DAEMON_ERROR) - return DAEMON_SUCCESS; + db_err_cmd(err, return DenyResponse::ERROR) + return DenyResponse::OK; } -int rm_list(int client) { +DenyResponse rm_list(int client) { string pkg = read_string(client); string proc = read_string(client); return rm_list(pkg.data(), proc.data()); @@ -308,11 +308,11 @@ void ls_list(int client) { { mutex_guard lock(data_lock); if (!ensure_data()) { - write_int(client, DAEMON_ERROR); + write_int(client, static_cast(DenyResponse::ERROR)); return; } - write_int(client, DAEMON_SUCCESS); + write_int(client,static_cast(DenyResponse::OK)); for (const auto &[pkg, procs] : pkg_to_procs) { for (const auto &proc : procs) { @@ -342,19 +342,19 @@ static void update_deny_config() { db_err(err); } -int enable_deny() { +DenyResponse enable_deny() { if (denylist_enforced) { - return DAEMON_SUCCESS; + return DenyResponse::OK; } else { mutex_guard lock(data_lock); if (access("/proc/self/ns/mnt", F_OK) != 0) { LOGW("The kernel does not support mount namespace\n"); - return DENY_NO_NS; + return DenyResponse::NO_NS; } if (procfp == nullptr && (procfp = opendir("/proc")) == nullptr) - return DAEMON_ERROR; + return DenyResponse::ERROR; LOGI("* Enable DenyList\n"); @@ -362,7 +362,7 @@ int enable_deny() { if (!ensure_data()) { denylist_enforced = false; - return DAEMON_ERROR; + return DenyResponse::ERROR; } // On Android Q+, also kill blastula pool and all app zygotes @@ -374,16 +374,16 @@ int enable_deny() { } update_deny_config(); - return DAEMON_SUCCESS; + return DenyResponse::OK; } -int disable_deny() { +DenyResponse disable_deny() { if (denylist_enforced) { denylist_enforced = false; LOGI("* Disable DenyList\n"); } update_deny_config(); - return DAEMON_SUCCESS; + return DenyResponse::OK; } void initialize_denylist() { diff --git a/native/jni/zygisk/entry.cpp b/native/jni/zygisk/entry.cpp index aa277f067..92aded483 100644 --- a/native/jni/zygisk/entry.cpp +++ b/native/jni/zygisk/entry.cpp @@ -142,9 +142,7 @@ static int zygisk_log(int prio, const char *fmt, va_list ap) { if (logd_fd < 0) { // Change logging temporarily to prevent infinite recursion and stack overflow android_logging(); - if (int fd = connect_daemon(); fd >= 0) { - write_int(fd, ZYGISK_REQUEST); - write_int(fd, ZYGISK_GET_LOG_PIPE); + if (int fd = zygisk_request(ZygiskRequest::GET_LOG_PIPE); fd >= 0) { if (read_int(fd) == 0) { logd_fd = recv_fd(fd); } @@ -178,10 +176,7 @@ static inline bool should_load_modules(uint32_t flags) { } int remote_get_info(int uid, const char *process, uint32_t *flags, vector &fds) { - if (int fd = connect_daemon(); fd >= 0) { - write_int(fd, ZYGISK_REQUEST); - write_int(fd, ZYGISK_GET_INFO); - + if (int fd = zygisk_request(ZygiskRequest::GET_INFO); fd >= 0) { write_int(fd, uid); write_string(fd, process); xxread(fd, flags, sizeof(*flags)); @@ -404,28 +399,39 @@ static void get_moddir(int client) { } void zygisk_handler(int client, const sock_cred *cred) { +// using enum ZYGISK_REQUEST; int code = read_int(client); char buf[256]; - switch (code) { - case ZYGISK_SETUP: + if (code < ZygiskRequest::SETUP || code >= ZygiskRequest::END) { + write_int(client, -1); + return; + } + auto req = static_cast(code); + if (req != ZygiskRequest::PASSTHROUGH && cred->context != "u:r:zygote:s0") { + return; + } + switch (req) { + case ZygiskRequest::SETUP: setup_files(client, cred); break; - case ZYGISK_PASSTHROUGH: + case ZygiskRequest::PASSTHROUGH: magiskd_passthrough(client); break; - case ZYGISK_GET_INFO: + case ZygiskRequest::GET_INFO: get_process_info(client, cred); break; - case ZYGISK_GET_LOG_PIPE: + case ZygiskRequest::GET_LOG_PIPE: send_log_pipe(client); break; - case ZYGISK_CONNECT_COMPANION: + case ZygiskRequest::CONNECT_COMPANION: get_exe(cred->pid, buf, sizeof(buf)); connect_companion(client, str_ends(buf, "64")); break; - case ZYGISK_GET_MODDIR: + case ZygiskRequest::GET_MODDIR: get_moddir(client); break; + case ZygiskRequest::END: + __builtin_unreachable(); } close(client); } diff --git a/native/jni/zygisk/hook.cpp b/native/jni/zygisk/hook.cpp index 3c413feaa..a279bdf27 100644 --- a/native/jni/zygisk/hook.cpp +++ b/native/jni/zygisk/hook.cpp @@ -317,9 +317,7 @@ bool ZygiskModule::RegisterModule(ApiTable *table, long *module) { } int ZygiskModule::connectCompanion() const { - if (int fd = connect_daemon(); fd >= 0) { - write_int(fd, ZYGISK_REQUEST); - write_int(fd, ZYGISK_CONNECT_COMPANION); + if (int fd = zygisk_request(ZygiskRequest::CONNECT_COMPANION); fd >= 0) { write_int(fd, id); return fd; } @@ -327,9 +325,7 @@ int ZygiskModule::connectCompanion() const { } int ZygiskModule::getModuleDir() const { - if (int fd = connect_daemon(); fd >= 0) { - write_int(fd, ZYGISK_REQUEST); - write_int(fd, ZYGISK_GET_MODDIR); + if (int fd = zygisk_request(ZygiskRequest::GET_MODDIR); fd >= 0) { write_int(fd, id); int dfd = recv_fd(fd); close(fd); diff --git a/native/jni/zygisk/main.cpp b/native/jni/zygisk/main.cpp index 209b772b2..3fbee0ed1 100644 --- a/native/jni/zygisk/main.cpp +++ b/native/jni/zygisk/main.cpp @@ -57,11 +57,8 @@ int app_process_main(int argc, char *argv[]) { return 1; } - if (int socket = connect_daemon(); socket >= 0) { + if (int socket = zygisk_request(ZygiskRequest::SETUP); socket >= 0) { do { - write_int(socket, ZYGISK_REQUEST); - write_int(socket, ZYGISK_SETUP); - if (read_int(socket) != 0) break; @@ -176,9 +173,7 @@ int zygisk_main(int argc, char *argv[]) { int is_64_bit = parse_int(argv[3]); if (fcntl(client, F_GETFD) < 0) return 1; - if (int magiskd = connect_daemon(); magiskd >= 0) { - write_int(magiskd, ZYGISK_PASSTHROUGH); - write_int(magiskd, ZYGISK_PASSTHROUGH); + if (int magiskd = zygisk_request(ZygiskRequest::PASSTHROUGH); magiskd >= 0) { write_int(magiskd, is_64_bit); if (read_int(magiskd) != 0) { diff --git a/native/jni/zygisk/zygisk.hpp b/native/jni/zygisk/zygisk.hpp index ddc1076c5..4152454bc 100644 --- a/native/jni/zygisk/zygisk.hpp +++ b/native/jni/zygisk/zygisk.hpp @@ -3,18 +3,21 @@ #include #include #include +#include #define INJECT_ENV_1 "MAGISK_INJ_1" #define INJECT_ENV_2 "MAGISK_INJ_2" #define MAGISKFD_ENV "MAGISKFD" #define MAGISKTMP_ENV "MAGISKTMP" -enum : int { - ZYGISK_SETUP, - ZYGISK_GET_INFO, - ZYGISK_GET_LOG_PIPE, - ZYGISK_CONNECT_COMPANION, - ZYGISK_GET_MODDIR, +enum class ZygiskRequest : int { + SETUP, + GET_INFO, + GET_LOG_PIPE, + CONNECT_COMPANION, + GET_MODDIR, + PASSTHROUGH, + END }; #if defined(__LP64__) @@ -47,3 +50,10 @@ extern void *self_handle; void hook_functions(); int remote_get_info(int uid, const char *process, uint32_t *flags, std::vector &fds); int remote_request_unmount(); + + +inline int zygisk_request(ZygiskRequest req) { + int fd = connect_daemon(DaemonRequest::ZYGISK_REQUEST, false); + write_int(fd, static_cast(req)); + return fd; +}