Escudo

Scudo é um alocador de memória de modo de usuário dinâmico, ou alocador de heap , projetado para ser resiliente contra vulnerabilidades relacionadas a heap (como estouro de buffer baseado em heap , use after free e double free ) enquanto mantém o desempenho. Ele fornece as primitivas de alocação e desalocação de C padrão (como malloc e free), bem como as primitivas de C++ (como new e delete).

O Scudo é mais uma mitigação do que um detector de erros de memória completo, como AddressSanitizer (ASan) .

A partir da versão Android 11, o scudo é usado para todo o código nativo (exceto em dispositivos com pouca memória, onde o jemalloc ainda é usado). Em tempo de execução, todas as alocações e desalocações de heap nativas são atendidas pelo Scudo para todos os executáveis ​​e suas dependências de biblioteca, e o processo é abortado se uma corrupção ou comportamento suspeito for detectado no heap.

No Android 10, o scudo precisava ser ativado por binário, definindo a opção LOCAL_SANITIZE := scudo no arquivo .mk ou a sanitize: { scudo: true, } no arquivo .bp.

Scudo é de código aberto e parte do projeto compiler-rt do LLVM. A documentação está disponível em https://llvm.org/docs/ScudoHardenedAllocator.html . O runtime do Scudo é fornecido como parte da cadeia de ferramentas do Android e o suporte foi adicionado ao Soong e ao Make para permitir a fácil ativação do alocador em um binário.

Você pode habilitar ou desabilitar a mitigação extra no alocador usando as opções descritas abaixo.

Costumização

Alguns parâmetros do alocador podem ser definidos por processo de várias maneiras:

  • Estaticamente : Defina uma função __scudo_default_options no programa que retorna a string de opções a ser analisada. Esta função deve ter o seguinte protótipo: extern "C" const char *__scudo_default_options() .
  • Dinamicamente: Use a variável de ambiente SCUDO_OPTIONS contendo a string de opções a ser analisada. As opções definidas dessa maneira substituem qualquer definição feita por meio de __scudo_default_options .

As seguintes opções estão disponíveis.

Opção padrão de 64 bits padrão de 32 bits Descrição
QuarantineSizeKb 256 64 O tamanho (em KB) da quarentena usado para atrasar a desalocação real dos blocos. Um valor mais baixo pode reduzir o uso de memória, mas diminuir a eficácia da mitigação; um valor negativo retorna aos padrões. Definir este e ThreadLocalQuarantineSizeKb como zero desabilita totalmente a quarentena.
QuarantineChunksUpToSize 2048 512 O tamanho (em bytes) até o qual os fragmentos podem ser colocados em quarentena.
ThreadLocalQuarantineSizeKb 64 16 O tamanho (em KB) do cache por thread usado para descarregar a quarentena global. Um valor mais baixo pode reduzir o uso de memória, mas pode aumentar a contenção na quarentena global. Definir este e QuarantineSizeKb como zero desabilita totalmente a quarentena.
DeallocationTypeMismatch false false Habilita o relatório de erros em malloc/delete, new/free, new/delete[]
DeleteSizeMismatch true true Ativa o relatório de erros sobre incompatibilidade entre os tamanhos de novo e de exclusão.
ZeroContents false false Habilita o conteúdo de bloco zero na alocação e desalocação.
allocator_may_return_null false false Especifica que o alocador pode retornar nulo quando ocorrer um erro recuperável, em vez de encerrar o processo.
hard_rss_limit_mb 0 0 Quando o RSS do processo atinge esse limite, o processo é encerrado.
soft_rss_limit_mb 0 0 Quando o RSS do processo atinge esse limite, outras alocações falham ou retornam null (dependendo do valor de allocator_may_return_null ), até que o RSS volte para baixo para permitir novas alocações.
allocator_release_to_os_interval_ms N / D 5000 Afeta apenas um alocador de 64 bits. Se definido, tenta liberar memória não utilizada para o sistema operacional, mas não com mais frequência do que esse intervalo (em milissegundos). Se o valor for negativo, a memória não será liberada para o SO.
abort_on_error true true Se definido, a ferramenta chama abort() em vez de _exit() após imprimir a mensagem de erro.

Validação

Atualmente, não há testes CTS especificamente para Scudo. Em vez disso, certifique-se de que os testes CTS sejam aprovados com ou sem o Scudo habilitado para um determinado binário para verificar se ele não afeta o dispositivo.

Solução de problemas

Se for detectado um problema irrecuperável, o alocador exibe uma mensagem de erro para o descritor de erro padrão e encerra o processo. Os rastreamentos de pilha que levam ao término são adicionados ao log do sistema. A saída geralmente começa com Scudo ERROR: seguido por um breve resumo do problema junto com quaisquer ponteiros.

Aqui está uma lista das mensagens de erro atuais e suas possíveis causas:

  • corrupted chunk header : a verificação da soma de verificação do cabeçalho do bloco falhou. Isso provavelmente se deve a uma de duas coisas: o cabeçalho foi substituído (parcial ou totalmente) ou o ponteiro passado para a função não é um pedaço.
  • race on chunk header : Dois threads diferentes estão tentando manipular o mesmo cabeçalho ao mesmo tempo. Isso geralmente é sintomático de uma condição de corrida ou falta geral de bloqueio ao executar operações nesse bloco.
  • invalid chunk state : o bloco não está no estado esperado para uma determinada operação, por exemplo, não é alocado ao tentar liberá-lo ou não está em quarentena ao tentar reciclá-lo. Um double free é o motivo típico para esse erro.
  • misaligned pointer : Os requisitos básicos de alinhamento são fortemente aplicados: 8 bytes em plataformas de 32 bits e 16 bytes em plataformas de 64 bits. Se um ponteiro passado para nossas funções não se encaixar nelas, o ponteiro passado para uma das funções está desalinhado.
  • allocation type mismatch : Quando esta opção está habilitada, uma função de desalocação chamada em um pedaço deve corresponder ao tipo de função que foi chamada para alocá-la. Esse tipo de incompatibilidade pode apresentar problemas de segurança.
  • invalid sized delete : quando o operador de exclusão de tamanho C++ 14 é usado e a verificação opcional está habilitada, há uma incompatibilidade entre o tamanho que foi passado ao desalocar um pedaço e o tamanho que foi solicitado ao alocá-lo. Isso geralmente é um problema do compilador ou uma confusão de tipos no objeto que está sendo desalocado.
  • RSS limit exhausted : O RSS máximo opcionalmente especificado foi excedido.

Se você estiver depurando uma falha no próprio sistema operacional, poderá usar uma compilação do sistema operacional HWASan . Se você estiver depurando uma falha em um aplicativo, também é possível usar uma compilação de aplicativo HWASan .