【问题标题】:Why can't my Android app (has root privilege) access /dev/input?为什么我的 Android 应用程序(具有 root 权限)无法访问 /dev/input?
【发布时间】:2016-06-30 13:28:45
【问题描述】:

我的应用针对有root权限的Android设备,它有root权限,需要访问目录/dev/input,但是为什么它抛出opendir failed, Permission denied,甚至/dev/input已经是chmod777了?

我使用下面的代码来获取root权限:

Process root = Runtime.getRuntime().exec("su");

并使用下面的代码更改/dev/input的权限:

Shell.runCommand("chmod 777 /dev/input");

以上两步都成功了,但是为什么我的应用还是不能访问呢?通过搜索,有人说应用程序的运行时权限与文件系统中文件的权限无关。 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;
}

来自/prog/kmsg 的 SELinux 错误

<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 而不是 unix 风格的权限问题。
  • 检查dmesg(或cat /proc/kmsg)的输出是否有selinux错误信息。此外,运行“su”不会改变当前进程的权限,所以从你的问题中你是否真的以 root 身份运行并不完全清楚。
  • @ChrisStratton,感谢您的指出!但是我可以为我的应用修改 SELinux 策略吗?从搜索来看,我不能,因为 SELinux 策略被烧录到操作系统映像中。但是有一个奇怪的现象是,当我从 Google Play 安装并运行另一个访问 /dev/input 的应用程序后,我的应用程序就可以访问 /dev/input。我不知道那个应用做了什么。
  • @fadden,感谢您的回答。我已将主要代码和错误消息添加到帖子内容中。看起来是SELinux 阻止了我的访问,但我该如何修改呢?我知道Google Play中有另一个应用程序需要访问/dev/input,安装并运行后,我的应用程序可以访问它,可能是主要技术是什么?

标签: android linux android-ndk root selinux


【解决方案1】:

正如 cmets 中所指出的,现代 Android 除了 Linux 文件权限之外还有许多额外的防御层。其中之一是 SELinux。

即使具有提升的权限,在 SELinux 上工作也是 rather complex — 它是专门为防止这种情况而设计的。所有 Android SELinux 设置都存储在修改后的 sepolicy 格式的单个文件中。该文件是只读系统映像的一部分,并且修补它基本上等于生根设备。几乎只有超级用户应用程序的开发人员才从事这方面的工作,例如 SuperSu 的作者或this one

我建议您利用已安装的 su 应用程序已经完成的一切,而不是尝试自己克服 SELinux。例如,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"

只要安装的“su”应用程序成功克服 SELinux 并为通过它运行的命令提供不受限制的上下文,这个巧妙的技巧就会起作用。我所知道的所有现代人都这样做。


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

【讨论】:

  • 我很惊讶能得到这么好的详细答案,非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-17
  • 1970-01-01
  • 2019-09-03
  • 1970-01-01
  • 1970-01-01
  • 2011-06-21
相关资源
最近更新 更多