O processo init tem permissões quase irrestritas e usa scripts de entrada das partições do sistema e do fornecedor para inicializar o sistema durante o processo de inicialização. Esse acesso causa um grande problema na divisão do sistema/fornecedor do Treble, já que os scripts do fornecedor podem instruir o init a acessar arquivos, propriedades etc. que não fazem parte da interface binária de aplicativo do sistema/fornecedor (ABI, na sigla em inglês) estável.
O init do fornecedor foi projetado para fechar esse problema usando um domínio
SELinux (Linux com segurança reforçada) vendor_init
separado para executar
comandos encontrados em /vendor
com permissões específicas do fornecedor.
Mecanismo
O init do fornecedor bifurca um subprocesso de init no início do processo de inicialização com o
contexto SELinux u:r:vendor_init:s0
. Esse contexto do SELinux tem
permissões consideravelmente menores do que o contexto de inicialização padrão, e o acesso dele é
limitado a arquivos, propriedades etc. específicos do fornecedor ou parte da
ABI estável do fornecedor do sistema.
O Init verifica cada script carregado para saber se o caminho dele começa com
/vendor
. Se sim, ele é marcado com uma indicação de que os comandos
precisam ser executados no contexto de inicialização do fornecedor. Cada init integrado é anotado com um
booleano que especifica se o comando precisa ser executado no subprocesso de inicialização
do fornecedor:
- A maioria dos comandos que acessam o sistema de arquivos é anotada para ser executada no subprocesso init do fornecedor e, portanto, está sujeita à SEPolicy de inicialização do fornecedor.
- A maioria dos comandos que afetam o estado de inicialização interno (por exemplo, iniciar e interromper serviços) são executados no processo de inicialização normal. Esses comandos são informados de que um script do fornecedor está os chamando para fazer o próprio processamento de permissões que não são do SELinux.
O ciclo de processamento principal do init contém uma verificação de que, se um comando é anotado para ser executado no subprocesso do fornecedor e origina-se de um script do fornecedor, esse comando é enviado por comunicação interprocesso (IPC, na sigla em inglês) para o subprocesso de inicialização do fornecedor, que executa o comando e envia o resultado de volta para o init.
Usar o init do fornecedor
A inicialização do fornecedor é ativada por padrão, e as restrições dela se aplicam a todos os scripts de inicialização
presentes na partição /vendor
. A inicialização do fornecedor precisa ser transparente
para fornecedores cujos scripts já não estão acessando arquivos,
propriedades etc. apenas do sistema.
No entanto, se os comandos em um determinado script do fornecedor violarem as restrições de inicialização do fornecedor, os comandos vão falhar. Os comandos com falha têm uma linha no registro do kernel (visível com dmesg) do init indicando a falha. Uma auditoria do SELinux acompanha qualquer comando com falha devido à política do SELinux. Exemplo de uma falha que inclui uma auditoria do 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
Se um comando falhar, há duas opções:
- Se o comando falhar devido a uma restrição intencional (por exemplo, se ele estiver acessando um arquivo ou propriedade do sistema), ele precisará ser reimplementado de uma maneira compatível com o Treble, passando apenas por interfaces estáveis. As regras de nunca permitir impedem a adição de permissões para acessar arquivos do sistema que não fazem parte da ABI estável do fornecedor do sistema.
- Se o rótulo do SELinux for novo e ainda não tiver recebido permissões no
vendor_init.te
do sistema nem permissões excluídas pelas regras neverallow, o novo rótulo poderá receber permissões novendor_init.te
específico do dispositivo.
Para dispositivos lançados antes do Android 9, as regras de nunca permitir podem ser ignoradas
adicionando o atributo de tipo data_between_core_and_vendor_violators
ao
arquivo vendor_init.te
específico do dispositivo.
Locais de código
A maior parte da lógica para o IPC de inicialização do fornecedor está em system/core/init/subcontext.cpp.
A tabela de comandos está na classe BuiltinFunctionMap
em system/core/init/builtins.cpp
e inclui anotações que indicam se o comando precisa ser executado no subprocesso
de inicialização do fornecedor.
A SEPolicy para o init do fornecedor é dividida entre os diretórios privados (system/sepolicy/private/vendor_init.te) e públicos (system/sepolicy/public/vendor_init.te) em system/sepolicy.