为什么我的Android应用程序(具有root特权)不能访问/dev/input? [英] Why can't my Android app (has root privilege) access /dev/input?

查看:191
本文介绍了为什么我的Android应用程序(具有root特权)不能访问/dev/input?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序针对植根于Android设备,它具有root特权,需要访问目录/dev/input,但是为什么即使/dev/input已经被chmod转换为777,它也会抛出opendir failed, Permission denied? >

我使用以下代码获取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

解决方案

正如注释中指出的那样,现代Android除了Linux文件权限外,还具有许多其他防御层.其中之一就是SELinux.

即使具有提升的特权,围绕SELinux的工作也是相当复杂 –它是专门为防止那.所有Android SELinux设置都存储在修改后的 sepolicy 格式的单个文件中.该文件是只读系统映像的一部分,对其进行修补基本上等同于生根设备.只有从事该工作的人是Superuser应用程序的开发人员,例如SuperSu或此人的作者.

我建议您不要试图克服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) {
    ...
}

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

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

  1. 普通的Android应用会创建 Linux域套接字
  2. 普通的Android应用通过系统"su"启动二进制文件
  3. 二进制文件连接到套接字
  4. 二进制文件将应用程序写入套接字的文件名读取并打开它们
  5. 二进制文件通过同一套接字将所述文件的文件描述符发送到应用程序(该技术也称为)

只要已安装的"su"应用程序成功克服SELinux并为通过它运行的命令提供不受限制的上下文,此巧妙的技巧就将起作用.我所知道的所有现代人都可以.


编辑:这个答案是在不久前写的.最新的Android sepolicy格式已不再被视为已修改",其更改已成功实现上游(很遗憾导致创建了又一个向后不兼容的sepolicy格式).上面链接的库通常仍然可以正常运行,但是现代SEAndroid策略进一步限制了它的功能,因此您可能会对

And use the code below to change the permissions of /dev/input:

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

Both the two steps above are successful, but why can't it be accessed by my app still? From the searching, someone says the runtime permissions of an app is nothing to do with the permissions of the file in file system. What's the permissions system of Android runtime? How can I make the app be able to access /dev/input?

Addition:

My test environment is Android 5.1.1, main part of the code is:

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;
}

SELinux error from /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

解决方案

As was pointed out in comments, modern Android has many additional defensive layers besides Linux file permissions. One of them is SELinux.

Even with elevated privileges, working around SELinux is rather complex — it is designed specifically to prevent that. All Android SELinux settings are stored in a single file of modified sepolicy format. That file is a part of read-only system image, and patching it basically equals to rooting a device. Pretty much only people working on that are developers of Superuser apps, such as author of SuperSu or this one.

Instead of trying to overcome SELinux yourself, I recommend you to leverage whatever was already done by installed su app. For example, SuperSu runs commands, passed to it, in unrestricted SELinux context (see link to Chainfire's site above), essentially as if SELinux didn't exist for it. This allows you to overcome SELinux by running specialized binaries via su, which do the dirty job for you.

Sadly, there are very few public high-level APIs, available to such pure native binaries. You can use Linux kernel syscalls and some C library functions... and that is it. Fortunately, if all you want is opening a bunch of protected files, there is no need to move lots of logic in native helper binary. Instead you can use an "open server" library, such as 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) {
    ...
}

Disclaimer: I am the author of linked library.

The concept of "open server" is pretty simple:

  1. Normal Android app creates a Linux domain socket
  2. Normal Android app launches binary via system "su"
  3. The binary connects to the socket
  4. The binary reads names of files written by app to the socket and opens them
  5. The binary sends file descriptors of said files to app via the same socket (the technique also known as "file descriptor passing")

This neat trick is going to work as long as installed "su" app successfully overcomes SELinux and provides unrestricted context to commands being run via it. All modern ones I know about do.


EDIT: This answer has been written a while ago. The latest Android sepolicy format is no longer considered "modified", their changes has been successfully upstreamed (humorously leading to creation of yet another backward-incompatible sepolicy format). The library, linked above, still works fine in general, but it's functioning has been further restricted by modern SEAndroid policies, so you may be interested in it's new iteration. Due to the fact, that SELinux policies enforce additional checks on each individual read/write in addition to standard Unix checks during open, it might be wiser to use shared memory and Linux pipes to carefully work around the policy, rather then passing the original descriptors to caller.

这篇关于为什么我的Android应用程序(具有root特权)不能访问/dev/input?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