Exploitation de la microarchitecture par le logiciel

Caractéristiques des jeux d’instructions

Le jeu d’instructions ou ISA influe directement sur l’implémentation du processeur. Selon les opérations définies, ce dernier devra être conçu pour les implémenter. Ainsi, il existe plusieurs types de jeu d’instructions, qui peuvent varier dans leur manière de représenter les données ou les instructions.
Représentation des données Une instruction spécifie également les données avec lesquelles ont lieu les opérations. Ces données, selon les architectures, peuvent prendre différentes formes. Voici quelques modèles :
– Le modèle à accumulateur possède un registre interne utilisé par défaut pour stocker le résultat des instructions. Des instructions de load et de store sont nécessaires pour respectivement recevoir ou envoyer des données en mémoire.
– Le modèle mémoire-mémoire n’effectue des opérations que sur des données en mémoire. Le résultat est ainsi directement stocké en mémoire. Plusieurs accès sont donc nécessaires pour chaque instruction.
– Le modèle registre-registre effectue des opérations uniquement sur des données contenues dans des registres. De même, le résultat est stocké dans un registre. Ce modèle nécessite lui aussi des instructions dédiées de load et de store pour accéder à la mémoire.
Les ISA utilisées actuellement suivent quasiment toute le modèle registre-registre. Les mémoires étant trop lentes, chaque accès ralentit le système. Le modèle registre-registre offre une flexibilité intéressante au programmeur qui dispose de plusieurs emplacements rapides d’accès pour stocker des données. Les accès mémoires pour récupérer des données ne sont pas systématiques. Pour la suite de ce manuscrit, sauf indication contraire, nous ne considèrerons donc que ce modèle là. Familles de jeu d’instructions Les différents jeux d’instructions peuvent également varier dans leur choix de représentation des opérations. En voici les trois principales familles :
1. Les ISA de type Reduced Instruction Set Computer (RISC) visent à associer des opérations simples à chaque instruction. Chacune ne nécessite donc que peu de cycles d’horloge pour être exécutée.
Un autre avantage est la simplicité d’implémentation : un nombre réduit d’opérations élémentaires est suffisant. Le logiciel est ensuite responsable de les combiner pour réaliser des opérations pluscomplexes.
2. Les ISA de type Complex Instruction Set Computer (CISC) visent à
associer des opérations complexes à chaque instruction. Contrairement au RISC, un plus grand nombre de cycles d’horloge est
nécessaire pour exécuter chaque instruction. De plus, l’implémentation est complexifiée : chaque instruction mène à plusieurs
sous-opérations au niveau du matériel. En revanche, ce jeu d’instructions est intéressant du point de vue logiciel de par la variété
d’opérations qu’il offre. Une seule instruction CISC peut-être l’équivalent de plusieurs instructions RISC. Cela impacte également la taille des programmes et des mémoires : moins d’instructions sont nécessaires pour des opérations complexes.
3. Les ISA de type Very Long Instruction Word (VLIW) visent à regrouper plusieurs sous-opérations dans des instructions très longues. L’objectif de ce genre d’architecture est de permettre au processeur de réaliser un grand nombre d’opérations en même temps. Pour cela, le compilateur joue un rôle essentiel : il s’assure que les différentes parties d’une même instruction utilisent des mécanismes différents du processeur. Cela permet d’éviter des conflits internes d’accès aux ressources lors de l’exécution.
Historiquement, les caractéristiques des processeurs RISC et CISC étaient opposées. Ce contraste est maintenant obsolète et se résume à un compromis entre coût de décodage (traduction de l’instruction en opérations matérielles) et coût mémoire (place pour stocker les instructions).
Architectures d’ISA existantes Plusieurs ISA ont été développées. Chacune d’entre elles a des caractéristiques qui lui sont propres. Par la suite, trois d’entre elles seront particulièrement évoquées :
1. L’ISA propriétaire x86 d’Intel. C’est un jeu d’instructions CISC que l’on retrouve dans les processeurs d’Intel et d’AMD, notamment à destination des serveurs ou ordinateurs personnels.
2. L’ISA proriétaire ARM d’Arm. C’est un jeu d’instructions RISC que l’on retrouve majoritairement dans les processeurs d’Arm principalement à destination des systèmes embarqués et téléphones.
3. L’ISA libre et ouverte RISC-V maintenue par la fondation du même nom. C’est la cinquième version d’ISA RISC développée par l’Université de Berkeley. Au départ développée pour des travaux de recherche, elle est ces dernières années au cœur de nombreux projets industriels.

Mémoires caches

