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 uma grande falha 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 (ABI, na sigla em inglês) estável do sistema/fornecedor.
O init do fornecedor foi projetado para resolver esse problema usando um domínio do Linux com segurança aprimorada (SELinux, na sigla em inglês) vendor_init separado para executar comandos encontrados em /vendor com permissões específicas do fornecedor.
Mecanismo
O init do fornecedor ramifica um subprocesso de init no início do processo de inicialização com o contexto do SELinux u:r:vendor_init:s0. Esse contexto do SELinux tem muito menos permissões do que o contexto init padrão, e o acesso dele é limitado a arquivos, propriedades etc. que são específicos do fornecedor ou fazem parte da ABI estável do sistema/fornecedor.
O init verifica se o caminho de cada script carregado começa com /vendor e, em caso afirmativo, o marca com uma indicação de que os comandos precisam ser executados no contexto do init do fornecedor. Cada init integrado é anotado com um booleano que especifica se o comando precisa ou não ser executado no subprocesso do init do fornecedor:
- A maioria dos comandos que acessam o sistema de arquivos é anotada para ser executada no subprocesso do init do fornecedor e, portanto, está sujeita à SEPolicy do init do fornecedor.
- A maioria dos comandos que afetam o estado interno do init (por exemplo, iniciar e interromper serviços) é executada no processo init normal. Esses comandos são informados de que um script do fornecedor está chamando-os para fazer o próprio processamento de permissões não SELinux.
O loop de processamento principal do init contém uma verificação de que, se um comando for anotado para ser executado no subprocesso do fornecedor e originado de um script do fornecedor, ele será enviado por comunicação entre processos (IPC, na sigla em inglês) para o subprocesso do init do fornecedor, que executa o comando e envia o resultado de volta ao init.
Usar o init do fornecedor
O init do fornecedor é ativado por padrão, e as restrições dele se aplicam a todos os scripts init presentes na partição /vendor. O init do fornecedor precisa ser transparente para os fornecedores cujos scripts já não acessam arquivos, propriedades etc. somente do sistema.
No entanto, se os comandos em um determinado script do fornecedor violarem as restrições do init do fornecedor, eles 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 deniedSe um comando falhar, há duas opções:
- Se o comando estiver falhando devido a uma restrição intencional (como se o comando 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 neverallow impedem a adição de permissões para acessar arquivos do sistema que não fazem parte da ABI estável do sistema/fornecedor.
- Se o rótulo do SELinux for novo e ainda não tiver permissões concedidas no
vendor_init.tedo sistema nem permissões excluídas pelas regras neverallow, o novo rótulo poderá receber permissões novendor_init.teespecífico do dispositivo.
Para dispositivos lançados antes do Android 9, as regras neverallow podem ser ignoradas adicionando o tipoattribute data_between_core_and_vendor_violators ao arquivo vendor_init.te específico do dispositivo.
Locais do código
A maior parte da lógica para a IPC do init 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 do init do fornecedor.
A SEPolicy para o init do fornecedor é dividida entre os diretórios particular (system/sepolicy/private/vendor_init.te) e público (system/sepolicy/public/vendor_init.te) em system/sepolicy.