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

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

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

Механизм

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

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

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

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

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

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

Однако, если команды в данном скрипте поставщика нарушают ограничения init поставщика, выполнение команд завершается ошибкой. В журнале ядра (отображаемом с помощью dmesg) от init отображается строка, указывающая на ошибку. Аудит 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 , специфичный для устройства.

Расположение кодов

Основная часть логики для IPC-инициализации поставщика находится в system/core/init/subcontext.cpp .

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

SEPolicy для vendor init разделена на частный ( system/sepolicy/private/vendor_init.te ) и публичный ( system/sepolicy/public/vendor_init.te ) каталоги в system/sepolicy.