Nous avons vu que la latence mémoire est un facteur limitant dans les performances des processeurs. Celui-ci est ainsi capable d’exécuter bien plus vite les instructions (une chaque cycle) que la mémoire n’est capable de lui en envoyer (plusieurs dizaines de cycles). Un mécanisme pour tenter de contrer ce problème est l’utilisation de mémoires caches.
Une mémoire cache est une mémoire plus rapide que la mémoire principale (généralement de la mémoire dynamique) : moins de cycles d’horloge sont nécessaires pour accéder à ses données. En contrepartie, les mémoires caches ont une contenance réduite. Augmenter la taille d’une mémoire cache augmente également sa complexité. Chaque donnée doit être accessible à tout moment : certains mécanismes matériels sont pour cela nécessaires. Un plus grand nombre de données implique donc plus d’opérations matérielles à réaliser et une latence accrue. Ainsi, ces mémoires sont généralement conçues pour contenir une quantité limitée de données, en plus du fait qu’elles nécessitent des technologies de fabrications onéreuses.
Le but des mémoires caches est de stocker localement une copie de certaines données ou instructions situées dans la mémoire principale.
Ces copies deviennent plus rapidement accessibles. Cependant, seule une petite partie de la mémoire principale peut être placée dans un cache.
Lors d’un accès du processeur à une donnée, on appelle un cache hit le fait que la donnée demandée se trouve dans le cache. Du point de vue du pipeline, cela revient à effectuer un accès mémoire accéléré : moins de cycles d’horloge sont nécessaires. À l’inverse, si la donnée demandée n’est pas dans le cache, on appelle cela un cache miss. Cela revient donc à effectuer un accès mémoire ralenti : plus de cycles d’horloge sont nécessaires pour aller accéder à la mémoire principale.
Finalement, le choix des données ou instructions placées dans un cache est essentiel. Il détermine directement quels accès effectués par le pipeline seront accélérés (hit) ou ralentis (miss). Pour maximiser l’efficacité, ce choix se base sur le principe de localité.

Spéculation

La spéculation est un principe utilisé pour accélérer l’exécution des instructions. L’idée générale est de prévoir les futurs évènements (redirection du flot d’exécution, accès mémoires, etc.) pour les anticiper et réduire leur impact sur les performances.

Pipeline et exécution dans le désordre

Le mécanisme le plus simple usant de spéculation dans un processeur est le pipeline lui-même. Le fait de récupérer en avance les prochaines instructions en mémoire avant d’avoir complètement exécuté les précédentes est une forme d’anticipation. Cependant, le fonctionnement basique d’un pipeline impose rapidement des limites à la spéculation.
Dépendances de données Il existe au sein des programmes des dépendances entre les instructions. Par exemple, l’opérande d’une instruction peut être le résultat d’une instruction précédente. Le Code 2.2 représentele cas classique d’un calcul de PGCD, un algorithme mathématique simpliste. On y retrouve alors plusieurs cas de dépendances (e.g. les lignes 3 et 5, 4 et 5, 18 et 20 etc.). Ces dépendances peuvent créer des bulles au sein du pipeline : il faut attendre que le résultat soit disponible avant de faire avancer la prochaine instruction. Ces mêmes bulles peuvent aussi être créées dans le cas où un accès mémoire est ralenti à cause d’un cache miss par exemple (e.g. si la ligne 3 est un miss, la ligne 4 devra attendre également). Des mécanismes de renvoi de registre (register forwarding) existent pour limiter l’impact des dépendances de données. Ils servent à rendre utilisable un résultat dès qu’il est calculé. À l’échelle d’un pipeline, un résultat est donc disponible en interne avant qu’il ne soit stocké dans un GPR par le dernier étage.
Les dépendances deviennent un facteur limitant d’autant plus important dans le cas de processeurs superscalaires. Ces derniers cherchent à augmenter le débit d’exécution en traitant plusieurs instructions à la fois dans chaque étage. Pour cela, la plupart des mécanismes sont dupliqués (e.g. plusieurs décodeurs et unités d’exécutions). Ainsi, en cas de bulle, le nombre d’instructions ralenties est d’autant plus important.
Or, le nombre d’instructions en cours d’exécution étant plus grand, le nombre de dépendances à gérer l’est également.
Réorganisation dynamique des instructions Un mécanisme utilisé dans les processeurs complexes pour diminuer les blocages dus aux dépendances est l’exécution dans le désordre. Son rôle est d’optimiser les cas où aucune dépendance n’est bloquante. L’objectif devient alors d’exécuter une instruction dès que toutes ses dépendances sont résolues.
Cela s’oppose donc au format linéaire d’un pipeline basique, où une instruction n’est forcément exécutée qu’après toutes les précédentes. Des mécanismes matériels sont alors responsables de préserver l’ordre du programme. Ils s’assurent que si les instructions sont exécutées dans un ordre différent de celui prévu par le logiciel, l’état architectural 20 2. Composants microarchitecturaux (celui visible par le logiciel) reste celui attendu. Même dans le cas d’un algorithme simple comme celui du Code 2.2, on retrouve plusieurs cas où cette optimisation peut être bénéfique. Par exemple, en cas de blocage de la ligne 10, les lignes 11 et 12 peuvent tout de même être exécutées.
Si les opérandes se situent généralement dans des registres, il existe également des opérations réalisant des accès mémoires. De la même manière, des dépendances se créent si des instructions accèdent à une même adresse. Il existe donc des processeurs qui étendent l’exécution dans le désordre à ces accès mémoire. Ils tentent alors de prédire les adresses utilisées ainsi que les valeurs lues/écrites.
Pour être implémentée au niveau matériel, l’exécution dans le désordre demande un grand nombre de ressources coûteuses. Des tables sont par exemple nécessaires pour mémoriser l’ordre original du programme, réaliser des sauvegardes temporaires des états en cas d’erreur etc. Ce mécanisme est donc généralement réservé aux processeurs avec d’importantes contraintes sur les performances. C’est par exemple le cas de la plupart des processeurs grand public (e.g. les processeurs Intel ou AMD) fabriqués depuis de nombreuses années.

