Android应用中如何限制JNI调用的C代码仅访问指定文件夹?
Android JNI调用C代码的存储访问范围限制
先说结论:可以实现,但单纯重写POSIX符号的路子行不通(因为共享库能用dlsym绕过去),得结合Android的底层机制来搞。
靠谱的实现方案
1. 用SELinux定制访问规则(Android 8.0及以上)
Android的SELinux是强制访问控制的核心,能给你的native组件锁死访问范围:
- 给应用的native进程/共享库定义专属的SELinux域,只允许这个域访问
/data/data/[你的包名]/files/c_storage/路径下的文件 - 简化版规则示例:
allow my_app_native app_data_file:file { read write open } allow my_app_native app_data_file:dir { search read write } # 单独放开c_storage目录的权限 allow my_app_native my_app_c_storage_dir:dir { all } allow my_app_native my_app_c_storage_file:file { all } - 操作要点:要把
c_storage目录标记上对应的SELinux上下文,可以在应用初始化时用chcon命令设置,或者在编译脚本(Android.mk/CMakeLists.txt)里配置安装时的上下文。
2. 只传文件描述符,不让native碰路径
- 彻底不让native代码直接用路径访问文件,由Java层提前打开
c_storage下的文件,把文件描述符(FD)传给JNI层 - native代码只通过FD做读写操作,根本碰不到其他路径,自然没法越界
- 示例代码:
Java层:
JNI层:File cFile = new File(getFilesDir(), "c_storage/test.txt"); try (FileInputStream fis = new FileInputStream(cFile)) { int fd = fis.getFD(); nativeWriteToFd(fd, "test content"); } catch (IOException e) { e.printStackTrace(); }JNIEXPORT void JNICALL Java_com_example_MainActivity_nativeWriteToFd(JNIEnv *env, jobject thiz, jint fd, jstring content) { const char *str = (*env)->GetStringUTFChars(env, content, NULL); if (str != NULL) { write(fd, str, strlen(str)); (*env)->ReleaseStringUTFChars(env, content, str); } } - 这种方式从根源上切断了native代码访问其他目录的可能,就算共享库用dlsym拿到原始系统调用,也只能操作你给的FD。
3. 替换系统调用表(仅限root/定制ROM场景)
- 如果有root权限或者能定制ROM,可以直接修改native进程的系统调用表,拦截
open/openat这类文件访问的系统调用 - 在系统调用层面检查路径是否属于
c_storage,不符合就返回权限错误 - 但这个方案兼容性极差,普通应用没法用,只适合定制化场景。
为什么重写POSIX符号会被绕过
共享库可以通过dlsym(RTLD_NEXT, "open")拿到libc里的原始open函数,直接绕开你重写的符号。这种方式只能防防没刻意规避的代码,对付主动绕的完全没用。
内容的提问来源于stack exchange,提问作者Papers.ch
相关产品推荐
相关产品推荐

