Sug*_*uge 2 linux android selinux root android-ndk
我的应用程序的目的是有根的Android设备,它具有超级用户权限,需要访问该目录/dev/input,但为什么它抛出opendir failed, Permission denied,甚至/dev/input已是chmod到777?
我使用以下代码获取root特权:
Process root = Runtime.getRuntime().exec("su");
Run Code Online (Sandbox Code Playgroud)
并使用以下代码更改以下权限/dev/input:
Shell.runCommand("chmod 777 /dev/input");
Run Code Online (Sandbox Code Playgroud)
以上两个步骤都成功,但是为什么我的应用程序仍无法访问它?通过搜索,有人说应用程序的运行时权限与文件系统中文件的权限无关。Android运行时的权限系统是什么?如何使应用程序能够访问/dev/input?
加成:
我的测试环境是Android 5.1.1,代码的主要部分是:
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;
}
Run Code Online (Sandbox Code Playgroud)
SELinux错误来自 /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
Run Code Online (Sandbox Code Playgroud)
正如评论中指出的那样,现代Android除了Linux文件权限外还具有许多其他防御层。其中之一就是SELinux。
即使具有特权提升,围绕SELinux的工作也相当复杂 -它是专门为防止这种情况而设计的。所有Android SELinux设置都存储在修改后的Sepolicy格式的单个文件中。该文件是只读系统映像的一部分,对其进行修补基本上等同于生根设备。几乎只有从事此工作的人是Superuser应用程序的开发人员,例如SuperSu的作者或this。
建议您不要尝试自己克服SELinux,而要利用已安装的su应用程序已经完成的一切。例如,SuperSu在不受限制的SELinux上下文中运行传递给它的命令(请参见上面的Chainfire网站的链接),实质上就像SELinux不存在一样。这使您可以通过su运行专用二进制文件来克服SELinux,这会为您带来麻烦。
可悲的是,只有很少的公共高级API可用于此类纯本机二进制文件。您可以使用Linux内核syscall和一些C库函数...就是这样。幸运的是,如果您只想打开一堆受保护的文件,则无需在本机帮助程序二进制文件中移动大量逻辑。相反,您可以使用“开放服务器”库,例如以下库:
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) {
...
}
Run Code Online (Sandbox Code Playgroud)
免责声明:我是链接库的作者。
“开放服务器”的概念非常简单:
只要已安装的“ su”应用程序成功克服SELinux并为通过它运行的命令提供不受限制的上下文,此巧妙的技巧就将起作用。我所知道的所有现代人都在做。
编辑:这个答案已经写了一段时间。最新的Android sepolicy格式已不再视为“已修改”,其更改已成功上游(很遗憾导致创建了另一种向后不兼容的sepolicy格式)。上面链接的库在总体上仍然可以正常运行,但是其功能已受到现代SEAndroid策略的进一步限制,因此您可能会对它的新迭代感兴趣。由于这一事实,SELinux策略 在期间对每个单独的对象执行了额外的检查read/ write除了标准的Unix检查之外open,使用共享内存和Linux管道来仔细地解决该策略,而不是将原始描述符传递给调用者可能是更明智的选择。