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 enorme buraco na divisão sistema/fornecedor do Treble, pois 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) estável do sistema-fornecedor.
O vendor init foi projetado para fechar essa lacuna usando um domínio Linux (SELinux) separado com segurança aprimorada vendor_init
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
. Este contexto SELinux tem consideravelmente menos permissões do que o contexto init padrão e seu acesso é limitado a arquivos, propriedades, etc. que são específicos do fornecedor ou fazem parte da ABI estável do fornecedor do sistema.
O Init verifica cada script que carrega para ver se seu caminho começa com /vendor
e, em caso afirmativo, marca-o com uma indicação de que seus comandos devem ser executados no contexto init do fornecedor. Cada init embutido é anotado com um booleano que especifica se o comando deve ou não ser executado no subprocesso init do fornecedor:
- A maioria dos comandos que acessam o sistema de arquivos são anotados para serem executados no subprocesso init do fornecedor e, portanto, estão sujeitos à SEPolicy init do fornecedor.
- A maioria dos comandos que afetam o estado de inicialização interno (por exemplo, iniciar e parar serviços) são executados dentro do processo de inicialização normal. Esses comandos são informados de que um script do fornecedor os está chamando para fazer seu próprio tratamento 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 se originar de um script do fornecedor, esse comando será enviado via comunicação entre processos (IPC) para o subprocesso init do fornecedor, que executa o comando e envia o resultado de volta para o init.
Usando inicialização do fornecedor
A inicialização do fornecedor é habilitada por padrão e suas restrições se aplicam a todos os scripts de inicialização presentes na partição /vendor
. A inicialização do fornecedor deve ser transparente para fornecedores cujos scripts já não estão acessando apenas arquivos, propriedades do sistema, etc.
No entanto, se os comandos em um determinado script de fornecedor violarem as restrições de inicialização do fornecedor, os comandos falharão. Comandos com falha possuem uma linha no log do kernel (visível com dmesg) do init indicando falha. Uma auditoria SELinux acompanha qualquer comando com falha devido à política SELinux. Exemplo de falha incluindo uma auditoria 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, existem duas opções:
- Se o comando falhar devido a uma restrição pretendida (como se o comando estiver acessando um arquivo ou propriedade do sistema), o comando deverá ser reimplementado de maneira amigável ao 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 fornecedor do sistema.
- Se o rótulo SELinux for novo e ainda não tiver permissões concedidas no sistema
vendor_init.te
nem permissões excluídas por meio das 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 neverallows 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 deve ser executado no subprocesso init do fornecedor.
A SEPolicy para init do fornecedor é dividida entre os diretórios privado ( system/sepolicy/private/vendor_init.te ) e público ( system/sepolicy/public/vendor_init.te ) em system/sepolicy.