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
This commit is contained in:
artdeell 2023-09-14 07:51:00 +03:00
parent 4cd3ab0fb5
commit 566f0ca36b
5 changed files with 93 additions and 52 deletions

View File

@ -2,42 +2,50 @@
// Created by maks on 05.06.2023. // Created by maks on 05.06.2023.
// //
#include <android/dlext.h> #include <android/dlext.h>
#include <android/log.h>
#include <string.h> #include <string.h>
// Silence the warnings about using reserved identifiers (we need to link to these to not pollute the global symtab)
typedef void* (*android_dlopen_ext_t)(const char *filename, int flags, const android_dlextinfo *extinfo); //NOLINTBEGIN
typedef struct android_namespace_t* (*android_get_exported_namespace_t)(const char* name); __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 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] = { static const char *sphal_namespaces[3] = {
"sphal", "vendor", "default" "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; 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.")) if(!strstr(filename, "vulkan."))
return original_func(filename, flags, extinfo); return __loader_android_dlopen_ext(filename, flags, extinfo, &android_dlopen_ext);
return ready_handle; return ready_handle;
} }
__attribute__((visibility("default"))) void *android_load_sphal_library(const char *filename, int flags) { __attribute__((visibility("default"), used)) void *android_load_sphal_library(const char *filename, int flags) {
if(strstr(filename, "vulkan.")) return ready_handle; if(strstr(filename, "vulkan.")) {
return ready_handle;
}
struct android_namespace_t* androidNamespace; struct android_namespace_t* androidNamespace;
for(int i = 0; i < 3; i++) { 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; if(androidNamespace != NULL) break;
} }
android_dlextinfo info; android_dlextinfo info;
info.flags = ANDROID_DLEXT_USE_NAMESPACE; info.flags = ANDROID_DLEXT_USE_NAMESPACE;
info.library_namespace = androidNamespace; 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;
} }

View File

