Проект Android с открытым исходным кодом (AOSP) обеспечивает прочную базовую политику для приложений и служб, которые являются общими для всех устройств Android. Участники AOSP регулярно уточняют эту политику. Ожидается, что базовая политика будет составлять около 90–95 % окончательной политики на устройстве, а настройки для конкретных устройств составят оставшиеся 5–10 %. В этой статье основное внимание уделяется этим настройкам для конкретных устройств, тому, как написать политику для конкретных устройств, а также некоторым ловушкам, которых следует избегать на этом пути.
Поднятие устройства
При написании политики для конкретного устройства выполните следующие действия.
Запуск в разрешительном режиме
Когда устройство находится в разрешительном режиме , отказы регистрируются, но не применяются. Разрешающий режим важен по двум причинам:
- Разрешающий режим гарантирует, что запуск политики не будет задерживать другие ранние задачи запуска устройства.
- Вынужденный отказ может маскировать другие отказы. Например, доступ к файлу обычно влечет за собой поиск в каталоге, открытие файла, а затем чтение файла. В принудительном режиме произойдет только отказ в поиске по каталогу. Разрешающий режим гарантирует, что все отказы видны.
Самый простой способ перевести устройство в разрешающий режим — использовать командную строку ядра . Это можно добавить в файл BoardConfig.mk
устройства: platform/device/<vendor>/<target>/BoardConfig.mk
. После изменения командной строки выполните make clean
, затем make bootimage
и прошейте новый загрузочный образ.
После этого подтвердите разрешительный режим с помощью:
adb shell getenforce
Две недели — это разумный срок, чтобы находиться в глобальном разрешительном режиме. После устранения большинства отказов вернитесь в принудительный режим и устраняйте ошибки по мере их появления. Домены, которые все еще производят отказы, или службы, находящиеся в стадии интенсивной разработки, могут быть временно переведены в разрешительный режим, но возвращайте их в принудительный режим как можно скорее.
Принудительно применять рано
В принудительном режиме отказы регистрируются и применяются. Рекомендуется перевести устройство в принудительный режим как можно раньше. Ожидание создания и применения политики для конкретного устройства часто приводит к ошибкам в продукте и плохому взаимодействию с пользователем. Начните достаточно рано, чтобы принять участие в тестовом тестировании и обеспечить полное тестовое покрытие функциональности в реальном мире. Раннее начало гарантирует, что вопросы безопасности влияют на проектные решения. И наоборот, предоставление разрешений исключительно на основе наблюдаемых отказов является небезопасным подходом. Используйте это время для проведения аудита безопасности устройства и файлов с ошибками в отношении поведения, которое не должно быть разрешено.
Удалить или удалить существующую политику
Существует ряд веских причин для создания политики для конкретного устройства с нуля на новом устройстве, в том числе:
- Аудит безопасности
- Слишком либеральная политика
- Уменьшение размера полиса
- Мертвая политика
Устранение отказов в основных услугах
Отказы, генерируемые основными службами, обычно устраняются путем маркировки файлов. Например:
avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0” dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1 avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1
полностью решается правильной маркировкой /dev/kgsl-3d0
. В этом примере tcontext
— это device
. Это представляет собой контекст по умолчанию, в котором все в /dev
получает метку « устройство », если не назначена более конкретная метка. Простое принятие вывода от audit2allow здесь привело бы к неправильному и чрезмерно разрешительному правилу.
Чтобы решить эту проблему, дайте файлу более конкретную метку, в данном случае это gpu_device . Никаких дополнительных разрешений не требуется, так как медиасервер уже имеет необходимые разрешения в базовой политике для доступа к gpu_device.
Другие специфичные для устройства файлы, которые должны быть помечены типами, предопределенными в основной политике:
- блокировать устройства
- аудиоустройства
- видеоустройства
- датчики
- нфс
- gps_device
- файлы в /sys
- файлы в /proc
В общем, давать разрешения на метки по умолчанию неправильно. Многие из этих разрешений запрещены правилами neverallow , но даже если они не запрещены явно, рекомендуется указать конкретную метку.
Отметьте новые услуги и адреса отказов
Службы, запускаемые с помощью Init, должны работать в своих собственных доменах SELinux. В следующем примере служба «foo» помещается в свой собственный домен SELinux и предоставляет ей разрешения.
Сервис запускается в init. device .rc
как:
service foo /system/bin/foo class core
- Создайте новый домен "foo"
Создайте файл
device/ manufacturer / device-name /sepolicy/foo.te
со следующим содержимым:# foo service type foo, domain; type foo_exec, exec_type, file_type; init_daemon_domain(foo)
Это исходный шаблон для домена foo SELinux, к которому вы можете добавить правила, основанные на конкретных операциях, выполняемых этим исполняемым файлом.
- Ярлык
/system/bin/foo
Добавьте следующее в
device/ manufacturer / device-name /sepolicy/file_contexts
:/system/bin/foo u:object_r:foo_exec:s0
Это гарантирует, что исполняемый файл будет правильно помечен, поэтому SELinux запускает службу в правильном домене.
- Создайте и прошейте загрузочный и системный образы.
- Уточните правила SELinux для домена.
Используйте отказы для определения необходимых разрешений. Инструмент audit2allow предоставляет хорошие рекомендации, но используйте его только для информирования при написании политик. Не просто копируйте вывод.
Вернуться в принудительный режим
Можно устранять неполадки в разрешающем режиме, но как можно раньше переключитесь обратно в принудительный режим и постарайтесь оставаться в нем.
Распространенные ошибки
Вот несколько решений для распространенных ошибок, возникающих при написании политик для конкретных устройств.
Чрезмерное использование отрицания
Следующий пример правила похож на запирание входной двери, но оставление окон открытыми:
allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms
Смысл ясен: все, кроме сторонних приложений, могут иметь доступ к отладочному устройству.
Правило ошибочно в нескольких отношениях. Исключение untrusted_app
легко обойти, поскольку все приложения могут дополнительно запускать службы в домене isolated_app
. Аналогичным образом, если в AOSP будут добавлены новые домены для сторонних приложений, они также получат доступ к scary_debug_device
. Правило слишком либерально. Доступ к этому инструменту отладки не принесет пользы большинству доменов. Правило должно было быть написано, чтобы разрешать только домены, которым требуется доступ.
Функции отладки в продакшене
Функции отладки не должны присутствовать в производственных сборках, как и их политика.
Самая простая альтернатива — разрешить функцию отладки только тогда, когда SELinux отключен в сборках eng/userdebug, таких как adb root
и adb shell setenforce 0
.
Другая безопасная альтернатива — заключить разрешения отладки в инструкцию userdebug_or_eng .
Взрыв размера полиса
Характеристика SEAndroid Policies in the Wild описывает тревожную тенденцию роста количества настроек политики устройств. Политика для конкретного устройства должна составлять 5–10 % от общей политики, работающей на устройстве. Настройки в диапазоне 20%+ почти наверняка содержат привилегированные домены и мертвую политику.
Неоправданно большой полис:
- Получает двойной удар по памяти, так как политика находится на виртуальном диске, а также загружается в память ядра.
- Пустая трата места на диске из-за необходимости увеличения загрузочного образа.
- Влияет на время поиска политики среды выполнения.
В следующем примере показаны два устройства, где политика производителя составляет 50 % и 40 % политики на устройстве. Переписывание политики дало существенные улучшения безопасности без потери функциональности, как показано ниже. (Устройства AOSP Shamu и Flounder включены для сравнения.)
В обоих случаях политика была резко уменьшена как по размеру, так и по количеству разрешений. Уменьшение размера политики почти полностью связано с удалением ненужных разрешений, многие из которых, вероятно, были правилами, сгенерированными audit2allow
, которые были добавлены в политику без разбора. Мертвые домены также были проблемой для обоих устройств.
Предоставление возможности dac_override
Отказ dac_override
означает, что процесс-нарушитель пытается получить доступ к файлу с неправильными разрешениями пользователя/группы/мира unix. Правильное решение — почти никогда не предоставлять разрешение dac_override
. Вместо этого измените разрешения unix для файла или процесса . Некоторым доменам, таким как init
, vold
и installd
, действительно нужна возможность переопределять права доступа к файлам unix для доступа к файлам других процессов. Смотрите блог Дэна Уолша для более подробного объяснения.