为什么可以';t我的Android应用程序(具有root权限)访问/dev/input?
我的应用程序针对有根的Android设备,它有根权限,需要访问目录为什么可以';t我的Android应用程序(具有root权限)访问/dev/input?,android,linux,android-ndk,root,selinux,Android,Linux,Android Ndk,Root,Selinux,我的应用程序针对有根的Android设备,它有根权限,需要访问目录/dev/input,但为什么它抛出opendir失败,权限被拒绝甚至/dev/input已经被chmod转到777 我使用下面的代码获取根权限: Process root = Runtime.getRuntime().exec("su"); 并使用下面的代码更改/dev/input的权限: Shell.runCommand("chmod 777 /dev/input"); 上面两个步骤都成功了,但是为什么我的应用程序仍然不能
/dev/input
,但为什么它抛出opendir失败,权限被拒绝
甚至/dev/input
已经被chmod
转到777
我使用下面的代码获取根权限:
Process root = Runtime.getRuntime().exec("su");
并使用下面的代码更改/dev/input
的权限:
Shell.runCommand("chmod 777 /dev/input");
上面两个步骤都成功了,但是为什么我的应用程序仍然不能访问它呢?通过搜索,有人说应用程序的运行时权限与文件系统中文件的权限无关。安卓运行时的权限系统是什么?如何使应用程序能够访问/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;
}
来自/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
[19700411\u 05:32:43.957165]@0 type=1400审核(8631163.939:1105):avc:denied{write}for pid=15706 comm=“app_process64\u o”name=”system@framework@boot.art“dev=“mmcblk0p43”ino=442379 scontext=u:r:shell:s0 tcontext=u:object\u r:dalvikache\u data\u file:s0 tclass=file permissive=0
[19700411_05:32:44.118202]@0初始:未跟踪的pid 15674已退出,状态为0
[19700411_05:32:44.202288]@0初始:未跟踪的pid 15704已退出,状态为224
[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\u app:s0tcontext=u:object\r:input\u设备:s0tclass=dir permissive=0
[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\u r:dalvikache\u data\u file:s0 tclass=file permissive=0
正如评论中所指出的,现代Android除了Linux文件权限外,还有许多额外的防御层。其中之一是塞利努克斯
即使拥有提升的特权,围绕SELinux工作也是——它是专门为防止这种情况而设计的。所有Android SELinux设置都存储在一个修改格式的文件中。该文件是只读系统映像的一部分,对其进行修补基本上等于对设备进行根处理。几乎只有从事这项工作的人是超级用户应用程序的开发人员,比如《超级用户》或《超级用户》的作者
我建议您不要试图自己克服SELinux,而是利用已安装的su应用程序所做的一切。例如,SuperSu在不受限制的SELinux上下文中运行传递给它的命令(请参见上面链接到Chainfire的站点),本质上就好像SELinux不存在一样。这允许您通过su运行专门的二进制文件来克服SELinux,这会为您带来麻烦
遗憾的是,可用于此类纯本机二进制文件的公共高级API非常少。您可以使用Linux内核系统调用和一些C库函数。。。就这样。幸运的是,如果您只想打开一堆受保护的文件,那么就不需要在原生助手二进制文件中移动大量逻辑。相反,您可以使用“开放服务器”库,例如:
免责声明:我是链接库的作者
“开放服务器”的概念非常简单:
编辑:这个答案是不久前写的。最新的Android sepolicy格式不再被视为“修改”,它们的更改已经成功地向上游移动(幽默地导致创建了另一种向后不兼容的sepolicy格式)。上面链接的库总体上仍然可以正常工作,但它的功能受到现代SEAndroid政策的进一步限制,因此您可能对它的功能感兴趣。由于SELinux策略对每个
读
/写
执行额外的检查,除了在打开
期间执行标准的Unix检查之外,更明智的做法是使用共享内存和Linux管道仔细处理策略,而不是将原始描述符传递给调用者。无论你想做什么都可能是个坏主意。您可能遇到selinux而不是unix风格的权限问题。请检查dmesg
(或cat/proc/kmsg
)的输出以了解selinux错误消息。此外,运行“su”不会改变当前进程的权限,因此您的问题并不完全清楚您是否实际以root用户身份运行。@ChrisStratton,谢谢您指出!但是我能为我的应用修改SELinux策略吗?从搜索结果来看,似乎我不能,因为SELinux策略被烧录到操作系统映像中。但有一个奇怪的现象是,在我安装并运行了另一个来自GooglePlay的应用程序后,我知道它可以访问/dev/input,然后我的应用程序就可以访问/dev/input了。我不知道那个应用程序做了什么。@fadden,谢谢你的回答。我已经在帖子内容中添加了主代码和错误消息。看起来它是SELinux
阻止了我的访问,但我如何修改它?我知道Google Play中还有另一个应用程序需要访问/dev/input
,在我安装并运行它之后,我的应用程序能够访问它,主要的技术是什么?我很惊讶得到这么好的详细答案,非常感谢!
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) {
...
}