# PaX

PaX est un correctif (patch) de sécurité pour le noyau Linux créé en octobre 2000 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 4 mars 2005 , une vulnérabilité dans l'implémentation du VMA Mirroring est publiée, accompagnée d'exploits$^,$. À la suite de cet évènement, en avril 2005, 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 octobre 2000$^,$$^,$. 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 octobre 2002, 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 novembre 2000, 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ée 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 avril 2003, 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.

#### Trampoline emulation

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. 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.

### Address space layout randomization

Inventé en juin 2001 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 avril 2011 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

PAX_RAP est une implémentation de CFI, interdisant les changements arbitraires du flux d'exécution en espace noyau, que ce soit via l'écrasement de pointeurs sur fonctions, ou d'adresses de retour sur la pile. Il opère sous un modèle de menace extrêmement large: une primitive de lecture/écriture de contenu arbitraire, sur des adresses arbitraires, un nombre arbitraire de fois, à des instants arbitraires, utilisée pour élever ou abuser de privilèges, avec un budget sur les performances aux alentours de 5%.
Annoncée en 2003, RAP fut publié 12 ans plus tard, en 2015, et consiste en deux parties principales.

##### Canari

L'utilisation d'un canari dont la valeur est stockée dans un register (r12 sur x86_64), nécessitant donc deux lectures pour le fuiter: une lecture de la valeur chiffrée, et une adresse mémoire. En espace noyau, il est unique par processus et change à chaque appel système. Les piles des autres processus sont rendues illisibles pour empêcher l'accès à leur canaris.

##### Graphe de flux de contrôle auto-assemblé basé sur les types

L'idée étant d'utiliser les types de fonctions pour générer les signatures. Par exemple un pointeur sur la fonction ssize_t read(int fd, void buf, size_t count) ne pourra appeler que des fonctions ayant la même signature. Certaines fonctions critiques sont augmentées de types artificiels afin de réduire au maximum les pointeurs pouvant y mener. Afin d'augmenter la ségrégation, les signatures sont découpées en plusieurs groupes:
* Les signatures positives sont utilisées uniquement pour les fonctions et les pointeurs sur fonction.
* Les signatures négatives pour les adresses de retour et les retours de fonctions
* Une signature spécifique est utilisée pour les fonctions qui ne sont jamais appelées par un pointeur,.
* Une signature spécifique est assignée pour les exceptions de type setjmp/longjmp.
Voici à quoi ressemble une vérification du type de retour d'un appel à une fonction:
Voici à quoi ressemble une vérification du type d'un appel à une fonction:

##### Influences

L'idée d'utiliser les types des fonctions fut reprise par Microsoft dans son implémentation de CFI nommé XFG en 2021, ainsi que par Intel avec IBT.