Verificação de inicialização

A inicialização verificada exige a verificação criptográfica de todos os códigos executáveis e dados que fazem parte da versão do Android que está sendo inicializada antes de ser usada. Isso inclui o kernel (carregado da partição boot), a árvore de dispositivos (carregada da partição dtbo), a partição system, a partição vendor e assim por diante.

Partições pequenas, como boot e dtbo, que são lidas apenas uma vez, geralmente são verificadas carregando todo o conteúdo na memória e calculando o hash. Em seguida, esse valor de hash calculado é comparado ao valor de hash esperado. Se o valor não corresponder, o Android não será carregado. Para mais detalhes, consulte Fluxo de inicialização.

Partições maiores que não cabem na memória (como sistemas de arquivos) podem usar uma árvore de hash em que a verificação é um processo contínuo que acontece à medida que os dados são carregados na memória. Nesse caso, o hash da raiz da árvore de hash é calculado durante o tempo de execução e verificado em relação ao valor esperado do hash da raiz. O Android inclui o driver dm-verity para verificar partições maiores. Se em algum momento o hash de raiz calculado não corresponder ao valor de hash de raiz esperado, os dados não serão usados e o Android vai entrar em um estado de erro. Para mais detalhes, consulte corrupção do dm-verity.

Os hashes esperados geralmente são armazenados no final ou no início de cada partição verificada, em uma partição dedicada ou em ambos. É importante lembrar que esses hashes são assinados (direta ou indiretamente) pela raiz de confiança. Por exemplo, a implementação do AVB aceita as duas abordagens. Consulte Inicialização verificada do Android para mais detalhes.

Proteção contra reversão

Mesmo com um processo de atualização completamente seguro, é possível que um exploit não persistente do kernel do Android instale manualmente uma versão mais antiga e vulnerável do Android, reinicie na versão vulnerável e use essa versão do Android para instalar um exploit persistente. A partir daí, o invasor passa a ser o proprietário permanente do dispositivo e pode fazer qualquer coisa, incluindo desativar as atualizações.

A proteção contra essa classe de ataques é chamada de Proteção de rollback. A proteção contra reversão normalmente é implementada usando armazenamento inviolável para registrar a versão mais recente do Android e impedir a inicialização do Android se ele for mais antigo que a versão registrada. As versões geralmente são rastreadas por partição.

Para mais detalhes sobre como o AVB lida com proteções de rollback, consulte o README (link em inglês) do AVB.

Resolver erros de verificação

A verificação pode falhar durante a inicialização (por exemplo, se o hash calculado na partição boot não corresponder ao hash esperado) ou durante a execução (por exemplo, se o dm-verity encontrar um erro de verificação na partição system). Se a verificação falhar na inicialização, o dispositivo não poderá ser inicializado, e o usuário final precisará seguir etapas para recuperar o dispositivo.

Se a verificação falhar durante a execução, o fluxo será um pouco mais complicado. Se o dispositivo usar dm-verity, ele precisará ser configurado no modo restart. No modo restart, se um erro de verificação for encontrado, o dispositivo será reiniciado imediatamente com uma flag específica definida para indicar o motivo. O carregador de inicialização vai notar essa flag e mudar o dm-verity para usar o modo de erro de E/S (eio), permanecendo assim até que uma nova atualização seja instalada.

Ao inicializar no modo eio, o dispositivo mostra uma tela de erro informando ao usuário que foi detectada uma corrupção e que o dispositivo pode não funcionar corretamente. A tela aparece até que o usuário a dispense. No modo eio, o driver dm-verity não reinicia o dispositivo se um erro de verificação for encontrado. Em vez disso, um erro EIO é retornado, e o app precisa lidar com ele.

O objetivo é que o atualizador do sistema seja executado (para que um novo SO sem erros de corrupção possa ser instalado) ou que o usuário possa transferir o máximo de dados do dispositivo possível. Depois que o novo SO for instalado, o carregador de inicialização vai notar o SO recém-instalado e voltar para o modo restart.