我的应用程序针对有根的Android设备,它具有root权限并需要访问目录/dev/input
,但为什么它opendir failed, Permission denied
甚至/dev/input
已经chmod
777
到Process root = Runtime.getRuntime().exec("su");
?
我使用下面的代码获取root权限:
/dev/input
并使用以下代码更改Shell.runCommand("chmod 777 /dev/input");
的权限:
/dev/input
上述两个步骤都是成功的,但为什么我的应用仍然无法访问它?从搜索中,有人说应用程序的运行时权限与文件系统中文件的权限无关。什么是Android运行时的权限系统?如何让应用能够访问jint Java_com_foo_funnyapp_Native_scanInputDevicesJNI(JNIEnv* env, jclass clazz)
{
const char *dirname = "/dev/input";
DIR *dir;
dir = opendir(dirname); // opendir failed, Permission denied
if(dir == NULL)
return -1;
......
return 0;
}
?
增加:
我的测试环境是Android 5.1.1,代码的主要部分是:
/prog/kmsg
来自<36>[19700411_05:32:43.957165]@0 type=1400 audit(8631163.939:1105): avc: denied { write } for pid=15706 comm="app_process64_o" name="system@framework@boot.art" dev="mmcblk0p43" ino=442379 scontext=u:r:shell:s0 tcontext=u:object_r:dalvikcache_data_file:s0 tclass=file permissive=0
<11>[19700411_05:32:44.118202]@0 init: untracked pid 15674 exited with status 0
<11>[19700411_05:32:44.202288]@0 init: untracked pid 15704 exited with status 224
<36>[19700411_05:32:44.225334]@0 type=1400 audit(8631164.209:1106): avc: denied { read } for pid=15734 comm="Thread-111" name="input" dev="tmpfs" ino=12525 scontext=u:r:untrusted_app:s0 tcontext=u:object_r:input_device:s0 tclass=dir permissive=0
<36>[19700411_05:32:44.332135]@0 type=1400 audit(8631164.319:1107): avc: denied { write } for pid=15742 comm="app_process64_o" name="system@framework@boot.art" dev="mmcblk0p43" ino=442379 scontext=u:r:shell:s0 tcontext=u:object_r:dalvikcache_data_file:s0 tclass=file permissive=0
image
答案 0 :(得分:4)
正如评论中所指出的,除了Linux文件权限之外,现代Android还有许多额外的防御层。其中一个是SELinux。
即使提升了权限,SELinux的工作也是rather complex - 它是专门为防止这种情况而设计的。所有Android SELinux设置都存储在修改后的sepolicy格式的单个文件中。该文件是只读系统映像的一部分,修补它基本上等于生成设备。几乎只有那些工作的人才是Superuser应用程序的开发者,例如SuperSu的作者或this one。
我建议您不要尝试自己克服SELinux,而应该利用安装的su app已经完成的任务。例如,SuperSu在无限制的SELinux上下文中运行传递给它的命令(参见上面Chainfire站点的链接),基本上就好像SELinux不存在一样。这允许您通过su运行专门的二进制文件来克服SELinux,它可以为您完成脏工作。
遗憾的是,很少有公共高级API可用于这种纯粹的原生二进制文件。您可以使用Linux内核系统调用和一些C库函数......就是这样。幸运的是,如果您只想打开一堆受保护的文件,则无需在本机帮助程序二进制文件中移动大量逻辑。相反,您可以使用“开放服务器”库,例如this one:Context context = ...
try (FileDescriptorFactory factory = FileDescriptorFactory.create(context);
ParcelFileDescriptor fd = factory.open("/dev/input", 2))
{
// the file descriptor is yours, as if you have gotten it by
// calling ParcelFileDescriptor#open
// You can use it from Java or pass to native code to read/write/ioctl on it
...
} catch (FactoryBrokenException oups) {
// most likely the root access being denied
...
} catch (IOException ioerr) {
...
}
免责声明:我是链接库的作者。
“开放服务器”的概念非常简单:
只要安装的“su”app成功克服了SELinux并为通过它运行的命令提供不受限制的上下文,这个巧妙的技巧就会起作用。我所知道的所有现代的都是。
编辑:这个答案已经写了一段时间。最新的Android sepolicy格式不再被视为“已修改”,其更改已成功升级(幽默地导致创建另一种向后不兼容的sepolicy格式)。上面链接的库仍然可以正常工作,但它的功能受到现代SEAndroid策略的进一步限制,因此您可能对它感兴趣new iteration。由于事实上,除read
期间的标准Unix检查外,SELinux策略还对每个write
/ open
执行额外检查,因此使用共享内存和Linux管道可能更为明智。仔细解决策略,而不是将原始描述符传递给调用者。