Написание политики SELinux

Проект 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.

Другие специфичные для устройства файлы, которые должны быть помечены типами, предопределенными в основной политике:

В общем, давать разрешения на метки по умолчанию неправильно. Многие из этих разрешений запрещены правилами neverallow , но даже если они не запрещены явно, рекомендуется указать конкретную метку.

Отметьте новые услуги и адреса отказов

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

Сервис запускается в init. device .rc как:

service foo /system/bin/foo
    class core
  1. Создайте новый домен "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, к которому вы можете добавить правила, основанные на конкретных операциях, выполняемых этим исполняемым файлом.

  2. Ярлык /system/bin/foo

    Добавьте следующее в device/ manufacturer / device-name /sepolicy/file_contexts :

    /system/bin/foo   u:object_r:foo_exec:s0
    

    Это гарантирует, что исполняемый файл будет правильно помечен, поэтому SELinux запускает службу в правильном домене.

  3. Создайте и прошейте загрузочный и системный образы.
  4. Уточните правила 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 включены для сравнения.)

Рисунок 1: Сравнение размера политики для конкретного устройства после аудита безопасности.

Рисунок 1 . Сравнение размера политики для конкретного устройства после аудита безопасности.

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

Предоставление возможности dac_override

Отказ dac_override означает, что процесс-нарушитель пытается получить доступ к файлу с неправильными разрешениями пользователя/группы/мира unix. Правильное решение — почти никогда не предоставлять разрешение dac_override . Вместо этого измените разрешения unix для файла или процесса . Некоторым доменам, таким как init , vold и installd , действительно нужна возможность переопределять права доступа к файлам unix для доступа к файлам других процессов. Смотрите блог Дэна Уолша для более подробного объяснения.