
Allocatore rafforzato progettato per i sistemi moderni. È integrato nella libc Bionic di Android e può essere utilizzato esternamente con musl e glibc come libreria dinamica per l'uso su altre piattaforme basate su Linux. Acquisirà maggiore portabilità/integrazione nel tempo.
Questo è un allocatore di memoria general-purpose orientato alla sicurezza che fornisce l'API malloc insieme a varie estensioni. Offre un sostanziale hardening contro le vulnerabilità di corruzione dell'heap. Il design orientato alla sicurezza comporta anche un overhead di metadati e uno spreco di memoria dovuto alla frammentazione molto inferiori rispetto a un design di allocatore più tradizionale. Mira a fornire prestazioni complessive decenti con un focus sulle prestazioni a lungo termine e sull'utilizzo della memoria piuttosto che sui micro-benchmark dell'allocatore. Offre scalabilità tramite un numero configurabile di arene completamente indipendenti, con il locking interno all'interno delle arene ulteriormente suddiviso per classe di dimensione.
Questo progetto attualmente supporta Bionic (Android), musl e glibc. Potrebbe supportare altri sistemi operativi non Linux in futuro. Per Android, esiste un'integrazione personalizzata e altre funzionalità di hardening che sono pianificate anche per musl in futuro. Il supporto per glibc sarà limitato alla sostituzione dell'implementazione di malloc perché musl è una base molto più robusta e pulita su cui costruire e può coprire gli stessi casi d'uso.
Questo allocatore è inteso come successore di una precedente implementazione basata sull'estensione di OpenBSD malloc con varie funzionalità di sicurezza aggiuntive. È ancora fortemente basato sul design di OpenBSD malloc, anche se non sul codice esistente, se non per il riutilizzo dell'implementazione della tabella hash. Le principali differenze nel design sono che è focalizzato esclusivamente sull'hardening piuttosto che sulla ricerca di bug, utilizza classi di dimensione più granulari insieme a dimensioni slab che superano i 4k per ridurre la frammentazione interna, non si basa sul fatto che il kernel disponga di una randomizzazione mmap a grana fine e prende di mira solo i 64 bit per fare un uso aggressivo del grande spazio di indirizzi. Ci sono molte differenze più piccole nell'approccio implementativo. Incorpora le precedenti estensioni apportate a OpenBSD malloc, tra cui l'aggiunta di padding alle allocazioni per i canary (distinti dai canary attuali di OpenBSD malloc), il rilevamento di write-after-free legato alla cancellazione esistente alla liberazione, code affiancate agli array randomizzati esistenti per la quarantena delle allocazioni e un'adeguata rilevazione del double-free per le allocazioni in quarantena. Le regioni di memoria per classe di dimensione con le proprie basi casuali sono state liberamente ispirate al partizionamento per dimensione e tipo in PartitionAlloc. Le modifiche pianificate a OpenBSD malloc si sono rivelate troppo estese e invasive, quindi questo progetto è stato avviato come un'implementazione da zero in grado di raggiungere meglio gli obiettivi. Per i 32 bit, è possibile utilizzare invece un port di OpenBSD malloc con piccole estensioni, poiché questo allocatore fondamentalmente non supporta tale ambiente.
Debian stable (attualmente Debian 13) determina l'insieme più antico di dipendenze supportate:
Per Android, sono supportati i rami Linux GKI 6.1, 6.6 e 6.12.
Tuttavia, è altamente raccomandato utilizzare versioni più recenti. Le versioni precedenti delle dipendenze potrebbero essere compatibili al momento ma non sono testate e non saranno esplicitamente supportate.
Per la sostituzione esterna di malloc con musl, è richiesto musl 1.1.20. Tuttavia, in futuro verrà offerta un'integrazione personalizzata con prestazioni migliori insieme ad altri rafforzamenti per l'implementazione della libreria standard C.
Per Android, sarà supportato solo il ramo di manutenzione della generazione corrente, attivamente sviluppato, dell'Android
Open Source Project, che attualmente significa android17-release.
Lo script preload.sh può essere utilizzato per testare con eseguibili
collegati dinamicamente che usano glibc o musl:
./preload.sh krita --new-image RGBA,U8,500,500
Può essere necessario aumentare sostanzialmente il sysctl vm.max_map_count per
far fronte al grande numero di mapping causati dalle guard slab e dalle vaste
regioni di guardia per le allocazioni. Il numero di mapping può anche essere drasticamente
ridotto tramite un aumento significativo di CONFIG_GUARD_SLABS_INTERVAL, ma la
funzionalità ha un basso costo in termini di prestazioni e utilizzo di memoria, quindi non è consigliato.
Può offrire prestazioni leggermente migliori se integrato nella libreria standard C e ci sono altre opportunità per un rafforzamento simile all'interno delle implementazioni della libreria standard C e del linker dinamico. Ad esempio, si può implementare una regione di libreria per offrire un isolamento simile per le librerie dinamiche come questo allocatore offre tra le diverse classi di dimensione. L'intenzione è che questo venga offerto come parte delle varianti rafforzate delle librerie standard C Bionic e musl.
Viene fornita una raccolta di test automatizzati semplici che possono essere eseguiti con il comando make come segue:
make test
È richiesto OpenSSH 8.1 o superiore per consentire le chiamate di sistema mprotect PROT_READ|PROT_WRITE
nel filtro seccomp-bpf anziché terminare il processo.
Su GrapheneOS, hardened_malloc è integrato nella libreria standard C come implementazione standard di malloc. Altri sistemi operativi basati su Android possono riutilizzare il codice di integrazione per fornirlo. Se lo si desidera, jemalloc può essere lasciato come opzione di configurazione a runtime utilizzando hardened_malloc solo in modo condizionale per dare agli utenti la scelta tra prestazioni e sicurezza. Tuttavia, questo riduce la sicurezza per modelli di minaccia in cui lo stato persistente non è attendibile, ovvero verified boot e attestation (vedi il progetto gemello attestation).
Assicurati di aumentare sostanzialmente anche vm.max_map_count per far fronte al
grandissimo numero di guard page create da hardened_malloc. Questo può essere fatto in
init.rc (system/core/rootdir/init.rc) vicino alle altre configurazioni della memoria virtuale:
write /proc/sys/vm/max_map_count 1048576
Questo non è necessario se imposti CONFIG_GUARD_SLABS_INTERVAL a un valore molto grande
nella configurazione di build.