2016-03-15 2 views
2

Мое приложение предназначено для корневых устройств Android, оно имеет корневую привилегию и нуждается в доступе к каталогу /dev/input, но почему он кидает opendir failed, Permission denied даже /dev/input уже был chmod - 777?Почему мой Android-приложение (имеет привилегии root) не имеет доступа/dev/input?

Я использую следующий код, чтобы получить корневую привилегию:

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

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="[email protected]@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="[email protected]@boot.art" dev="mmcblk0p43" ino=442379 scontext=u:r:shell:s0 tcontext=u:object_r:dalvikcache_data_file:s0 tclass=file permissive=0 
+1

Что бы вы ни пытались сделать, это, вероятно, плохая идея. Вы можете столкнуться с проблемами selinux, а не с разрешениями в стиле unix. –

+0

Проверьте выходные данные 'dmesg' (или' cat/proc/kmsg') для сообщений об ошибках selinux. Кроме того, запуск «su» не изменяет разрешения текущего процесса, поэтому из вашего вопроса не совсем ясно, действительно ли вы выполняете роль root. – fadden

+0

@ChrisStratton, Спасибо за указание! Но могу ли я изменить политику SELinux для своего приложения? Из поиска, похоже, я не могу, потому что политика SELinux записывается в образ ОС. Но есть странное явление: после того, как я установил и запустил другое приложение из Google Play, которое обращается к/dev/input, как я знал, мое приложение стало доступным/dev/input. Я не знаю, что сделало это приложение. – Suge

ответ

3

Как было отмечено в комментариях, у современных Android есть много дополнительных защитных слоев, помимо прав доступа к файлам Linux. Один из них - SELinux.

Даже с повышенными привилегиями, работая над SELinux, это rather complex - он разработан специально для предотвращения этого. Все настройки Android SELinux хранятся в одном файле с измененным форматом sepolicy. Этот файл является частью образа системы только для чтения, и его исправление в основном равносильно укоренению устройства. Практически только люди, работающие над этим, являются разработчиками приложений Superuser, такими как автор SuperSu или this one.

Вместо того, чтобы пытаться преодолеть SELinux самостоятельно, я рекомендую вам использовать все, что уже было сделано с помощью установленного приложения su. Например, SuperSu запускает команды, переданные ему, в неограниченном контексте SELinux (см. Ссылку на сайт Chainfire выше), по сути, как будто SELinux для него не существует. Это позволяет вам преодолевать SELinux путем запуска специализированных двоичных файлов через su, которые выполняют грязную работу для вас.

К сожалению, очень мало публичных высокоуровневых 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. Normal Android приложение создает Linux domain socket
  2. Normal Android приложение запускает бинарный файл с помощью системы «Су»
  3. Двоичных подключается к разъему
  4. Бинарный файл считывает имена файлов, написанных приложением, в сокет и открывает их
  5. Двоичный файл отправляет дескрипторы файлов указанных файлов в приложение через один и тот же сокет (техника также известный как "file descriptor passing")

Этот ловкий трюк будет работать до тех пор, как установлено «су» приложение успешно преодолевает SELinux и обеспечивает неограниченный контекст команд, запускаемых через него. Все современные, о которых я знаю, знают.


EDIT: Этот ответ был написан давно. Последний формат sepolicy Android больше не считается «измененным», их изменения успешно воссозданы (с юмором приводя к созданию еще одного обратного несовместимого формата sepolicy). Библиотека, связанная выше, по-прежнему отлично работает в целом, но ее функционирование еще больше ограничивается современными политиками SEAndroid, поэтому вы можете быть заинтересованы в ее new iteration. В связи с тем, что политики SELinux обеспечивают дополнительные проверки для каждого отдельного пользователя read/write в дополнение к стандартным проверкам Unix в течение open, было бы разумнее использовать разделяемую память и Linux-каналы, чтобы тщательно обойти эту политику, а не передавать исходные дескрипторы вызывающему абоненту.

+0

Я удивляюсь, чтобы получить такой хороший и подробный ответ, спасибо вам большое! – Suge