Теперь вопрос о том как получить права root на этих устройствах.
Информацию об этом читаем здесь:
Механизмы функционирования рут-прав на Андроиде или многа букф 2 (открыть там спойлер)
Вроде бы ничего сложного, однако в Андроиде механизм смены владельца у процесса окружен этаким флером таинственности, чему виной несколько причин.
Часть 1. Андроид до версии 4.3
В мире Unix все просто - запускаем su, она запрашивает пароль пользователя root, мы его вводим, su заменяет себя на шелл. В Андроиде никаких паролей у пользователей нет, да и заморачиваться с вводом пароля утилите su явно не с руки. Поэтому к утилите прилагается специальное приложение - запросчик рут-прав, называемое Superuser, CWM Superuser, SuperSU, тысячи их уже. Главной задачей этого запросчика является как раз авторизация рут-прав для того или иного приложения у человека. Дополнительно, любой запросчик ведет протоколирование операций, совершаемых от имени пользователя root. Обычно все считается перевернутым с ног на голову: приложение-запросчик якобы является главным, а утилита su - довесок к нему. Можно, наверное, представлять все именно так, но мы этого делать не будем. Хотя бы потому, что приложение-запросчик можно, как и любое другое приложение, установить из магазина Google Play, но никаких особых привилегий от такого действия не получишь. (Кстати, делать запросчик системным приложением, т. е. помещать его в каталог /system/app, совершенно не обязательно, откуда пошел этот «карго-культ», пусть разбираются будущие историки.) Поскольку методы обмена информацией об авторизации уникальны для каждого запросчика, реализации утилит su, для которых запросчики предназначены, несовместимы между собой. Другими словами, su для приложения Superuser не будет работать с приложениями CWM Superuser или SuperSU и наоборот.
Но практически на всех современных аппаратах нас будет интересовать:
Часть 2. Андроид версии 4.3 и выше
Начиная с 4.3 Гугль кардинально изменил правила игры, заменив традиционную систему привилегий Unix («руту доступно все») на систему «полномочий» (capabilities). Это, в свою очередь, привело к кардинальным изменениям в методах работы утилиты su.
При использовании системы «полномочий» каждое административное действие ограничено собственным полномочием. Например, полномочие CAP_FOWNER позволяет игнорировать права доступа к файлам, полномочие CAP_SYS_ADMIN разрешает монтировать дисковые устройства, CAP_NET_ADMIN - конфигурировать сетевые интерфейсы, CAP_KILL - игнорировать ограничения на посылку сигналов процессам. Такой подход позволяет избежать концентрации всех привилегий у одного пользователя-администратора (вируса, трояна). В ядре Linux система полномочий использовалась также задолго до появления Андроида. Другое дело, что в дистрибутивах Linux система полномочий практически не используется — пользователю root выдают все полномочия, остальным … ну, вы поняли. Поэтому, хотя ядро внутри себя трудолюбиво проверяет именно полномочия, снаружи этого не видно: по-прежнему, есть root и есть «твари дрожащие» все остальные пользователи.
Гугль, однако, сделал пользователя с uid 0 самым обычным пользователем, лишив все процессы полномочий. Небольшая лазейка, как вы понимаете, все же осталась (рут-то можно получить на всех Андроидах). Дело в том, что некоторые процессы с uid 0 по-прежнему обладают всем набором полномочий. Скажем, самый первый процесс, init, с номером (pid) 1, запускаемый самим ядром, имеет владельцем пользователя root (кого же еще) и все полномочия, процессы, запускаемые лично процессом init, наследуют набор полномочий от него. Но все приложения в Андроиде запускаются другим процессом (его называют zygote), который, хотя и является потомком init, однако сразу после запуска сбрасывает все полномочия, лишая таковых и все свои процессы-потомки. Причем не просто сбрасывает, а еще инструктирует ядро, чтобы не давало его процессам-потомкам (и их потомкам) никаких новых полномочий. Таким образом, начиная с Андроида 4.3, получить какие-либо полномочия приложения уже не в состоянии. А для пущей надежности Гугль еще и проинструктировал ядро Linux игнорировать suid биты на исполняемых файлах в разделе /system. Для этого прямо в виртуальную машину Dalvik был добавлен код, перемонтирующий раздел /system с опцией nosuid для процесса zygote (а, следовательно, и всех его потомков).
Отстреливание бита suid для процессов, порождаемых zygote, использует еще один непривычный механизм ядра Linux – пространство имен точек монтирования (mount namespace). Гугль впервые применил его еще в Андроиде 4.2 для поддержки многопользовательского режима в Андроиде. Однако пространства имен точек монтирования работали в 4.2, даже когда в системе был ровно один пользователь.
Замечу, что «пользователь» в Андроиде, хотя тоже идентифицируется целым неотрицательным числом, совершенно не совпадает с понятием uid ядра. Система uid в Андроиде с самого начала использовалась для идентификации приложений, и когда Гуглю пришлось таки изобрести еще и систему идентификации пользователей, инженеры нашли элегантное решение, поражающее своей непосредственностью, - идентификатор Андроид-пользователя (user id) хранится … в старших разрядах uid.
Код: Выделить всё
[olej@dell platform-tools]$ ./adb -s 0123456789ABCDEF shell
shell@elink8321_emmc:/ $ ps | grep zygote
root 247 1 947084 19292 ffffffff 00000000 S zygote
Итак, что мы имеем в итоге. У нас есть начальное пространство имен точек монтирования для процесса init и его потомков, все процессы, кроме adbd (и его потомков) и zygote (и его потомков) имеют владельцем пользователя root и полный набор полномочий. Приложения (т. е. потомки zygote) не могут менять владельца для своих потомков. У приложений нет никаких полномочий и их принципиально нельзя добавить. В сеансах adb владельца можно поменять, но пользователь с uid 0 изначально не будет иметь никаких полезных привилегий, это можно будет изменить, явно установив нужные полномочия (например, задав их для исполняемого файла su, подобно биту suid). Кстати, тем, кто считает что это плохо, возражу, что это таки хорошо. Теперь зловредам (вирусам и троянам) на нерутованном Андроиде гораздо сложнее сделать что-то по-настоящему вредное.
Имея полноправный init, функции «рут-прав» придется выполнять от имени процесса - потомка init. Поэтому утилита su для Андроидов 4.3 и выше «разрезана» на две части: демон su, запускаемый init (или его потомком, что несущественно), и собственно утилита su, являющаяся мостом (proxy) между приложением (или сеансом adb) и демоном. Как запустить демон su - разговор отдельный и нам малоинтересный, способы со всеми подробностями легко находятся в других источниках. Поговорим лучше об изменениях в алгоритме выдачи рут-прав приложениям.
1. Приложение порождает новый процесс, в котором выполняет утилиту su. Потоки стандартного ввода, стандартного вывода и стандартного вывода ошибок назначаются на каналы , связывающие процесс-потомок (su) с процессом-родителем (приложением). [Этот пункт, конечно же, не меняется.]
2. «Поскольку у выполняемого файла su установлен бит suid...» Этот пункт полностью исчезает для приложений. Но и для сеансов adb - тоже, владельца процесса, конечно, можно сменить на uid 0, но толку-то с того.
2'. Поэтому утилита su связывается с демоном su, передавая ему свои потоки stdin, stout и stderr, полученные от приложения или сеанса adb. (В Linux такие фокусы возможны.) Механизмы передачи потоков для приложения и для сеанса слегка отличаются, но нам это несущественно.
3, 4 Где-то в этом месте (где именно, зависит от реализации утилиты) выполняется авторизация действия. Делает ли это сама утилита или демон, для нас не так важно. Конечно, для авторизации по-прежнему используется специальное приложение — запросчик рут-прав. И точно также демон или утилита (или даже оба, независимо друг от друга), получая ответ, информируют запросчик о результатах.
5. Демон порождает процесс, в котором выполняет шелл, и привязывает к этому процессу переданные ему потоки в качестве stdin, stdout и stderr. Таким образом, каналы, созданные в приложении, пройдя через утилиту и демон, оказываются прикрепленными к процессу с шеллом, uid 0 и всеми полномочиями.
6. Теперь приложение, запросившее рут-права [как и ранее] может выдавать команды шеллу в канал stdin, получая ответы из stdout и stderr.
7. Утилита su дожидается от демона кода возврата из процесса-шелла, чтобы вернуть этот код приложению. [Ранее, код возврата доставлялся приложению сам собой, поскольку рут-шелл был прямым потомком процесса с приложением.]
Как мы видим, принципиально ничего не изменилось - приложение по-прежнему имеет доступ к процессу с uid 0 и всеми полномочиями.
Заканчивая рассказ про рут права в Андроидах 4.3 и выше замечу еще, что помимо capabilities и namespaces, Гугль задействовал в Андроидах также и подсистему SELinux (проект SEAndroid), причем в 4.3, 4.4 и 5.0 добавлялись все новые и новые ограничения. В итоге, например, даже имея «полноценный» рут-доступ, предоставляемый демоном su, нельзя отредактировать понравившийся системный файл, т. к. он защищен от изменений уже на уровне SELinux. В действительности, можно, конечно, но нужно знать, что такое контекст SELinux и как его установить для процесса.