Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/PojavLauncher
Path: blob/v3_openjdk/app_pojavlauncher/src/main/jni/driver_helper/nsbypass.c
2128 views
1
//
2
// Created by maks on 05.06.2023.
3
//
4
#include "nsbypass.h"
5
#include <dlfcn.h>
6
#include <android/dlext.h>
7
#include <android/log.h>
8
#include <sys/mman.h>
9
#include <sys/user.h>
10
#include <string.h>
11
#include <stdio.h>
12
#include <linux/limits.h>
13
#include <errno.h>
14
#include <unistd.h>
15
#include <asm/unistd.h>
16
#include <fcntl.h>
17
#include <sys/stat.h>
18
#include <elf.h>
19
20
/* upper 6 bits of an ARM64 instruction are the instruction name */
21
#define OP_MS 0b11111100000000000000000000000000
22
/* Branch Label instruction opcode and immediate mask */
23
#define BL_OP 0b10010100000000000000000000000000
24
#define BL_IM 0b00000011111111111111111111111111
25
/* Library search path */
26
#define SEARCH_PATH "/system/lib64"
27
#define ELF_EHDR Elf64_Ehdr
28
#define ELF_SHDR Elf64_Shdr
29
#define ELF_HALF Elf64_Half
30
#define ELF_XWORD Elf64_Xword
31
#define ELF_DYN Elf64_Dyn
32
33
//#define ADRENO_POSSIBLE
34
35
typedef void* (*loader_dlopen_t)(const char* filename, int flags, const void* caller_addr);
36
37
typedef struct android_namespace_t* (*ld_android_create_namespace_t)(
38
const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type,
39
const char* permitted_when_isolated_path, struct android_namespace_t* parent, const void* caller_addr);
40
41
typedef void* (*ld_android_link_namespaces_t)(struct android_namespace_t* namespace_from,
42
struct android_namespace_t* namespace_to,
43
const char* shared_libs_sonames);
44
45
static ld_android_create_namespace_t android_create_namespace;
46
static struct android_namespace_t* driver_namespace;
47
48
struct android_namespace_t* local_android_create_namespace(
49
const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type,
50
const char* permitted_when_isolated_path, struct android_namespace_t* parent) {
51
void* caller = __builtin_return_address(0);
52
return android_create_namespace(name, ld_library_path, default_library_path, type, permitted_when_isolated_path, parent, caller);
53
}
54
55
// Find the first "branch to label" function in the function provided in func_start
56
static void* find_branch_label(void* func_start) {
57
// round down the pointer to get the start of the function's page
58
void* func_page_start = (void*)(((uintptr_t)func_start) & ~(PAGE_SIZE-1));
59
// remap to r-x to bypass "execute only" protections on MIUI
60
mprotect(func_page_start, PAGE_SIZE, PROT_READ | PROT_EXEC);
61
uint32_t* bl_addr = func_start;
62
// search for the "branch to label" opcode
63
while((*bl_addr & OP_MS) != BL_OP) {
64
bl_addr++; // walk through memory until we find it or die
65
}
66
// offset the address to find where the "branch to label" instrunction
67
// points to.
68
return ((char*)bl_addr) + (*bl_addr & BL_IM) * 4;
69
}
70
71
bool linker_ns_load(const char* lib_search_path) {
72
#ifndef ADRENO_POSSIBLE
73
return false;
74
#else
75
loader_dlopen_t loader_dlopen = find_branch_label(&dlopen);
76
// reprotecting the functions removes protection from indirect jumps
77
mprotect(loader_dlopen, PAGE_SIZE, PROT_WRITE | PROT_READ | PROT_EXEC);
78
void* ld_android_handle = loader_dlopen("ld-android.so", RTLD_LAZY, &dlopen);
79
if(ld_android_handle == NULL) {
80
return false;
81
}
82
// load the two functions we need
83
android_create_namespace = dlsym(ld_android_handle, "__loader_android_create_namespace");
84
ld_android_link_namespaces_t android_link_namespaces = dlsym(ld_android_handle, "__loader_android_link_namespaces");
85
if(android_create_namespace == NULL || android_link_namespaces == NULL) {
86
dlclose(ld_android_handle);
87
return false;
88
}
89
// assemble the full path search path
90
char full_path[strlen(SEARCH_PATH) + strlen(lib_search_path) + 2 + 1];
91
sprintf(full_path, "%s:%s", SEARCH_PATH, lib_search_path);
92
driver_namespace = local_android_create_namespace("pojav-driver",
93
full_path,
94
full_path,
95
3 /* TYPE_SHAFED | TYPE_ISOLATED */,
96
"/system/:/data/:/vendor/:/apex/", NULL);
97
// THIS IS VERY IMPORTANT and how I trolled FoldCraft:
98
// You need to link the new driver_namespace with NULL and and add ld-android.so
99
// in the link list, to pass through the driver_namespace correctly.
100
// Not doing this fucks up internal __loader symbol lookup
101
// inside the new driver_namespace, thus breaking it on
102
// a lot of android versions
103
// FoldCraft got trolled because they copied the
104
// old broken code verbatim and didn't even test it thoroughly
105
android_link_namespaces(driver_namespace, NULL, "ld-android.so");
106
// Also establish links to use the libnativeloader(_lazy).so libraries
107
// from the global namespace. This is a workaround for an EMUI issue where
108
// the newly loaded libnativeloader_lazy for some unknown reason links
109
// to itself and causes a deadlock when loading the vulkan driver.
110
android_link_namespaces(driver_namespace, NULL, "libnativeloader.so");
111
android_link_namespaces(driver_namespace, NULL, "libnativeloader_lazy.so");
112
dlclose(ld_android_handle);
113
return true;
114
#endif
115
}
116
117
void* linker_ns_dlopen(const char* name, int flag) {
118
#ifndef ADRENO_POSSIBLE
119
return NULL;
120
#else
121
android_dlextinfo dlextinfo;
122
dlextinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
123
dlextinfo.library_namespace = driver_namespace;
124
return android_dlopen_ext(name, flag, &dlextinfo);
125
#endif
126
}
127
128
bool patch_elf_soname(int patchfd, int realfd, uint16_t patchid) {
129
struct stat realstat;
130
if(fstat(realfd, &realstat)) return false;
131
if(ftruncate64(patchfd, realstat.st_size) == -1) return false;
132
char* target = mmap(NULL, realstat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, patchfd, 0);
133
if(!target) return false;
134
if(read(realfd, target, realstat.st_size) != realstat.st_size) {
135
munmap(target, realstat.st_size);
136
return false;
137
}
138
close(realfd);
139
140
141
ELF_EHDR *ehdr = (ELF_EHDR*)target;
142
ELF_SHDR *shdr = (ELF_SHDR*)(target + ehdr->e_shoff);
143
for(ELF_HALF i = 0; i < ehdr->e_shnum; i++) {
144
ELF_SHDR *hdr = &shdr[i];
145
if(hdr->sh_type == SHT_DYNAMIC) {
146
char* strtab = target + shdr[hdr->sh_link].sh_offset;
147
// If there's a warning below, it's bogus, ignore it
148
ELF_DYN *dynEntries = (ELF_DYN*)(target + hdr->sh_offset);
149
for(ELF_XWORD k = 0; k < (hdr->sh_size / hdr->sh_entsize);k++) {
150
ELF_DYN* dynEntry = &dynEntries[k];
151
if(dynEntry->d_tag == DT_SONAME) {
152
char* soname = strtab + dynEntry->d_un.d_val;
153
char sprb[4];
154
snprintf(sprb, 4, "%03x", patchid);
155
memcpy(soname, sprb, 3);
156
munmap(target, realstat.st_size);
157
return true;
158
}
159
}
160
}
161
}
162
return false;
163
}
164
165
void* linker_ns_dlopen_unique(const char* tmpdir, const char* name, int flags) {
166
#ifndef ADRENO_POSSIBLE
167
return NULL;
168
#else
169
char pathbuf[PATH_MAX];
170
static uint16_t patch_id;
171
int patch_fd, real_fd;
172
snprintf(pathbuf,PATH_MAX,"%s/%d_p.so", tmpdir, patch_id);
173
patch_fd = open(pathbuf, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
174
if(patch_fd == -1) return NULL;
175
snprintf(pathbuf,PATH_MAX,"%s/%s", SEARCH_PATH, name);
176
real_fd = open(pathbuf, O_RDONLY);
177
if(real_fd == -1) {
178
close(patch_fd);
179
return NULL;
180
}
181
if(!patch_elf_soname(patch_fd, real_fd, patch_id)) {
182
close(patch_fd);
183
close(real_fd);
184
return NULL;
185
}
186
android_dlextinfo extinfo;
187
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE | ANDROID_DLEXT_USE_LIBRARY_FD;
188
extinfo.library_fd = patch_fd;
189
extinfo.library_namespace = driver_namespace;
190
snprintf(pathbuf, PATH_MAX, "/proc/self/fd/%d", patch_fd);
191
return android_dlopen_ext(pathbuf, flags, &extinfo);
192
#endif
193
}
194
195