From 566f0ca36bafe51054b0778552914010f36bf23a Mon Sep 17 00:00:00 2001 From: artdeell Date: Thu, 14 Sep 2023 07:51:00 +0300 Subject: [PATCH] Fix[zink]: resolve namespace issues and fix old android support Note: old android support still requires me to compile a working build of Turnip to work on old android --- .../src/main/jni/driver_helper/hook.c | 40 +++++---- .../src/main/jni/driver_helper/nsbypass.c | 85 +++++++++++------- .../src/main/jni/driver_helper/nsbypass.h | 1 - app_pojavlauncher/src/main/jni/egl_bridge.c | 19 +++- .../src/main/jniLibs/arm64-v8a/libhardware.so | Bin 4928 -> 0 bytes 5 files changed, 93 insertions(+), 52 deletions(-) delete mode 100644 app_pojavlauncher/src/main/jniLibs/arm64-v8a/libhardware.so diff --git a/app_pojavlauncher/src/main/jni/driver_helper/hook.c b/app_pojavlauncher/src/main/jni/driver_helper/hook.c index 1a544d48c..4a25c26db 100644 --- a/app_pojavlauncher/src/main/jni/driver_helper/hook.c +++ b/app_pojavlauncher/src/main/jni/driver_helper/hook.c @@ -2,42 +2,50 @@ // Created by maks on 05.06.2023. // #include -#include #include - -typedef void* (*android_dlopen_ext_t)(const char *filename, int flags, const android_dlextinfo *extinfo); -typedef struct android_namespace_t* (*android_get_exported_namespace_t)(const char* name); - +// Silence the warnings about using reserved identifiers (we need to link to these to not pollute the global symtab) +//NOLINTBEGIN +__attribute__((weak)) void* __loader_android_dlopen_ext(const char* filename, + int flags, + const android_dlextinfo* extinfo, + const void* caller_addr); +__attribute__((weak)) struct android_namespace_t* __loader_android_get_exported_namespace(const char* name); +//NOLINTEND static void* ready_handle; -static android_dlopen_ext_t original_func; -static android_get_exported_namespace_t android_get_exported_namespace; static const char *sphal_namespaces[3] = { "sphal", "vendor", "default" }; -__attribute__((visibility("default"))) void app__pojav_linkerhook_set_data(void* data, void* data1, void* data2) { +__attribute__((visibility("default"), used)) void app__pojav_linkerhook_pass_handle(void* data) { ready_handle = data; - original_func = data1; - android_get_exported_namespace = data2; } -__attribute__((visibility("default"))) void *android_dlopen_ext(const char *filename, int flags, const android_dlextinfo *extinfo) { +__attribute__((visibility("default"), used)) void *android_dlopen_ext(const char *filename, int flags, const android_dlextinfo *extinfo) { if(!strstr(filename, "vulkan.")) - return original_func(filename, flags, extinfo); + return __loader_android_dlopen_ext(filename, flags, extinfo, &android_dlopen_ext); return ready_handle; } -__attribute__((visibility("default"))) void *android_load_sphal_library(const char *filename, int flags) { - if(strstr(filename, "vulkan.")) return ready_handle; +__attribute__((visibility("default"), used)) void *android_load_sphal_library(const char *filename, int flags) { + if(strstr(filename, "vulkan.")) { + return ready_handle; + } struct android_namespace_t* androidNamespace; for(int i = 0; i < 3; i++) { - androidNamespace = android_get_exported_namespace(sphal_namespaces[i]); + androidNamespace = __loader_android_get_exported_namespace(sphal_namespaces[i]); if(androidNamespace != NULL) break; } android_dlextinfo info; info.flags = ANDROID_DLEXT_USE_NAMESPACE; info.library_namespace = androidNamespace; - return original_func(filename, flags, &info); + return __loader_android_dlopen_ext(filename, flags, &info, &android_dlopen_ext); +} + +// This is done for older android versions which don't +// export this function. Technically this is wrong +// but for our usage it's fine enough +__attribute__((visibility("default"), used)) uint64_t atrace_get_enabled_tags() { + return 0; } \ No newline at end of file diff --git a/app_pojavlauncher/src/main/jni/driver_helper/nsbypass.c b/app_pojavlauncher/src/main/jni/driver_helper/nsbypass.c index b26cf4f59..9088f7678 100644 --- a/app_pojavlauncher/src/main/jni/driver_helper/nsbypass.c +++ b/app_pojavlauncher/src/main/jni/driver_helper/nsbypass.c @@ -38,11 +38,12 @@ typedef struct android_namespace_t* (*ld_android_create_namespace_t)( const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type, const char* permitted_when_isolated_path, struct android_namespace_t* parent, const void* caller_addr); -typedef struct android_namespace_t* (*ld_android_get_exported_namespace_t)(const char* name, const void* caller_addr); +typedef void* (*ld_android_link_namespaces_t)(struct android_namespace_t* namespace_from, + struct android_namespace_t* namespace_to, + const char* shared_libs_sonames); static ld_android_create_namespace_t android_create_namespace; -static ld_android_get_exported_namespace_t android_get_exported_namespace; -static struct android_namespace_t* namespace; +static struct android_namespace_t* driver_namespace; struct android_namespace_t* local_android_create_namespace( const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type, @@ -51,58 +52,78 @@ struct android_namespace_t* local_android_create_namespace( return android_create_namespace(name, ld_library_path, default_library_path, type, permitted_when_isolated_path, parent, caller); } -struct android_namespace_t* ns_android_get_exported_namespace( - const char* name) { - void* caller = __builtin_return_address(0); - return android_get_exported_namespace(name, caller); +// Find the first "branch to label" function in the function provided in func_start +static void* find_branch_label(void* func_start) { + // round down the pointer to get the start of the function's page + void* func_page_start = (void*)(((uintptr_t)func_start) & ~(PAGE_SIZE-1)); + // remap to r-x to bypass "execute only" protections on MIUI + mprotect(func_page_start, PAGE_SIZE, PROT_READ | PROT_EXEC); + uint32_t* bl_addr = func_start; + // search for the "branch to label" opcode + while((*bl_addr & OP_MS) != BL_OP) { + bl_addr++; // walk through memory until we find it or die + } + // offset the address to find where the "branch to label" instrunction + // points to. + return ((char*)bl_addr) + (*bl_addr & BL_IM) * 4; } - bool linker_ns_load(const char* lib_search_path) { #ifndef ADRENO_POSSIBLE return false; -#endif - uint32_t *dlext_bl_addr = (uint32_t*)&dlopen; - while((*dlext_bl_addr & OP_MS) != - BL_OP) dlext_bl_addr++; //walk through the function until we find the label that we need to go to - __android_log_print(ANDROID_LOG_INFO, "nsbypass", "found branch label: %u", *dlext_bl_addr); - loader_dlopen_t loader_dlopen; - loader_dlopen = (loader_dlopen_t)(((char *) dlext_bl_addr) + (*dlext_bl_addr & BL_IM)*4); - mprotect(loader_dlopen, PAGE_SIZE, PROT_WRITE | PROT_READ | PROT_EXEC); // reprotecting the function removes protection from indirect jumps +#else + loader_dlopen_t loader_dlopen = find_branch_label(&dlopen); + // reprotecting the functions removes protection from indirect jumps + mprotect(loader_dlopen, PAGE_SIZE, PROT_WRITE | PROT_READ | PROT_EXEC); void* ld_android_handle = loader_dlopen("ld-android.so", RTLD_LAZY, &dlopen); - __android_log_print(ANDROID_LOG_INFO, "nsbypass", "ld-android.so handle: %p", ld_android_handle); - if(ld_android_handle == NULL) return false; + if(ld_android_handle == NULL) { + return false; + } + // load the two functions we need android_create_namespace = dlsym(ld_android_handle, "__loader_android_create_namespace"); - android_get_exported_namespace = dlsym(ld_android_handle, "__loader_android_get_exported_namespace"); - if(android_create_namespace == NULL || android_get_exported_namespace == NULL) { + ld_android_link_namespaces_t android_link_namespaces = dlsym(ld_android_handle, "__loader_android_link_namespaces"); + __android_log_print(ANDROID_LOG_INFO, "nsbypass", "found functions at %p %p", android_create_namespace, android_link_namespaces); + if(android_create_namespace == NULL || android_link_namespaces == NULL) { dlclose(ld_android_handle); return false; } + // assemble the full path search path char full_path[strlen(SEARCH_PATH) + strlen(lib_search_path) + 2 + 1]; sprintf(full_path, "%s:%s", SEARCH_PATH, lib_search_path); - namespace = local_android_create_namespace("pojav-driver", - full_path, - full_path, - 3 /* TYPE_SHAFED | TYPE_ISOLATED */, - "/system/:/data/:/vendor/:/apex/", NULL); - //dlclose(ld_android_handle); + driver_namespace = local_android_create_namespace("pojav-driver", + full_path, + full_path, + 3 /* TYPE_SHAFED | TYPE_ISOLATED */, + "/system/:/data/:/vendor/:/apex/", NULL); + // THIS IS VERY IMPORTANT and how I trolled FoldCraft: + // You need to link the new driver_namespace with NULL and and add ld-android.so + // in the link list, to pass through the driver_namespace correctly. + // Not doing this fucks up internal __loader symbol lookup + // inside the new driver_namespace, thus breaking it on + // a lot of android versions + // FoldCraft got trolled because they copied the + // old broken code verbatim and didn't even test it thoroughly + android_link_namespaces(driver_namespace, NULL, "ld-android.so"); + dlclose(ld_android_handle); return true; +#endif } void* linker_ns_dlopen(const char* name, int flag) { #ifndef ADRENO_POSSIBLE return NULL; -#endif +#else android_dlextinfo dlextinfo; dlextinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; - dlextinfo.library_namespace = namespace; + dlextinfo.library_namespace = driver_namespace; return android_dlopen_ext(name, flag, &dlextinfo); +#endif } bool patch_elf_soname(int patchfd, int realfd, uint16_t patchid) { struct stat realstat; if(fstat(realfd, &realstat)) return false; - if(ftruncate(patchfd, realstat.st_size) == -1) return false; + if(ftruncate64(patchfd, realstat.st_size) == -1) return false; char* target = mmap(NULL, realstat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, patchfd, 0); if(!target) return false; if(read(realfd, target, realstat.st_size) != realstat.st_size) { @@ -118,6 +139,7 @@ bool patch_elf_soname(int patchfd, int realfd, uint16_t patchid) { ELF_SHDR *hdr = &shdr[i]; if(hdr->sh_type == SHT_DYNAMIC) { char* strtab = target + shdr[hdr->sh_link].sh_offset; + // If there's a warning below, it's bogus, ignore it ELF_DYN *dynEntries = (ELF_DYN*)(target + hdr->sh_offset); for(ELF_XWORD k = 0; k < (hdr->sh_size / hdr->sh_entsize);k++) { ELF_DYN* dynEntry = &dynEntries[k]; @@ -138,7 +160,7 @@ bool patch_elf_soname(int patchfd, int realfd, uint16_t patchid) { void* linker_ns_dlopen_unique(const char* tmpdir, const char* name, int flags) { #ifndef ADRENO_POSSIBLE return NULL; -#endif +#else char pathbuf[PATH_MAX]; static uint16_t patch_id; int patch_fd, real_fd; @@ -159,7 +181,8 @@ void* linker_ns_dlopen_unique(const char* tmpdir, const char* name, int flags) { android_dlextinfo extinfo; extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE | ANDROID_DLEXT_USE_LIBRARY_FD; extinfo.library_fd = patch_fd; - extinfo.library_namespace = namespace; + extinfo.library_namespace = driver_namespace; snprintf(pathbuf, PATH_MAX, "/proc/self/fd/%d", patch_fd); return android_dlopen_ext(pathbuf, flags, &extinfo); +#endif } diff --git a/app_pojavlauncher/src/main/jni/driver_helper/nsbypass.h b/app_pojavlauncher/src/main/jni/driver_helper/nsbypass.h index 7b6ac9b06..fb9e1c397 100644 --- a/app_pojavlauncher/src/main/jni/driver_helper/nsbypass.h +++ b/app_pojavlauncher/src/main/jni/driver_helper/nsbypass.h @@ -11,6 +11,5 @@ bool linker_ns_load(const char* lib_search_path); void* linker_ns_dlopen(const char* name, int flag); void* linker_ns_dlopen_unique(const char* tmpdir, const char* name, int flag); -struct android_namespace_t* ns_android_get_exported_namespace(const char*); #endif //POJAVLAUNCHER_NSBYPASS_H diff --git a/app_pojavlauncher/src/main/jni/egl_bridge.c b/app_pojavlauncher/src/main/jni/egl_bridge.c index 1e900eeaf..7ded9391d 100644 --- a/app_pojavlauncher/src/main/jni/egl_bridge.c +++ b/app_pojavlauncher/src/main/jni/egl_bridge.c @@ -187,11 +187,22 @@ void* load_turnip_vulkan() { if(!checkAdrenoGraphics()) return NULL; const char* native_dir = getenv("POJAV_NATIVEDIR"); const char* cache_dir = getenv("TMPDIR"); - linker_ns_load(native_dir); + if(!linker_ns_load(native_dir)) return NULL; void* linkerhook = linker_ns_dlopen("liblinkerhook.so", RTLD_LOCAL | RTLD_NOW); + if(linkerhook == NULL) return NULL; void* turnip_driver_handle = linker_ns_dlopen("libvulkan.adr.so", RTLD_LOCAL | RTLD_NOW); - void (*linkerhook_set_data)(void*, void*, void*) = dlsym(linkerhook, "app__pojav_linkerhook_set_data"); - linkerhook_set_data(turnip_driver_handle, &android_dlopen_ext, &ns_android_get_exported_namespace); + if(turnip_driver_handle == NULL) { + printf("AdrenoSupp: Failed to load Turnip!\n%s\n", dlerror()); + dlclose(linkerhook); + return NULL; + } + void (*linkerhook_set_data)(void*) = dlsym(linkerhook, "app__pojav_linkerhook_pass_handle"); + if(linkerhook_set_data == NULL) { + dlclose(linkerhook); + dlclose(turnip_driver_handle); + return NULL; + } + linkerhook_set_data(turnip_driver_handle); void* libvulkan = linker_ns_dlopen_unique(cache_dir, "libvulkan.so", RTLD_LOCAL | RTLD_NOW); return libvulkan; } @@ -217,7 +228,7 @@ void load_vulkan() { } printf("OSMDroid: loading vulkan regularly...\n"); void* vulkan_ptr = dlopen("libvulkan.so", RTLD_LAZY | RTLD_LOCAL); - printf("OSMDroid: loaded vulkan, ptr=%p", vulkan_ptr); + printf("OSMDroid: loaded vulkan, ptr=%p\n", vulkan_ptr); set_vulkan_ptr(vulkan_ptr); } diff --git a/app_pojavlauncher/src/main/jniLibs/arm64-v8a/libhardware.so b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/libhardware.so deleted file mode 100644 index 440ce8fe8f33916e3d34581c8c6f96061226393b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4928 zcmbtYU2GIp6u!HQKTv*Egjl63X%vV~x9zrU5lw-X6fL9@NyNkqvoq7~+TEGW>?~~& zV5Pjjn2Q`{hW3&%ON%VmilRgMB@dY0=h8Tk;8i-0gXYToSmth+W-gf4@ z=ey_JpEKv)d)ilrM|UR^35AkUpQ(nV)F2vGqQYEGEv5Hbb+5XU=q2Iw)SK1+5oMbY?g!1ny)c%d!ujHVS3 zd{bW}UlgPuN{;I_*^U-v+NU+-<(FJ{Q|yr)GYhgB>7p+)$vh;LKh zO1$BFE0v6Xc$@_NJV_`atLzmVu}L*dZxq&JUot+xB>SHP=8A6}?Np{|Pg~}A(X&d$ zBd&;6=uQ_y5(0OkSPk94w8C*em{f%+bHWYHvhUPNt|}Gtwo&!f=$@UsSSVP5Gi3!X zb5aohDfys~a}wX+Ps%z6V?6fV{G+ribyP z#>Lq=FNST>AI9Sy%;k)9v`mZYpx__Z^?IhIJ=)XMhW&)tApb_?ip+mR^skHjoX86? z|A^Tw;gamvIF1&*NjKP*9vvM@cV~@^u@%R5decB}Ur&Fg_px-|s=7|v_tHVOFS9k5 zb-FjF?ULn9qz}76wMY%xG`*=1hL!5Jt}aU-{lEpZ==&wRU=_Wt zQt5E{@k-#oR%UC~9q8%JS>w5UwmZ{r_hu}|$!5EAbGb}HGTEk%OB}*)N%~;SpB5hbuU+_eg~vYW68>x9@g2vAPb3@u zNB``{R`KvvG`Yrojk%tWDmVN88{!kH;eUJvt>56$&m_%9C08lrgW$iXN~^qLBk8x| zpIU@}G2$EZ$9k3F`JroI{}mnA3zgx_c-5J*GA6v5AzSta!3?xmu&M>E9TF3`C5ug^ zRw+?WZowQ6tg>qs9MXWK3`#(#HBxb`&|+I7@RdP{O3}1}z?zBrwaP`ChVnzLN+&`& znjpHf1=zXF4UjR0S6Q=DaLXAz&#JTFAoJX*1?xt^muXVQchxt^~T zOOEN)%6T_X$f?X~Sj!uBrNYz9@Mt{O-TQa!9X5ye4VflMu}sb_*TPcOta~?q$x?`L2XL?o%M{X|%_23)%DC3m*3` zFiq`TFn)ag1Jw3slRfT#V497opnuF?vr6$-;42^P$S;7%FQCspXfAy3@SI?Ol{=#X z9MNLE9pl4)2dJIxcZ%MiED+di&u4JlUf)ZN@fZ7hRl1MHLY=Wp53dRH$Gr#qfR&mG z#s|gs9NQy*!@ZCH4-}v%82^5+#O&*NlO%ll{%&-FdkD-iu@|@3^9cOiAD?ereuL~e zXMsKP#hffCK3?4ZZL(!m*yA3;|10o+3HS&0==UA6W&gn*`SF}2#u;jBF0cppAywEu zuJ^Ope+)%I*5v~HlkB%0TO7Vw^AVUdQ-|-!F*6+{HA4IX+aV%xkE>F)oPn RRB2^@V!74`V+Ju%{R?e^2j~C*