PaX est un correctif (patch) de sécurité pour le noyau Linux créé en par un collectif nommé PaX Team (en français, L'Équipe PaX), aujourd'hui composé d'un seul développeur utilisant le pseudonyme pipacs.
Le modèle de menace de PaX est un attaquant, local ou distant, possédant une primitive de lecture/écriture arbitraire de la mémoire du noyau ou de l'espace utilisateur. Ce qui se traduit par 3 familles d'attaques:
celles qui introduisent et exécutent un code arbitraire, fréquemment via un shellcode; celles qui essaient d'exécuter du code déjà existant, mais dans un contexte autre que celui prévu par le programmeur, à l'aide de constructions telle que return-to-libc attack; celles qui essaient d'exécuter du code avec des données arbitraires.
Pour défendre contre ce modèle, PaX inventa un grand nombre de mécanisme de sécurité qui ont été largement adopté au sein de l'industrie: la protection de l'espace exécutable via l'implémentation de W^X (ayant mené à son implantation matérielle via le bit NX), l'ASLR, l'intégrité de flux de contrôle (CFI), … La plupart de ces mécanismes n'ont pas pour but de détecter toutes les vulnérabilités, mais de les rendre inexploitables.
Étant basé sur le noyau Linux, PaX peut être utilisé sur toutes les architectures qu'il supporte.
Le , une vulnérabilité dans l'implémentation du est publiée, accompagnée d'exploits PaX VMA Mirroring Privilege Escalation Vulnerability, 5 mars 2005, SecurityFocus. À la suite de cet évènement, en , PaX Team annonce la fin du développement de PaX, ce qui n'aura finalement pas lieu: faute de candidat à la reprise du développement, l'équipe originale a continué.
Les techniques utilisées par PaX
Protection de zones mémoires contenant du code exécutable La protection de zones mémoires contenant du code exécutable vise à interdire à un attaquant d'introduire du code arbitraire. La technique principale pour ce faire est de ne jamais avoir de code à la fois accessible en écriture et en exécution, en utilisant (ou émulant) la fonctionnalité du NX Bit.
PaX_PAGEEXEC
Basée sur une idée du projet freemware/plex86, PAGEEXEC est la première implémentation proposée pour implémenter le bit NX sur les architectures i386 en . L'implémentation repose sur le translation lookaside buffer (TLB), le cache utilisé par l'unité de gestion mémoire. Lors d'une tentative d'accès à une page protégée qui n'est pas encore dans le TLB, en exécution, une faute de protection est levée. Comme sur les processeurs récents le TLB est séparé en un cache pour les exécutions (ITLB) et un cache pour les données (DTLB), PaX peut déterminer s'il s'agit d'une instruction, qui doit alors être interdite.
PaX_SEGMEXEC Créé en , SEGMEXEC émule le fonctionnement du bit NX sur les processeurs IA-32. Cela fonctionne en segmentant la mémoire en deux zones de 1.5 Go chacune. La zone basse (de 0 à 1.5 Go) contient les données non exécutables, c'est-à-dire les données mais aussi instructions (qui peuvent en effet vouloir être lues). La seconde zone, exécutable, en revanche ne contient que les instructions. Les mappings des deux segments pointent vers les mêmes zones de la mémoire physique, ainsi la mémoire vive utilisée n'est pas doublée.
Lorsqu'une adresse mémoire doit être exécutée, elle est traduite dans la zone contenant le code exécutable. Si le code n'est pas présent à l'adresse traduite, il s'agit alors d'une tentative d'exécution de code interdite, le programme est alors tué.
PaX_MPROTECT Introduite en , le but de PAX_MPROTECT est d'interdire l'introduction de nouveau code exécutable dans des processus, en ajoutant des restrictions sur les fonctions mmap et mprotect, interdisant:
L'allocation mémoire accessible en lecture et écriture; la projection mémoire via mmap en lecture et écriture; l'ajout de permission d'accès en exécution sur une projection mémoire, excepté pour effectuer des relocations sur un fichier marqué comme ET_DYN ELF l'ajout de permission d'accès en exécution sur une allocation mémoire. Microsoft adopta cette mitigation en 2017 à partir de Windows 10, sous le nom d'Arbitrary Code Guard
PaX_KERNEXEC Ajouté à PaX in , il s'agit plus ou moins d'une implémentation de PAGEEXEC pour l'espace noyau, basé sur les mêmes mécanismes que SEGMEXEC et PAX_MPROTECT:
Un marquage d'autant d'éléments que possible en lecture seule: table d'appels systeme, segment .rodata, IDT, GDT, … L'interdiction d'exécuter du code en espace utilisateur depuis l'espace noyau, en forçant le bit de poids significatif à 1 dans tous les pointeurs sur fonction en espace noyau ainsi que sur les adresses de retour, rendant les adresses de l'espace utilisateur non-canoniques.
Les trampolines implémentés par GCC sous la forme de petites portions de code généralement générés sur la pile lors du runtime « Trampolines for Nested Functions » dans la documentation de GCC. Cela nécessite donc de rendre exécutable la pile, ce qu'empêche PaX. Pour éviter que les programmes utilisant cette technique ne soient tués, PaX est capable d'identifier et d'autoriser leur utilisation.
Inventé en par pipacs comme une mesure de sécurité temporaire, l'address space layout randomization consiste à rendre certaines adresses de la mémoire virtuelle aléatoires permettant de se prémunir contre l'exploitation de certaines failles (généralement de type dépassement de tampon). Les parties de programmes qui seront placées à des adresses aléatoires sont en général la pile, le tas, la position des bibliothèques, … Cette technique est maintenant utilisée par tous les systèmes d'exploitation modernes: Microsoft l'ajouta à Windows XP SP3 en 2007, Apple à macOS en 2007 également, Linux l'obtiendra en 2005, …
PaX_RANDKSTACK Ce plugin rend aléatoire la pile d'appel des processus noyau a chaque appel système, forçant un attaquant à deviner son adresse, mais empêchent également la fuite d'informations par ce biais. Ce plugin fut écrit en réaction à la publication de l'attaque Stackjacking by Jon Oberheide et Dan Rosenberg. Ce plugin fut intégré au noyau linux en 2019 par Elena Reshetova.
PaX_RANDUSTACK Afin de complexifier les attaques par dépassement de tampon sur la pile d'appel, PaX rend aléatoire son adresse.
PaX_RANDMMAP Introduit en 2003, PAX_RANDMMAP rend aléatoire l'adresse de base utilisée par mmap(). ayant pour effet, entre autres, de rendre aléatoire les adresses auxquelles sont chargées les bibliothèques externes.
Ségrégation de l'espace noyau et de l'espace utilisateur
PaX_MEMORY_UDEREF PAX_MEMORY_UDEREF interdit au noyau d'accéder en lecture/écriture à l'espace utilisateur. Elle utilise différentes implémentations suivant les architectures:
Sur i386, la segmentation est utilisée, excluant complètement l'espace utilisateur du segment data. Sur SPARC64, UDEREF est fournie de manière native par le processeur. Sur x86_64 Utilisation d'une projection de l'espace utilisateur non-exécutable lors de l'exécution de code en espace noyau, via le PGD (page global directory). SMAP sur les processeurs possédant cette fonctionnalité. Sur ARMv6+ Une technique similaire à celle utilisée sur x86_64 sans support de SMAP. PXN sur les processeurs possédant cette fonctionnalité.
PaX_USERCOPY PAX_USERCOPY ajoute des vérifications sur la taille des objets sur le tas copiés, y compris partiellement, vers/depuis l'espace utilisateur vers/depuis l'espace noyau. L'idée principale étant que comme les allocations mémoire sont ségrégées par taille, il est possible de retrouver la taille d'une allocation à partir de son adresse mémoire.
Elle introduit également une liste-blanche de zones mémoire pouvant être copié vers/depuis l'espace utilisateur, interdisant par exemple les structures contenant les privilèges utilisateur ou les détails des tâches en cours d'être copiées.
Cette fonctionnalité fut intégrée dans le noyau Linux par Kees Cook en 2016 sous le nom de CONFIG_HARDENED_USERCOPY.
Prévention de fuites de données PaX_MEMORY_SANITIZE Cette fonctionnalité efface immédiatement les zones mémoires lorsqu'elles sont rendues au noyau, réduisant ainsi la durée pendant laquelle des informations sensibles comme des mots de passes ou des clefs de chiffrement. Cette approche a deux effets de bord bénéfique
Les fuites dues au padding lié à l'alignement mémoire de certaines structures sont réduites; Certaines attaques de type user-after-free utilisant des pointeurs au sein de structures peuvent être détectée: le déréférencement d'un pointeur effacé provoquant un crash.
Cette approche a cependant un coût en performance non-négligeable, aux alentours de 3%. Un sous-ensemble de cette approche, nommé INIT_ON_FREE_DEFAULT_ON, a été accepté dans le noyau linux en 2019, avec un impact sur les performances aux alentours de 7%.
Plugins gcc PaX_SIZE_OVERFLOW Originellement écrit par Emese "ephox" Révfy, size_overflow vise a détecter les dépassements d'entiers automatiquement. L'idée principale est basée sur l'usage du type intoverflow_t d'anciennes versions de PaX: un entier de taille 64 sur les architectures 32 bits, et 128 bits sur celles a 64 bits, permettant de valider, manuellement, dans certains fonctions critiques que les entiers ne dépassent pas. Le plugin se contente d'effectuer les mêmes vérifications, mais de manière entièrement automatique. Ce plugin a permis, et permet encore, de trouver un grand nombre de failles de sécurité, comme CVE-2013-0914, CVE-2013-0913, CVE-2013-2141, …
PaX_LATENT_ENTROPY Introduit en 2012 et inspiré par le papier "Mining Your Ps and Qs: Detection of Widespread Weak Keys in Network Devices", ce plugin extrait de l'entropie en instrumentant le processus de démarrage du noyau, rendant la génération de matériel cryptographique plus robuste, en particulier dans l'informatique embarquée. Cette approche est similaire à celle utilisée par Larry H. dans sa modification KERNHEAP pour le noyau linux en 2009.
PaX_REFCOUNT PAX_REFCOUNT fut créé en 2008. L'idée est d'utiliser un type spécial pour les compteurs de références, pour lequel il est impossible d'obtenir un dépassement d'entier: au lieu de résulter en un dépassement, le type sature à sa valeur maximale, résultant en une possible fuite mémoire, au lieu d'un dangling pointer. Cette fonctionnalité fut proposée à l'adoption dans le noyau Linux en 2012 par David Windsor, puis en 2016 par Elena Reshetova, mais c'est la version de Peter Zijlstra qui fut finalement acceptée en 2017 pour des raisons de performance.
PaX_MEMORY_STACKLEAK Créé en en réponse à la publication de l'attaque "Stackjacking" par Jon Oberheide et Dan Rosenberg contournant les mechanisms de sécurité, PAX_MEMORY_STACKLEAK efface systématiquement la pile de l'espace noyau avant la fin de chaque appel système, réduisant les informations pouvant être obtenues via une fuite mémoire de la pile. Il convient de noter que les informations poussées sur la pile par l'appel système à l'origine de la fuite mémoire de la pile sont évidemment accessibles, seules celles de appels système précédents ne le sont plus. L'impact en performance se situe aux alentours de 1%. Cette fonctionnalité fut intégrée au noyau Linux en 2018 par Alexander Popov.
PaX_MEMORY_STRUCTLEAK PAX_MEMORY_STRUCTLEAK initialise à zéro certains variables locales en espace noyau pouvant être passées en espace utilisateur, empêchant des fuites de mémoire de l'espace noyau si ces variables ne sont pas complètement initialisées dans le code. Il s'agit d'une approche similaire à PAX_MEMORY_STACKLEAK, fournissant une couverture bien moindre, mais avec des performances bien plus élevées.
PaX_CONSTIFY_PLUGIN PAX_CONSTIFY_PLUGIN rend constants les types contenant uniquement des pointeurs sur fonctions, réduisant ainsi la surface d'attaque du noyau tout en augmentant marginalement ses performances.
PaX_RAP