为什么我的Android应用程序(具有root权限)访问/ dev / input?

时间:2016-03-15 08:11:29

标签: android linux android-ndk root selinux

我的应用程序针对有根的Android设备,它具有root权限并需要访问目录/dev/input,但为什么它opendir failed, Permission denied甚至/dev/input已经chmod 777Process 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

的SELinux错误
image

1 个答案:

答案 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) {
    ...
}

免责声明:我是链接库的作者。

“开放服务器”的概念非常简单:

  1. 普通Android应用会创建Linux domain socket
  2. 普通Android应用程序通过系统“su”启动二进制文件
  3. 二进制文件连接到套接字
  4. 二进制文件读取应用程序写入套接字的文件名称并打开它们
  5. 二进制文件通过相同的套接字将所述文件的文件描述符发送到应用程序(该技术也称为"file descriptor passing"
  6. 只要安装的“su”app成功克服了SELinux并为通过它运行的命令提供不受限制的上下文,这个巧妙的技巧就会起作用。我所知道的所有现代的都是。

    编辑:这个答案已经写了一段时间。最新的Android sepolicy格式不再被视为“已修改”,其更改已成功升级(幽默地导致创建另一种向后不兼容的sepolicy格式)。上面链接的库仍然可以正常工作,但它的功能受到现代SEAndroid策略的进一步限制,因此您可能对它感兴趣new iteration。由于事实上,除read期间的标准Unix检查外,SELinux策略还对每个write / open执行额外检查,因此使用共享内存和Linux管道可能更为明智。仔细解决策略,而不是将原始描述符传递给调用者。