
Allocateur renforcé conçu pour les systèmes modernes. Il est intégré à la libc Bionic d'Android et peut être utilisé en externe avec musl et glibc en tant que bibliothèque dynamique sur d'autres plateformes basées sur Linux. Sa portabilité et son intégration s'amélioreront avec le temps.
Il s'agit d'un allocateur mémoire à usage général axé sur la sécurité, fournissant l'API malloc ainsi que diverses extensions. Il offre un durcissement substantiel contre les vulnérabilités de corruption du tas. La conception axée sur la sécurité conduit également à beaucoup moins de surcharge de métadonnées et de gaspillage de mémoire dû à la fragmentation qu'une conception d'allocateur plus traditionnelle. Il vise à offrir des performances globales correctes, en mettant l'accent sur les performances à long terme et l'utilisation de la mémoire plutôt que sur les micro-benchmarks de l'allocateur. Il offre une scalabilité via un nombre configurable d'arènes entièrement indépendantes, le verrouillage interne au sein des arènes étant en outre réparti par classe de taille.
Ce projet prend actuellement en charge Bionic (Android), musl et glibc. Il pourrait prendre en charge d'autres systèmes d'exploitation non-Linux à l'avenir. Pour Android, il existe une intégration personnalisée et d'autres fonctionnalités de durcissement qui sont également prévues pour musl à l'avenir. La prise en charge de glibc sera limitée au remplacement de l'implémentation de malloc, car musl est une base beaucoup plus robuste et plus propre sur laquelle s'appuyer et peut couvrir les mêmes cas d'usage.
Cet allocateur est conçu comme le successeur d'une implémentation précédente basée sur l'extension d'OpenBSD malloc avec diverses fonctionnalités de sécurité supplémentaires. Il reste largement basé sur la conception d'OpenBSD malloc, bien que pas sur le code existant, hormis la réutilisation de l'implémentation de la table de hachage. Les principales différences de conception sont qu'il est uniquement axé sur le durcissement plutôt que sur la recherche de bugs, qu'il utilise des classes de taille plus fines ainsi que des tailles de slab dépassant 4k pour réduire la fragmentation interne, qu'il ne dépend pas d'une randomisation mmap fine du noyau et qu'il ne cible que le 64 bits afin d'exploiter agressivement le large espace d'adressage. Il existe de nombreuses différences plus petites dans l'approche d'implémentation. Il intègre les extensions précédemment apportées à OpenBSD malloc, notamment l'ajout de remplissage aux allocations pour les canaries (distincts des canaries actuels d'OpenBSD malloc), la détection d'écriture après libération liée à l'effacement existant lors de la libération, des files d'attente en complément des tableaux randomisés existants pour la mise en quarantaine des allocations, et une détection appropriée des doubles libérations pour les allocations en quarantaine. Les régions mémoire par classe de taille avec leurs propres bases aléatoires ont été librement inspirées du partitionnement par taille et par type de PartitionAlloc. Les changements prévus pour OpenBSD malloc se sont finalement révélés trop étendus et invasifs, c'est pourquoi ce projet a été lancé comme une implémentation nouvelle, mieux à même d'atteindre les objectifs. Pour le 32 bits, un portage d'OpenBSD malloc avec de petites extensions peut être utilisé à la place, car cet allocateur ne prend fondamentalement pas en charge cet environnement.
Debian stable (actuellement Debian 13) détermine l'ensemble le plus ancien de dépendances prises en charge :
Pour Android, les branches Linux GKI 6.1, 6.6 et 6.12 sont prises en charge.
Cependant, l'utilisation de versions plus récentes est fortement recommandée. Les versions plus anciennes des dépendances peuvent être compatibles pour le moment, mais ne sont pas testées et ne seront explicitement pas prises en charge.
Pour un remplacement externe de malloc avec musl, musl 1.1.20 est requis. Cependant, une intégration personnalisée offrant de meilleures performances sera proposée à l'avenir, accompagnée d'autres renforcements pour l'implémentation de la bibliothèque standard C.
Pour Android, seule la génération actuelle, branche de maintenance activement développée du projet
Android Open Source Project sera prise en charge, ce qui signifie actuellement android17-release.
Le script preload.sh peut être utilisé pour tester des exécutables liés dynamiquement
utilisant glibc ou musl :
./preload.sh krita --new-image RGBA,U8,500,500
Il peut être nécessaire d'augmenter sensiblement le sysctl vm.max_map_count pour
supporter le grand nombre de mappings causés par les guard slabs et les grandes
régions de garde d'allocation. Le nombre de mappings peut également être considérablement
réduit via une augmentation significative de CONFIG_GUARD_SLABS_INTERVAL, mais cette
fonctionnalité a un faible coût en performances et en utilisation mémoire, ce qui n'est donc pas recommandé.
Elle peut offrir des performances légèrement meilleures lorsqu'elle est intégrée dans la bibliothèque standard C, et d'autres opportunités de renforcement similaire existent au sein des implémentations de la bibliothèque standard C et de l'éditeur de liens dynamique. Par exemple, une région de bibliothèque peut être implémentée pour offrir une isolation similaire aux bibliothèques dynamiques, comme cet allocateur en offre entre différentes classes de tailles. L'intention est que cela soit proposé dans le cadre de variantes renforcées des bibliothèques standard C Bionic et musl.
Une collection de tests automatisés simples est fournie et peut être exécutée avec la commande make comme suit :
make test
OpenSSH 8.1 ou supérieur est requis pour autoriser les appels système mprotect PROT_READ|PROT_WRITE
dans le filtre seccomp-bpf plutôt que de tuer le processus.
Sur GrapheneOS, hardened_malloc est intégré dans la bibliothèque standard C comme implémentation standard de malloc. D'autres systèmes d'exploitation basés sur Android peuvent réutiliser le code d'intégration pour le fournir. Si souhaité, jemalloc peut être conservé comme option de configuration à l'exécution en n'utilisant hardened_malloc que de manière conditionnelle, afin de laisser aux utilisateurs le choix entre performances et sécurité. Cependant, cela réduit la sécurité pour les modèles de menace où l'état persistant n'est pas fiable, c'est-à-dire le démarrage vérifié et l'attestation (voir le projet frère d'attestation).
Assurez-vous également d'augmenter sensiblement vm.max_map_count pour supporter le très
grand nombre de pages de garde créées par hardened_malloc. Cela peut être fait dans
init.rc (system/core/rootdir/init.rc) près des autres configurations de mémoire virtuelle :
write /proc/sys/vm/max_map_count 1048576