Инициализация поставщика

Процесс инициализации имеет практически неограниченные права доступа и использует входные скрипты как из системного, так и из стороннего раздела для инициализации системы во время загрузки. Такой доступ создает огромную брешь в разделении Treble между системой и сторонним разделом, поскольку скрипты стороннего раздела могут указывать процессу инициализации на доступ к файлам, свойствам и т. д., которые не являются частью стабильного двоичного интерфейса приложения (ABI) системы и стороннего раздела.

Vendor init предназначен для устранения этой уязвимости путем использования отдельного домена SELinux (security-enhanced Linux) vendor_init для выполнения команд, находящихся в каталоге /vendor с правами доступа, специфичными для конкретного поставщика.

Механизм

Vendor init создает дочерний процесс init на ранней стадии загрузки с контекстом SELinux u:r:vendor_init:s0 . Этот контекст SELinux имеет значительно меньше прав доступа, чем контекст init по умолчанию, и его доступ ограничен файлами, свойствами и т. д., которые либо специфичны для конкретного производителя, либо являются частью стабильного ABI системного производителя.

Init проверяет каждый загружаемый скрипт, начинается ли его путь с /vendor , и если да, то помечает его тегом, указывающим на то, что его команды должны выполняться в контексте инициализации поставщика. Каждая встроенная команда инициализации аннотируется логическим значением, указывающим, должна ли команда выполняться в подпроцессе инициализации поставщика:

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

Основной цикл обработки init содержит проверку: если команда помечена для выполнения в подпроцессе поставщика и исходит из скрипта поставщика, то эта команда отправляется посредством межпроцессного взаимодействия (IPC) в подпроцесс инициализации поставщика, который выполняет команду и отправляет результат обратно в init.

Используйте vendor init

Инициализация поставщика включена по умолчанию, и ее ограничения распространяются на все скрипты инициализации, присутствующие в разделе /vendor . Инициализация поставщика должна быть прозрачной для поставщиков, скрипты которых уже не обращаются только к системным файлам, свойствам и т. д.

Однако, если команды в заданном скрипте поставщика нарушают ограничения инициализации поставщика, они завершаются с ошибкой. В журнале ядра (видимом с помощью dmesg) команды инициализации, завершающиеся с ошибкой, появляется запись об ошибке. Любая команда, завершившаяся с ошибкой из-за политики SELinux, сопровождается проверкой SELinux. Пример ошибки, включающей проверку SELinux:

type=1400 audit(1511821362.996:9): avc: denied { search } for pid=540 comm="init" name="nfc" dev="sda45" ino=1310721 scontext=u:r:vendor_init:s0 tcontext=u:object_r:nfc_data_file:s0 tclass=dir permissive=0
init: Command 'write /data/nfc/bad_file_access 1234' action=boot (/vendor/etc/init/hw/init.walleye.rc:422) took 2ms and failed: Unable to write to file '/data/nfc/bad_file_access': open() failed: Permission denied

Если команда не выполнена, есть два варианта:

  • Если команда завершается с ошибкой из-за предполагаемого ограничения (например, если команда обращается к системному файлу или свойству), команду необходимо переписать таким образом, чтобы она была совместима с Treble, используя только стабильные интерфейсы. Правила neverallow предотвращают добавление разрешений на доступ к системным файлам, которые не являются частью стабильного ABI поставщика системы.
  • Если метка SELinux новая и ей еще не предоставлены разрешения в системном файле vendor_init.te , а также не исключены разрешения с помощью правил neverallow, новой метке могут быть предоставлены разрешения в файле vendor_init.te , специфичном для устройства.

Для устройств, выпущенных до Android 9, правила neverallows можно обойти, добавив атрибут типа data_between_core_and_vendor_violators в файл vendor_init.te , специфичный для данного устройства.

Места расположения кодов

Основная логика межпроцессного взаимодействия при инициализации поставщика находится в файле system/core/init/subcontext.cpp .

Таблица команд находится в классе BuiltinFunctionMap в файле system/core/init/builtins.cpp и содержит аннотации, указывающие, должна ли команда выполняться в подпроцессе инициализации поставщика.

Политика SEPolicy для инициализации поставщика разделена между частным ( system/sepolicy/private/vendor_init.te ) и публичным ( system/sepolicy/public/vendor_init.te ) каталогами в system/sepolicy.