mirror of
				https://github.com/topjohnwu/Magisk.git
				synced 2025-10-25 06:49:06 +00:00 
			
		
		
		
	Add new Zygisk API to get module dir
This commit is contained in:
		| @@ -541,15 +541,7 @@ static void inject_magisk_bins(root_node *system) { | |||||||
|         delete bin->extract(init_applet[i]); |         delete bin->extract(init_applet[i]); | ||||||
| } | } | ||||||
|  |  | ||||||
| struct module_info { | vector<module_info> *module_list; | ||||||
|     string name; |  | ||||||
|     int z32 = -1; |  | ||||||
| #if defined(__LP64__) |  | ||||||
|     int z64 = -1; |  | ||||||
| #endif |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| static vector<module_info> *modules; |  | ||||||
| int app_process_32 = -1; | int app_process_32 = -1; | ||||||
| int app_process_64 = -1; | int app_process_64 = -1; | ||||||
|  |  | ||||||
| @@ -577,8 +569,8 @@ void magic_mount() { | |||||||
|  |  | ||||||
|     char buf[4096]; |     char buf[4096]; | ||||||
|     LOGI("* Loading modules\n"); |     LOGI("* Loading modules\n"); | ||||||
|     if (modules) { |     if (module_list) { | ||||||
|         for (const auto &m : *modules) { |         for (const auto &m : *module_list) { | ||||||
|             const char *module = m.name.data(); |             const char *module = m.name.data(); | ||||||
|             char *b = buf + sprintf(buf, "%s/" MODULEMNT "/%s/", MAGISKTMP.data(), module); |             char *b = buf + sprintf(buf, "%s/" MODULEMNT "/%s/", MAGISKTMP.data(), module); | ||||||
|  |  | ||||||
| @@ -732,7 +724,7 @@ static void collect_modules(bool open_zygisk) { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         info.name = entry->d_name; |         info.name = entry->d_name; | ||||||
|         modules->push_back(info); |         module_list->push_back(info); | ||||||
|     }); |     }); | ||||||
|     if (open_zygisk && zygisk_enabled) { |     if (open_zygisk && zygisk_enabled) { | ||||||
|         bool use_memfd = true; |         bool use_memfd = true; | ||||||
| @@ -752,7 +744,7 @@ static void collect_modules(bool open_zygisk) { | |||||||
|             } |             } | ||||||
|             return fd; |             return fd; | ||||||
|         }; |         }; | ||||||
|         std::for_each(modules->begin(), modules->end(), [&](module_info &info) { |         std::for_each(module_list->begin(), module_list->end(), [&](module_info &info) { | ||||||
|             info.z32 = convert_to_memfd(info.z32); |             info.z32 = convert_to_memfd(info.z32); | ||||||
| #if defined(__LP64__) | #if defined(__LP64__) | ||||||
|             info.z64 = convert_to_memfd(info.z64); |             info.z64 = convert_to_memfd(info.z64); | ||||||
| @@ -762,13 +754,13 @@ static void collect_modules(bool open_zygisk) { | |||||||
| } | } | ||||||
|  |  | ||||||
| void handle_modules() { | void handle_modules() { | ||||||
|     default_new(modules); |     default_new(module_list); | ||||||
|     prepare_modules(); |     prepare_modules(); | ||||||
|     collect_modules(false); |     collect_modules(false); | ||||||
|     exec_module_scripts("post-fs-data"); |     exec_module_scripts("post-fs-data"); | ||||||
|  |  | ||||||
|     // Recollect modules (module scripts could remove itself) |     // Recollect modules (module scripts could remove itself) | ||||||
|     modules->clear(); |     module_list->clear(); | ||||||
|     collect_modules(true); |     collect_modules(true); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -789,24 +781,7 @@ void remove_modules() { | |||||||
|  |  | ||||||
| void exec_module_scripts(const char *stage) { | void exec_module_scripts(const char *stage) { | ||||||
|     vector<string_view> module_names; |     vector<string_view> module_names; | ||||||
|     std::transform(modules->begin(), modules->end(), std::back_inserter(module_names), |     std::transform(module_list->begin(), module_list->end(), std::back_inserter(module_names), | ||||||
|         [](const module_info &info) -> string_view { return info.name; }); |         [](const module_info &info) -> string_view { return info.name; }); | ||||||
|     exec_module_scripts(stage, module_names); |     exec_module_scripts(stage, module_names); | ||||||
| } | } | ||||||
|  |  | ||||||
| vector<int> zygisk_module_fds(bool is_64_bit) { |  | ||||||
|     vector<int> fds; |  | ||||||
|     // All fds passed to send_fds have to be valid file descriptors. |  | ||||||
|     // To workaround this issue, send over STDOUT_FILENO as an indicator of an |  | ||||||
|     // invalid fd as it will always be /dev/null in magiskd |  | ||||||
|     if (is_64_bit) { |  | ||||||
| #if defined(__LP64__) |  | ||||||
|         std::transform(modules->begin(), modules->end(), std::back_inserter(fds), |  | ||||||
|             [](const module_info &info) { return info.z64 < 0 ? STDOUT_FILENO : info.z64; }); |  | ||||||
| #endif |  | ||||||
|     } else { |  | ||||||
|         std::transform(modules->begin(), modules->end(), std::back_inserter(fds), |  | ||||||
|             [](const module_info &info) { return info.z32 < 0 ? STDOUT_FILENO : info.z32; }); |  | ||||||
|     } |  | ||||||
|     return fds; |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -42,9 +42,18 @@ enum : int { | |||||||
|     DAEMON_LAST |     DAEMON_LAST | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct module_info { | ||||||
|  |     std::string name; | ||||||
|  |     int z32 = -1; | ||||||
|  | #if defined(__LP64__) | ||||||
|  |     int z64 = -1; | ||||||
|  | #endif | ||||||
|  | }; | ||||||
|  |  | ||||||
| extern bool zygisk_enabled; | extern bool zygisk_enabled; | ||||||
| extern int app_process_32; | extern int app_process_32; | ||||||
| extern int app_process_64; | extern int app_process_64; | ||||||
|  | extern std::vector<module_info> *module_list; | ||||||
|  |  | ||||||
| int connect_daemon(bool create = false); | int connect_daemon(bool create = false); | ||||||
|  |  | ||||||
| @@ -69,7 +78,6 @@ void boot_complete(int client); | |||||||
| void denylist_handler(int client, const sock_cred *cred); | void denylist_handler(int client, const sock_cred *cred); | ||||||
| void su_daemon_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); | void zygisk_handler(int client, const sock_cred *cred); | ||||||
| std::vector<int> zygisk_module_fds(bool is_64_bit); |  | ||||||
|  |  | ||||||
| // Denylist | // Denylist | ||||||
| void initialize_denylist(); | void initialize_denylist(); | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ | |||||||
|  |  | ||||||
| #include <jni.h> | #include <jni.h> | ||||||
|  |  | ||||||
| #define ZYGISK_API_VERSION 1 | #define ZYGISK_API_VERSION 2 | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  |  | ||||||
| @@ -173,6 +173,16 @@ struct Api { | |||||||
|     // module's companion request handler. Returns -1 if the connection attempt failed. |     // module's companion request handler. Returns -1 if the connection attempt failed. | ||||||
|     int connectCompanion(); |     int connectCompanion(); | ||||||
|  |  | ||||||
|  |     // Get the file descriptor of the root folder of the current module. | ||||||
|  |     // | ||||||
|  |     // This API only works in the pre[XXX]Specialize functions. | ||||||
|  |     // Accessing the directory returned is only possible in the pre[XXX]Specialize functions | ||||||
|  |     // or in the root companion process (assuming that you sent the fd over the socket). | ||||||
|  |     // Both restrictions are due to SELinux and UID. | ||||||
|  |     // | ||||||
|  |     // Returns -1 if errors occurred. | ||||||
|  |     int getModuleDir(); | ||||||
|  |  | ||||||
|     // Set various options for your module. |     // Set various options for your module. | ||||||
|     // Please note that this function accepts one single option at a time. |     // Please note that this function accepts one single option at a time. | ||||||
|     // Check zygisk::Option for the full list of options available. |     // Check zygisk::Option for the full list of options available. | ||||||
| @@ -261,6 +271,7 @@ struct api_table { | |||||||
|     // Zygisk functions |     // Zygisk functions | ||||||
|     int  (*connectCompanion)(void * /* _this */); |     int  (*connectCompanion)(void * /* _this */); | ||||||
|     void (*setOption)(void * /* _this */, Option); |     void (*setOption)(void * /* _this */, Option); | ||||||
|  |     int  (*getModuleDir)(void * /* _this */); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <class T> | template <class T> | ||||||
| @@ -278,6 +289,9 @@ void entry_impl(api_table *table, JNIEnv *env) { | |||||||
| inline int Api::connectCompanion() { | inline int Api::connectCompanion() { | ||||||
|     return impl->connectCompanion ? impl->connectCompanion(impl->_this) : -1; |     return impl->connectCompanion ? impl->connectCompanion(impl->_this) : -1; | ||||||
| } | } | ||||||
|  | inline int Api::getModuleDir() { | ||||||
|  |     return impl->getModuleDir ? impl->getModuleDir(impl->_this) : -1; | ||||||
|  | } | ||||||
| inline void Api::setOption(Option opt) { | inline void Api::setOption(Option opt) { | ||||||
|     if (impl->setOption) impl->setOption(impl->_this, opt); |     if (impl->setOption) impl->setOption(impl->_this, opt); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -185,6 +185,23 @@ std::vector<int> remote_get_info(int uid, const char *process, AppInfo *info) { | |||||||
|  |  | ||||||
| // The following code runs in magiskd | // The following code runs in magiskd | ||||||
|  |  | ||||||
|  | static vector<int> get_module_fds(bool is_64_bit) { | ||||||
|  |     vector<int> fds; | ||||||
|  |     // All fds passed to send_fds have to be valid file descriptors. | ||||||
|  |     // To workaround this issue, send over STDOUT_FILENO as an indicator of an | ||||||
|  |     // invalid fd as it will always be /dev/null in magiskd | ||||||
|  |     if (is_64_bit) { | ||||||
|  | #if defined(__LP64__) | ||||||
|  |         std::transform(module_list->begin(), module_list->end(), std::back_inserter(fds), | ||||||
|  |             [](const module_info &info) { return info.z64 < 0 ? STDOUT_FILENO : info.z64; }); | ||||||
|  | #endif | ||||||
|  |     } else { | ||||||
|  |         std::transform(module_list->begin(), module_list->end(), std::back_inserter(fds), | ||||||
|  |             [](const module_info &info) { return info.z32 < 0 ? STDOUT_FILENO : info.z32; }); | ||||||
|  |     } | ||||||
|  |     return fds; | ||||||
|  | } | ||||||
|  |  | ||||||
| static bool get_exe(int pid, char *buf, size_t sz) { | static bool get_exe(int pid, char *buf, size_t sz) { | ||||||
|     snprintf(buf, sz, "/proc/%d/exe", pid); |     snprintf(buf, sz, "/proc/%d/exe", pid); | ||||||
|     return xreadlink(buf, buf, sz) > 0; |     return xreadlink(buf, buf, sz) > 0; | ||||||
| @@ -221,7 +238,7 @@ static void connect_companion(int client, bool is_64_bit) { | |||||||
|             exit(-1); |             exit(-1); | ||||||
|         } |         } | ||||||
|         close(fds[1]); |         close(fds[1]); | ||||||
|         vector<int> module_fds = zygisk_module_fds(is_64_bit); |         vector<int> module_fds = get_module_fds(is_64_bit); | ||||||
|         send_fds(zygiskd_socket, module_fds.data(), module_fds.size()); |         send_fds(zygiskd_socket, module_fds.data(), module_fds.size()); | ||||||
|         // Wait for ack |         // Wait for ack | ||||||
|         if (read_int(zygiskd_socket) != 0) { |         if (read_int(zygiskd_socket) != 0) { | ||||||
| @@ -342,7 +359,7 @@ static void get_process_info(int client, const sock_cred *cred) { | |||||||
|     if (!info.on_denylist) { |     if (!info.on_denylist) { | ||||||
|         char buf[256]; |         char buf[256]; | ||||||
|         get_exe(cred->pid, buf, sizeof(buf)); |         get_exe(cred->pid, buf, sizeof(buf)); | ||||||
|         vector<int> fds = zygisk_module_fds(str_ends(buf, "64")); |         vector<int> fds = get_module_fds(str_ends(buf, "64")); | ||||||
|         send_fds(client, fds.data(), fds.size()); |         send_fds(client, fds.data(), fds.size()); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -357,6 +374,15 @@ static void send_log_pipe(int fd) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void get_moddir(int client) { | ||||||
|  |     int id = read_int(client); | ||||||
|  |     char buf[4096]; | ||||||
|  |     snprintf(buf, sizeof(buf), MODULEROOT "/%s", module_list->operator[](id).name.data()); | ||||||
|  |     int dfd = xopen(buf, O_RDONLY | O_CLOEXEC); | ||||||
|  |     send_fd(client, dfd); | ||||||
|  |     close(dfd); | ||||||
|  | } | ||||||
|  |  | ||||||
| void zygisk_handler(int client, const sock_cred *cred) { | void zygisk_handler(int client, const sock_cred *cred) { | ||||||
|     int code = read_int(client); |     int code = read_int(client); | ||||||
|     char buf[256]; |     char buf[256]; | ||||||
| @@ -377,6 +403,9 @@ void zygisk_handler(int client, const sock_cred *cred) { | |||||||
|         get_exe(cred->pid, buf, sizeof(buf)); |         get_exe(cred->pid, buf, sizeof(buf)); | ||||||
|         connect_companion(client, str_ends(buf, "64")); |         connect_companion(client, str_ends(buf, "64")); | ||||||
|         break; |         break; | ||||||
|  |     case ZYGISK_GET_MODDIR: | ||||||
|  |         get_moddir(client); | ||||||
|  |         break; | ||||||
|     } |     } | ||||||
|     close(client); |     close(client); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -294,16 +294,26 @@ bool ZygiskModule::RegisterModule(ApiTable *table, long *module) { | |||||||
|     table->module->ver = module; |     table->module->ver = module; | ||||||
|  |  | ||||||
|     // Fill in API accordingly with module API version |     // Fill in API accordingly with module API version | ||||||
|     table->v1.hookJniNativeMethods = &hookJniNativeMethods; |     switch (ver) { | ||||||
|     table->v1.pltHookRegister = [](const char *path, const char *symbol, void *n, void **o) { |     case 2: | ||||||
|         xhook_register(path, symbol, n, o); |         table->v2.getModuleDir = [](ZygiskModule *m) { return m->getModuleDir(); }; | ||||||
|     }; |         [[fallthrough]]; | ||||||
|     table->v1.pltHookExclude = [](const char *path, const char *symbol) { |     case 1: | ||||||
|         xhook_ignore(path, symbol); |         table->v1.hookJniNativeMethods = &hookJniNativeMethods; | ||||||
|     }; |         table->v1.pltHookRegister = [](const char *p, const char *s, void *n, void **o) { | ||||||
|     table->v1.pltHookCommit = []{ bool r = xhook_refresh(0) == 0; xhook_clear(); return r; }; |             xhook_register(p, s, n, o); | ||||||
|     table->v1.connectCompanion = [](ZygiskModule *m) { return m->connectCompanion(); }; |         }; | ||||||
|     table->v1.setOption = [](ZygiskModule *m, auto opt) { m->setOption(opt); }; |         table->v1.pltHookExclude = [](const char *p, const char *s) { | ||||||
|  |             xhook_ignore(p, s); | ||||||
|  |         }; | ||||||
|  |         table->v1.pltHookCommit = []{ bool r = xhook_refresh(0) == 0; xhook_clear(); return r; }; | ||||||
|  |         table->v1.connectCompanion = [](ZygiskModule *m) { return m->connectCompanion(); }; | ||||||
|  |         table->v1.setOption = [](ZygiskModule *m, auto opt) { m->setOption(opt); }; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         // Unknown version number | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| @@ -318,6 +328,18 @@ int ZygiskModule::connectCompanion() const { | |||||||
|     return -1; |     return -1; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int ZygiskModule::getModuleDir() const { | ||||||
|  |     if (int fd = connect_daemon(); fd >= 0) { | ||||||
|  |         write_int(fd, ZYGISK_REQUEST); | ||||||
|  |         write_int(fd, ZYGISK_GET_MODDIR); | ||||||
|  |         write_int(fd, id); | ||||||
|  |         int dfd = recv_fd(fd); | ||||||
|  |         close(fd); | ||||||
|  |         return dfd; | ||||||
|  |     } | ||||||
|  |     return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
| void ZygiskModule::setOption(zygisk::Option opt) { | void ZygiskModule::setOption(zygisk::Option opt) { | ||||||
|     if (g_ctx == nullptr) |     if (g_ctx == nullptr) | ||||||
|         return; |         return; | ||||||
|   | |||||||
| @@ -81,6 +81,9 @@ struct ApiTable { | |||||||
|         int (*connectCompanion)(ZygiskModule *); |         int (*connectCompanion)(ZygiskModule *); | ||||||
|         void (*setOption)(ZygiskModule *, zygisk::Option); |         void (*setOption)(ZygiskModule *, zygisk::Option); | ||||||
|     } v1; |     } v1; | ||||||
|  |     struct { | ||||||
|  |         int (*getModuleDir)(ZygiskModule *); | ||||||
|  |     } v2; | ||||||
|  |  | ||||||
|     ApiTable(ZygiskModule *m); |     ApiTable(ZygiskModule *m); | ||||||
| }; | }; | ||||||
| @@ -100,6 +103,7 @@ struct ZygiskModule { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     int connectCompanion() const; |     int connectCompanion() const; | ||||||
|  |     int getModuleDir() const; | ||||||
|     void setOption(zygisk::Option opt); |     void setOption(zygisk::Option opt); | ||||||
|     void doUnload() const { if (unload) dlclose(handle); } |     void doUnload() const { if (unload) dlclose(handle); } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ enum : int { | |||||||
|     ZYGISK_GET_INFO, |     ZYGISK_GET_INFO, | ||||||
|     ZYGISK_GET_LOG_PIPE, |     ZYGISK_GET_LOG_PIPE, | ||||||
|     ZYGISK_CONNECT_COMPANION, |     ZYGISK_CONNECT_COMPANION, | ||||||
|  |     ZYGISK_GET_MODDIR, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #if defined(__LP64__) | #if defined(__LP64__) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 topjohnwu
					topjohnwu