Skip to content

Commit 6fc25c6

Browse files
authored
Fix LD_PRELOAD namespace restriction using memfd (#553)
The Android dynamic linker (Bionic) restricts loading libraries from unauthorized paths via LD_PRELOAD. This causes the linker to reject the hook library with a "not accessible for the namespace" fatal error. To bypass this restriction, we exploit a fallback in Bionic that explicitly skips the namespace accessibility check for files located on tmpfs. We use `memfd_create` to create an anonymous tmpfs-backed file descriptor, copy the library into it using `sendfile`, and pass the new memfd to LD_PRELOAD instead. Reference: function `load_library` in https://cs.android.com/android/platform/superproject/main/+/main:bionic/linker/linker.cpp
1 parent 64de273 commit 6fc25c6

2 files changed

Lines changed: 28 additions & 1 deletion

File tree

dex2oat/src/main/cpp/dex2oat.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
#include <linux/memfd.h>
2+
#include <sys/sendfile.h>
13
#include <sys/socket.h>
4+
#include <sys/stat.h>
5+
#include <sys/syscall.h>
26
#include <sys/un.h>
37
#include <unistd.h>
48

@@ -144,7 +148,29 @@ int main(int argc, char **argv) {
144148

145149
if (hooker_fd == -1) {
146150
LOGE("failed to read liboat_hook.so");
151+
} else {
152+
int mem_fd = syscall(__NR_memfd_create, "liboat_hook_memfd", 0);
153+
if (mem_fd >= 0) {
154+
// Get the exact size of the original library
155+
LOGD("Copying %d as mem_fd %d", hooker_fd, mem_fd);
156+
struct stat st;
157+
if (fstat(hooker_fd, &st) == 0) {
158+
// Tell the kernel to copy the entire file directly to the memfd
159+
off_t offset = 0;
160+
sendfile(mem_fd, hooker_fd, &offset, st.st_size);
161+
162+
// Swap the old FD with the new memfd
163+
close(hooker_fd);
164+
hooker_fd = mem_fd;
165+
} else {
166+
PLOGE("fstat failed");
167+
close(mem_fd);
168+
}
169+
} else {
170+
PLOGE("memfd_create failed, falling back to original fd");
171+
}
147172
}
173+
148174
LOGD("sock: %s stock_fd: %d", sock.sun_path + 1, stock_fd);
149175

150176
// Prepare arguments for execve
@@ -176,6 +202,7 @@ int main(int argc, char **argv) {
176202

177203
// Set LD_PRELOAD to point to the hooker library FD
178204
std::string preload_val = "LD_PRELOAD=/proc/self/fd/" + std::to_string(hooker_fd);
205+
LOGD("Inject oat hook via %s", preload_val.data());
179206
setenv("LD_PRELOAD", ("/proc/self/fd/" + std::to_string(hooker_fd)).c_str(), 1);
180207

181208
// Pass original argv[0] as DEX2OAT_CMD

magisk-loader/magisk_module/sepolicy.rule

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ type xposed_file file_type
77
typeattribute xposed_file mlstrustedobject
88
allow {dex2oat installd isolated_app shell} xposed_file {file dir} *
99

10-
allow dex2oat unlabeled file *
10+
allow dex2oat {unlabeled tmpfs} file *
1111

1212
type xposed_data file_type
1313
typeattribute xposed_data mlstrustedobject

0 commit comments

Comments
 (0)