Verificação de inicialização

O inicialização verificada exige a verificação criptográfica de todos os dados e códigos executáveis 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.

Pequenas partições, 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. 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 hashes em que a verificação é um processo contínuo que ocorre à medida que os dados são carregados na memória. Nesse caso, o hash raiz da árvore de hashes é calculado durante a execução e verificado em relação ao valor de hash raiz esperado. O Android inclui o driver dm-verity para verificar partições maiores. Se em algum momento o hash raiz calculado não corresponder ao valor de hash raiz esperado, os dados não serão usados e o Android entrará em um estado de erro. Para mais detalhes, consulte Corrupção dm-verity.

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

Proteção de reversão

Mesmo com um processo de atualização totalmente seguro, é possível que uma exploração de kernel do Android não persistente instale manualmente uma versão mais antiga e mais vulnerável do Android, reinicie na versão vulnerável e use essa versão do Android para instalar uma exploração persistente. A partir daí, o invasor tem o dispositivo permanentemente e pode fazer qualquer coisa, incluindo desativar atualizações.

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

Para mais detalhes sobre como o AVB processa as proteções de reversão, consulte o README (link em inglês) do AVB.

Processar erros de verificação

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

Se a verificação falhar no momento da 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 precisa notar essa flag e mudar o dm-verity para usar o modo de erro de E/S (eio) e permanecer nesse modo 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 a corrupção foi detectada 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 o erro.

A intenção é 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 consiga transferir o máximo possível de dados do dispositivo. Depois que o novo SO é instalado, o carregador de inicialização percebe o SO recém-instalado e volta para o modo restart.