Exploitation de la microarchitecture par le logiciel

Résumé du chapitre : Dans ce chapitre, nous nous intéressons aux attaques logicielles exploitant les mécanismes de la microarchitecture. De nombreux travaux ont montré que des programmes normalement isolés pouvaient interagir grâce au matériel : un principe microarchitectural comme le partage de ressources est notamment utilisé. Après quelques rappels sur des éléments et concepts nécessaires, nous étudions les différentes attaques exploitant la microarchitecture en quatre parties : les attaques par analyses des variations temporelles, les attaques par contention dynamique de ressources, les attaques par exécution transitoire et enfin les attaques par canaux contrôlés.

Objectifs de sécurité

Contexte Nous avons vu dans le chapitre précédent que les processeurs sont des composants électroniques essentiels. Ils sont responsables de l’exécution des calculs au sein de systèmes variés, que ce soit des ordinateurs, des serveurs, de téléphones ou d’autres systèmes embarqués. Selon les cas d’application, ils peuvent être utilisés pour le traitement de données sensibles et confidentielles. Ils doivent alors être capables d’assurer la protection de ces données.
Ce dernier aspect a longtemps été négligé au profit des performances. L’existence de potentielles failles exploitables est connue depuis de nombreuses années. L’ajout de nouveaux mécanismes, comme vu précédemment, n’a fait qu’accroître les faiblesses de ces systèmes. Cela mène aux processeurs modernes de ces dernières années, cibles d’attaques certes plus complexes, mais surtout plus puissantes.
Modèle d’attaquant Un modèle d’attaquant définit les capacités d’un attaquant. Il détermine la manière dont ce dernier peut influer sur le système et quelles actions il peut mener. De la même manière, ce modèle délimite les menaces que doivent considérer les solutions mises en place. Dans ce manuscrit, nous nous intéressons aux attaques logicielles exploitant la microarchitecture. Elles peuvent être définies comme des programmes qui, au cours de leur exécution, utilisent les différents mécanismes matériels à disposition à des fins malveillantes (e.g. retrouver des informations secrètes).
Dans notre cas, nous considérons donc un attaquant capable d’exécuter des programmes sur un processeur et d’effectuer des mesures de temps. Généralement, les ISA incluent des instructions permettant de connaître le nombre de cycles exécutés. Cette fonctionnalité est commune et essentielle pour de nombreux programmes. En exécutant deux mesures de cycles, un attaquant est capable de déduire le nombre de cycles qui s’est écoulé entre ces deux instructions. Il peut ainsi connaître le temps qu’a utilisé le processeur pour exécuter les instructions entre ces deux mesures. Dans notre modèle, l’attaquant dispose du minimum de droits sur le système. Il n’est donc pas privilégié et n’a accès qu’à ses propres données.

Le rapport de stage ou le pfe est un document d’analyse, de synthèse et d’évaluation de votre apprentissage, c’est pour cela chatpfe.com propose le téléchargement des modèles complet de projet de fin d’étude, rapport de stage, mémoire, pfe, thèse, pour connaître la méthodologie à avoir et savoir comment construire les parties d’un projet de fin d’étude.

Table des matières

