Android JNI中从内存加载本地库遇加载失败问题求助
Android内存加载本地库失败排查与解决
问题描述
我正在做Android平台下从内存加载本地库的实验:通过syscall(SYS_memfd_create, "lib", 0)创建有效的memfd文件描述符,使用write()将ELF文件内容写入该描述符后,通过/proc/self/fd/%d路径调用System.load()加载库,出现错误:
java.lang.UnsatisfiedLinkError: dlopen failed: library "/proc/self/fd/76" not found
...
同时直接调用dlopen()加载该路径也返回NULL,dlerror提示相同信息。
相关代码:
int mem_lib_fd = syscall(SYS_memfd_create, "lib", 0); DBG_LOG_VA("memfd_create(): %d", mem_lib_fd); if (mem_lib_fd < 0) return -1; sys_write(mem_lib_fd, elf_buf, elf.size); char load_path[0xff]; sprintf(load_path, "/proc/self/fd/%d", mem_lib_fd); DBG_LOG_VA("lib path: %s", load_path); jclass jSystem = env->FindClass("java/lang/System"); jmethodID jSystem_load = env->GetStaticMethodID(jSystem, "load", "(Ljava/lang/String;)V"); env->CallStaticVoidMethod(jSystem, jSystem_load, env->NewStringUTF(load_path));
问题原因
- Android安全机制限制:
dlopen(包括System.load底层依赖的dlopen)默认拦截/proc/self/fd/这类虚拟路径的加载请求,防止恶意加载临时文件。 - memfd权限与属性缺失:创建memfd时未设置允许密封和可执行权限,写入ELF后也未配置文件的可执行属性,导致加载时权限不足。
- 文件指针位置问题:写入ELF后文件指针停在末尾,
dlopen读取时可能无法获取完整的ELF内容。
解决办法
1. 修正memfd创建参数
创建memfd时需添加MFD_ALLOW_SEALING(允许后续密封操作)和MFD_CLOEXEC(进程执行新程序时自动关闭fd,避免泄漏)标志:
int mem_lib_fd = syscall(SYS_memfd_create, "lib", MFD_ALLOW_SEALING | MFD_CLOEXEC);
2. 设置文件可执行权限
写入ELF内容后,通过fchmod给memfd添加可执行权限:
fchmod(mem_lib_fd, 0755);
3. 重置文件指针到开头
写入完成后将文件指针重置到起始位置,确保dlopen能读取完整ELF:
lseek(mem_lib_fd, 0, SEEK_SET);
4. 使用文件描述符直接加载(推荐)
Android 8.0及以上版本支持通过android_dlopen_ext直接加载文件描述符,绕过/proc/self/fd路径限制:
#include <android/dlext.h> void* handle = android_dlopen_ext(mem_lib_fd, RTLD_NOW, nullptr, ANDROID_DL_OPEN_FD); if (!handle) { DBG_LOG_VA("dlopen failed: %s", dlerror()); return -1; }
若需在Java层调用,可在Native层完成库加载后,通过JNI暴露方法给Java,无需走System.load。
内容的提问来源于stack exchange,提问作者na29
相关产品推荐
相关产品推荐

