Skip to content

Commit 6bd436a

Browse files
committed
fix: preload on some systems; update: rollback global module on_load
This commit fixes the preload on some systems by opening modules before system server is forked. For that, we need to handle the solist early on to avoid gaps due to libraries being opened after that. And, because of that, we also deal with the deconstructors manually. It also rolls back the commit that made module "on load" be called in preload stage/globally, as initializators can be used instead, and makes it behave the same way as other Zygisks.
1 parent ecb2981 commit 6bd436a

4 files changed

Lines changed: 294 additions & 71 deletions

File tree

loader/src/injector/hook.cpp

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ struct ZygiskContext {
9898
~ZygiskContext();
9999

100100
/* Zygisksu changed: Load module fds */
101-
bool load_modules_only();
102101
void run_modules_pre();
103102
void run_modules_post();
104103
DCL_PRE_POST(fork)
@@ -696,7 +695,7 @@ void ZygiskContext::fork_post() {
696695
g_ctx = nullptr;
697696
}
698697

699-
bool ZygiskContext::load_modules_only() {
698+
bool load_modules_only() {
700699
struct zygisk_modules ms;
701700
if (rezygiskd_read_modules(&ms) == false) {
702701
LOGE("Failed to read modules from zygiskd");
@@ -738,14 +737,33 @@ bool ZygiskContext::load_modules_only() {
738737
zygisk_modules[zygisk_module_length].handle = handle;
739738
zygisk_modules[zygisk_module_length].zygisk_module_entry = (void (*)(void *, void *))entry;
740739

740+
zygisk_modules[zygisk_module_length].base = solist_get_base(entry);
741+
zygisk_modules[zygisk_module_length].size = solist_get_size(entry);
742+
743+
zygisk_modules[zygisk_module_length].deconstructors = solist_get_deconstructors(entry);
744+
zygisk_modules[zygisk_module_length].gap = solist_get_gap_info(entry);
745+
746+
LOGD("Loaded module [%s]. Entry: %p, Base: %p, Size: %zu, Deconstructors: fini_func=%p, fini_array=%p (size: %zu), Gap: %p (size: %zu)",
747+
lib_path,
748+
entry,
749+
zygisk_modules[zygisk_module_length].base,
750+
zygisk_modules[zygisk_module_length].size,
751+
zygisk_modules[zygisk_module_length].deconstructors.fini_func,
752+
zygisk_modules[zygisk_module_length].deconstructors.fini_array,
753+
zygisk_modules[zygisk_module_length].deconstructors.fini_array_size,
754+
zygisk_modules[zygisk_module_length].gap.start,
755+
zygisk_modules[zygisk_module_length].gap.size);
756+
741757
zygisk_modules[zygisk_module_length].unload = false;
742758

743-
zygisk_module_length++;
759+
/* INFO: Early removal to avoid gaps in solist */
760+
solist_drop_so_path(entry, false);
744761

745-
/* INFO: The module will call register module function, so by then, it must be fully registered. */
746-
rezygisk_module_call_on_load(&zygisk_modules[zygisk_module_length - 1], env);
762+
zygisk_module_length++;
747763
}
748764

765+
solist_reset_counters(zygisk_module_length, zygisk_module_length);
766+
749767
free_modules(&ms);
750768

751769
return true;
@@ -754,6 +772,8 @@ bool ZygiskContext::load_modules_only() {
754772
/* Zygisksu changed: Load module fds */
755773
void ZygiskContext::run_modules_pre() {
756774
for (size_t i = 0; i < zygisk_module_length; i++) {
775+
rezygisk_module_call_on_load(&zygisk_modules[i], env);
776+
757777
if (flags[APP_SPECIALIZE]) rezygisk_module_call_pre_app_specialize(&zygisk_modules[i], args.app);
758778
else if (flags[SERVER_FORK_AND_SPECIALIZE]) rezygisk_module_call_pre_server_specialize(&zygisk_modules[i], args.server);
759779
}
@@ -771,24 +791,28 @@ void ZygiskContext::run_modules_post() {
771791

772792
/* INFO: If module is unloaded by dlclose, there's no need to
773793
hide it from soinfo manually. */
774-
if (m->unload && dlclose(m->handle) == 0) modules_unloaded++;
775-
else if (m->unload) {
776-
PLOGE("Failed to unload module %zu", i);
777-
} else {
778-
bool has_dropped = solist_drop_so_path((void *)m->zygisk_module_entry, false);
779-
if (!has_dropped) continue;
794+
if (m->unload) {
795+
/* INFO: Deconstructors are called in the inverted order, and following fini array then fini
796+
function order. It must not change. */
797+
for (size_t j = m->deconstructors.fini_array_size; j > 0; j--) {
798+
void (*destructor)(void) = m->deconstructors.fini_array[j - 1];
799+
if (destructor) {
800+
LOGD("Calling destructor %p for module %p", (void *)destructor, (void *)m->zygisk_module_entry);
801+
802+
destructor();
803+
}
804+
}
805+
806+
if (m->deconstructors.fini_func) m->deconstructors.fini_func();
780807

781-
LOGD("Dropped solist record for %p", (void *)m->zygisk_module_entry);
808+
solist_unload_lib(&m->gap, m->base, m->size);
809+
810+
modules_unloaded++;
782811
}
783812
}
784813

785-
if (zygisk_module_length > 0) {
814+
if (zygisk_module_length > 0)
786815
LOGD("Modules unloaded: %zu/%zu", modules_unloaded, zygisk_module_length);
787-
788-
solist_reset_counters(zygisk_module_length, modules_unloaded);
789-
790-
LOGD("Returned global counters to their original values");
791-
}
792816
}
793817

794818
/* Zygisksu changed: Load module fds */
@@ -936,11 +960,6 @@ void ZygiskContext::nativeForkSystemServer_pre() {
936960
LOGV("pre forkSystemServer");
937961
flags[SERVER_FORK_AND_SPECIALIZE] = true;
938962

939-
if (!modules_loaded) {
940-
load_modules_only();
941-
modules_loaded = true;
942-
}
943-
944963
fork_pre();
945964
if (!is_child())
946965
return;
@@ -1140,6 +1159,13 @@ static void hook_unloader() {
11401159
}
11411160

11421161
lsplt_free_maps(map_infos);
1162+
1163+
/* INFO: Load modules early on (before system server fork) to spread through all Zygotes */
1164+
if (!modules_loaded) {
1165+
if (!load_modules_only()) {
1166+
LOGE("Failed to load modules in hook_unloader");
1167+
} else modules_loaded = true;
1168+
}
11431169
}
11441170

11451171
static void unhook_functions() {

loader/src/injector/module.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define MODULE_H
33

44
#include "logging.h"
5+
#include "solist.h"
56

67
#define REZYGISK_API_VERSION 5
78

@@ -148,6 +149,12 @@ struct rezygisk_module {
148149
void *handle;
149150
void (*zygisk_module_entry)(void *, void *);
150151

152+
void *base;
153+
size_t size;
154+
155+
struct soinfo_deconstructor deconstructors;
156+
struct soinfo_gap gap;
157+
151158
bool unload;
152159
};
153160

0 commit comments

Comments
 (0)