
Alocador reforçado projetado para sistemas modernos. Possui integração com a Bionic libc do Android e pode ser usado externamente com musl e glibc como uma biblioteca dinâmica para uso em outras plataformas baseadas em Linux. Ganhará mais portabilidade/integração com o tempo.
Este é um alocador de memória de uso geral focado em segurança que fornece a API malloc juntamente com várias extensões. Ele oferece um endurecimento substancial contra vulnerabilidades de corrupção de heap. O design focado em segurança também resulta em muito menos sobrecarga de metadados e desperdício de memória por fragmentação do que um design de alocador mais tradicional. Ele visa proporcionar um desempenho geral decente, com foco no desempenho e uso de memória a longo prazo, em vez de micro-benchmarks do alocador. Oferece escalabilidade por meio de um número configurável de arenas totalmente independentes, com o bloqueio interno dentro das arenas ainda mais dividido por classe de tamanho.
Este projeto atualmente suporta Bionic (Android), musl e glibc. Pode vir a suportar outros sistemas operacionais não-Linux no futuro. Para Android, há integração personalizada e outros recursos de endurecimento que também estão planejados para musl no futuro. O suporte a glibc será limitado à substituição da implementação de malloc, porque musl é uma base muito mais robusta e limpa para se construir e pode cobrir os mesmos casos de uso.
Este alocador destina-se a ser o sucessor de uma implementação anterior baseada em estender o OpenBSD malloc com vários recursos de segurança adicionais. Ele ainda é fortemente baseado no design do OpenBSD malloc, embora não no código existente, exceto pela reutilização da implementação da tabela hash. As principais diferenças no design são que ele é focado exclusivamente no endurecimento em vez de encontrar bugs, usa classes de tamanho mais refinadas juntamente com tamanhos de slab que ultrapassam 4k para reduzir a fragmentação interna, não depende de o kernel ter randomização de mmap refinada e tem como alvo apenas 64 bits para fazer uso agressivo do grande espaço de endereçamento. Há muitas diferenças menores na abordagem de implementação. Ele incorpora as extensões anteriores feitas ao OpenBSD malloc, incluindo a adição de padding às alocações para canários (distintos dos canários atuais do OpenBSD malloc), detecção de write-after-free vinculada à limpeza existente na liberação, filas juntamente com os arrays randomizados existentes para colocar alocações em quarentena e detecção adequada de double-free para alocações em quarentena. As regiões de memória por classe de tamanho com suas próprias bases aleatórias foram vagamente inspiradas no particionamento baseado em tamanho e tipo do PartitionAlloc. As mudanças planejadas no OpenBSD malloc acabaram sendo demasiado extensas e invasivas, então este projeto foi iniciado como uma implementação nova, mais capaz de atingir os objetivos. Para 32 bits, um port do OpenBSD malloc com pequenas extensões pode ser usado em vez disso, já que este alocador fundamentalmente não suporta esse ambiente.
O Debian stable (atualmente Debian 13) determina o conjunto mais antigo de dependências suportadas:
Para Android, os branches Linux GKI 6.1, 6.6 e 6.12 são suportados.
No entanto, é altamente recomendável usar versões mais recentes. Versões mais antigas das dependências podem ser compatíveis no momento, mas não são testadas e explicitamente não serão suportadas.
Para substituição externa de malloc com musl, é necessário musl 1.1.20. No entanto, haverá integração personalizada oferecendo melhor desempenho no futuro, juntamente com outros endurecimentos para a implementação da biblioteca padrão C.
Para Android, apenas a geração atual, ramo de manutenção ativamente desenvolvido do Android
Open Source Project será suportado, o que atualmente significa android17-release.
O script preload.sh pode ser usado para testes com executáveis
dinamicamente vinculados usando glibc ou musl:
./preload.sh krita --new-image RGBA,U8,500,500
Pode ser necessário aumentar substancialmente o sysctl vm.max_map_count para
acomodar o grande número de mapeamentos causados por guard slabs e grandes
regiões de guarda de alocação. O número de mapeamentos também pode ser drasticamente
reduzido através de um aumento significativo em CONFIG_GUARD_SLABS_INTERVAL, mas o
recurso tem um baixo custo de desempenho e uso de memória, portanto não é recomendado.
Pode oferecer um desempenho ligeiramente melhor quando integrado na biblioteca padrão C e existem outras oportunidades para endurecimento semelhante dentro das implementações da biblioteca padrão C e do vinculador dinâmico. Por exemplo, uma região de biblioteca pode ser implementada para oferecer isolamento semelhante para bibliotecas dinâmicas como este alocador oferece entre diferentes classes de tamanho. A intenção é que isto seja oferecido como parte de variantes endurecidas das bibliotecas padrão C Bionic e musl.
Uma coleção de testes simples e automatizados é fornecida e pode ser executada com o comando make da seguinte forma:
make test
É necessário OpenSSH 8.1 ou superior para permitir as chamadas de sistema mprotect PROT_READ|PROT_WRITE
no filtro seccomp-bpf em vez de matar o processo.
No GrapheneOS, o hardened_malloc está integrado na biblioteca padrão C como a implementação padrão de malloc. Outros sistemas operacionais baseados em Android podem reutilizar o código de integração para fornecê-lo. Se desejado, o jemalloc pode ser deixado como uma opção de configuração em tempo de execução, usando condicionalmente o hardened_malloc para dar aos usuários a escolha entre desempenho e segurança. No entanto, isto reduz a segurança para modelos de ameaça onde o estado persistente não é confiável, ou seja, boot verificado e atestação (consulte o projeto irmão de atestação).
Certifique-se de aumentar substancialmente vm.max_map_count também para acomodar o
grande número de guard pages criadas pelo hardened_malloc. Isto pode ser feito em
init.rc (system/core/rootdir/init.rc) perto da outra configuração de memória virtual:
write /proc/sys/vm/max_map_count 1048576
Isto é desnecessário se você definir CONFIG_GUARD_SLABS_INTERVAL para um valor muito grande
na configuração de compilação.