@ -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* 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); 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_create_namespace_t android_create_namespace;
static ld_android_get_exported_namespace_t android_get_exported_namespace; static struct android_namespace_t* driver_namespace;
static struct android_namespace_t* namespace;
struct android_namespace_t* local_android_create_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, 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); 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( // Find the first "branch to label" function in the function provided in func_start
const char* name) { static void* find_branch_label(void* func_start) {
void* caller = __builtin_return_address(0); // round down the pointer to get the start of the function's page
return android_get_exported_namespace(name, caller); 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) { bool linker_ns_load(const char* lib_search_path) {
#ifndef ADRENO_POSSIBLE #ifndef ADRENO_POSSIBLE
return false; return false;
#endif #else
uint32_t *dlext_bl_addr = (uint32_t*)&dlopen; loader_dlopen_t loader_dlopen = find_branch_label(&dlopen);
while((*dlext_bl_addr & OP_MS) != // reprotecting the functions removes protection from indirect jumps
BL_OP) dlext_bl_addr++; //walk through the function until we find the label that we need to go to mprotect(loader_dlopen, PAGE_SIZE, PROT_WRITE | PROT_READ | PROT_EXEC);
__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
void* ld_android_handle = loader_dlopen("ld-android.so", RTLD_LAZY, &dlopen); 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) {
if(ld_android_handle == NULL) return false; return false;
}
// load the two functions we need
android_create_namespace = dlsym(ld_android_handle, "__loader_android_create_namespace"); android_create_namespace = dlsym(ld_android_handle, "__loader_android_create_namespace");
android_get_exported_namespace = dlsym(ld_android_handle, "__loader_android_get_exported_namespace"); ld_android_link_namespaces_t android_link_namespaces = dlsym(ld_android_handle, "__loader_android_link_namespaces");
if(android_create_namespace == NULL || android_get_exported_namespace == NULL) { __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); dlclose(ld_android_handle);
return false; return false;
} }
// assemble the full path search path
char full_path[strlen(SEARCH_PATH) + strlen(lib_search_path) + 2 + 1]; char full_path[strlen(SEARCH_PATH) + strlen(lib_search_path) + 2 + 1];
sprintf(full_path, "%s:%s", SEARCH_PATH, lib_search_path); sprintf(full_path, "%s:%s", SEARCH_PATH, lib_search_path);
namespace = local_android_create_namespace("pojav-driver", driver_namespace = local_android_create_namespace("pojav-driver",
full_path, full_path,
full_path, full_path,
3 /* TYPE_SHAFED | TYPE_ISOLATED */, 3 /* TYPE_SHAFED | TYPE_ISOLATED */,
"/system/:/data/:/vendor/:/apex/", NULL); "/system/:/data/:/vendor/:/apex/", NULL);
//dlclose(ld_android_handle); // 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; return true;
#endif
} }
void* linker_ns_dlopen(const char* name, int flag) { void* linker_ns_dlopen(const char* name, int flag) {
#ifndef ADRENO_POSSIBLE #ifndef ADRENO_POSSIBLE
return NULL; return NULL;
#endif #else
android_dlextinfo dlextinfo; android_dlextinfo dlextinfo;
dlextinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; dlextinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
dlextinfo.library_namespace = namespace; dlextinfo.library_namespace = driver_namespace;
return android_dlopen_ext(name, flag, &dlextinfo); return android_dlopen_ext(name, flag, &dlextinfo);
#endif
} }
bool patch_elf_soname(int patchfd, int realfd, uint16_t patchid) { bool patch_elf_soname(int patchfd, int realfd, uint16_t patchid) {
struct stat realstat; struct stat realstat;
if(fstat(realfd, &realstat)) return false; 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); char* target = mmap(NULL, realstat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, patchfd, 0);
if(!target) return false; if(!target) return false;
if(read(realfd, target, realstat.st_size) != realstat.st_size) { 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]; ELF_SHDR *hdr = &shdr[i];
if(hdr->sh_type == SHT_DYNAMIC) { if(hdr->sh_type == SHT_DYNAMIC) {
char* strtab = target + shdr[hdr->sh_link].sh_offset; 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); ELF_DYN *dynEntries = (ELF_DYN*)(target + hdr->sh_offset);
for(ELF_XWORD k = 0; k < (hdr->sh_size / hdr->sh_entsize);k++) { for(ELF_XWORD k = 0; k < (hdr->sh_size / hdr->sh_entsize);k++) {
ELF_DYN* dynEntry = &dynEntries[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) { void* linker_ns_dlopen_unique(const char* tmpdir, const char* name, int flags) {
#ifndef ADRENO_POSSIBLE #ifndef ADRENO_POSSIBLE
return NULL; return NULL;
#endif #else
char pathbuf[PATH_MAX]; char pathbuf[PATH_MAX];
static uint16_t patch_id; static uint16_t patch_id;
int patch_fd, real_fd; 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; android_dlextinfo extinfo;
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE | ANDROID_DLEXT_USE_LIBRARY_FD; extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE | ANDROID_DLEXT_USE_LIBRARY_FD;
extinfo.library_fd = patch_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); snprintf(pathbuf, PATH_MAX, "/proc/self/fd/%d", patch_fd);
return android_dlopen_ext(pathbuf, flags, &extinfo); return android_dlopen_ext(pathbuf, flags, &extinfo);
#endif
} }

View File

@ -11,6 +11,5 @@
bool linker_ns_load(const char* lib_search_path); bool linker_ns_load(const char* lib_search_path);
void* linker_ns_dlopen(const char* name, int flag); void* linker_ns_dlopen(const char* name, int flag);
void* linker_ns_dlopen_unique(const char* tmpdir, 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 #endif //POJAVLAUNCHER_NSBYPASS_H

View File

@ -187,11 +187,22 @@ void* load_turnip_vulkan() {
if(!checkAdrenoGraphics()) return NULL; if(!checkAdrenoGraphics()) return NULL;
const char* native_dir = getenv("POJAV_NATIVEDIR"); const char* native_dir = getenv("POJAV_NATIVEDIR");
const char* cache_dir = getenv("TMPDIR"); 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); 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* 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"); if(turnip_driver_handle == NULL) {
linkerhook_set_data(turnip_driver_handle, &android_dlopen_ext, &ns_android_get_exported_namespace); 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); void* libvulkan = linker_ns_dlopen_unique(cache_dir, "libvulkan.so", RTLD_LOCAL | RTLD_NOW);
return libvulkan; return libvulkan;
} }
@ -217,7 +228,7 @@ void load_vulkan() {
} }
printf("OSMDroid: loading vulkan regularly...\n"); printf("OSMDroid: loading vulkan regularly...\n");
void* vulkan_ptr = dlopen("libvulkan.so", RTLD_LAZY | RTLD_LOCAL); 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); set_vulkan_ptr(vulkan_ptr);
} }