Remerciements
Sommaire
Liste des figures
Liste des tableaux
Liste des codes
Liste des acronymes
1. Introduction
1.1. Contexte
1.2. Sécurité dans les systèmes
1.3. Objectifs et contributions
1.4. Organisation du manuscrit
Comprendre les microarchitectures modernes
2. Composants microarchitecturaux 
2.1. Principes généraux
Circuits logiques et mémoires
Organisation du processeur
Caractéristiques des jeux d’instructions
2.2. L’enjeu des performances
Limites du modèle de base
Utilisation d’un pipeline
Mémoires caches
2.3. Spéculation
Pipeline et exécution dans le désordre
Prédiction dynamique de branchement
Prefetcher
2.4. Parallélisme des exécutions
2.5. Mémoire virtuelle
2.6. Mécanismes de sécurité
Privilèges
Exceptions et interruptions
2.7. Conclusion
3. Exploitation de la microarchitecture par le logiciel
3.1. Objectifs de sécurité
3.2. Principes microarchitecturaux exploités
3.3. Attaques par analyse des variations temporelles
Principes
Attaques sur les mémoires caches
Étude généralisée du système
3.4. Attaques par contention dynamique de ressources
Principes
Impact sur les timings
3.5. Attaques par exécution transitoire
Principes
Spectre
Meltdown
Échantillonnage des données microarchitecturales
3.6. Attaques par canal contrôlé
3.7. Synthèse et conclusion
4. Solutions existantes contre l’exploitation logicielle
4.1. Solutions pour la gestion des ressources partagées
Suppression des mécanismes
Effacement des traces
Partitionnement des ressources
4.2. Solutions pour la gestion de la spéculation
Modifications du logiciel
Renforcement du matériel
4.3. Solutions de gestion du temps et des évènements
Modification des évènements microarchitecturaux
Indéterminisme du fonctionnement
Altération des mesures de temps
Exécution en temps constant
4.4. Stratégie globale
Prise en compte ciblée des failles
Rôles des couches d’abstraction
4.5. Conclusion et suite
Repenser le jeu d’instructions
5. Modifier l’ISA pour la sécurité
5.1. Principes de base
5.2. Organisation des domaines de sécurité
Hiérarchie statique
Hiérarchie hybride
Hiérarchie dynamique
5.3. Politique d’isolation microarchitecturale dans l’ISA
Forme des modifications de l’ISA
Stratégies d’abstraction du matériel
5.4. Conclusion
6. Domes
6.1. Stratégie de modification de l’ISA
ISA de base : RISC-V 32 bits
Objectifs d’implémentation
6.2. Proposition d’implémentation
Modèles et représentation
Opérations et instructions
Utilisation des capacités : les exceptions
6.3. Support d’une politique d’isolation
6.4. Impact sur le logiciel
Conception de la hiérarchie
Compilation
Scénario de dome.switch fréquents
6.5. Extension du modèle
Accès aux compteurs de performances
Intégrité du flot d’exécution
Chiffrement et authentification de la mémoire
Augmentation du nombre de domes
6.6. Version rétrocompatible avec les privilèges statiques
6.7. Conclusion
Adapter la microarchitecture
7. Conception des ressources partagées 
7.1. Définitions
Ressource partagée
Problématique et objectifs
7.2. Allocation statique des ressources
Principe
Mécanismes pour l’implémentation
7.3. Séparation des ressources
Principes
Mécanismes pour l’implémentation
7.4. Suppression des traces
Principe
Mécanismes pour l’implémentation
7.5. Homogénéité
7.6. Modèle mémoire et renforcement des frontières
Objectif
Accès contrôlé
Duplication
Cohérence
7.7. Conclusion
8. Implémentation d’une politique d’isolation 
8.1. Contexte
8.2. Processeur Aubrac
Description de l’architecture de base
Support des domes
8.3. Processeur Salers
Description de l’architecture de base
Support des domes
8.4. Mémoire cache
Fonctionnement général des caches
Partie « mémoire » des caches
Partie « contrôleur » des caches
Partie « bus » des caches
8.5. Généricité de l’approche
8.6. Autres mécanismes
8.7. Conclusion
9. Évaluation 
9.1. Timesecbench : une suite de tests pour la sécurité
Objectif et contraintes de développement
Scénario d’attaquant
Vulnérabilités couvertes par Timesecbench
9.2. Mesure d’efficacité des contremesures
Comparaison des implémentations vulnérables et sécurisées
Isolation temporelle
Isolation spatiale
9.3. Analyse des performances et du coût
Performances
Coût en ressources matérielles
9.4. Bilan et conclusion
10. Conclusion
10.1. Résumé des travaux
10.2. Bilan synthétique
10.3. Travaux futurs et perspectives
Publications et communications
Bibliographie
Annexes
A. Paramètres des processeurs
A.1. Processeur Aubrac
A.2. Processeur Salers
B. Liste des instructions pour les domes

Lire le rapport complet

Télécharger aussi :

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *