Afin d'atténuer la divulgation de mémoire du noyau ou inter-processus (l' attaque Spectre ), le noyau Linux 1 sera compilé avec une nouvelle option , -mindirect-branch=thunk-extern
introduite gcc
pour effectuer des appels indirects via une soi-disant retpoline .
Cela semble être un terme nouvellement inventé car une recherche Google ne s'avère que très récente (généralement en 2018).
Qu'est-ce qu'une retpoline et comment empêche-t-elle les récentes attaques de divulgation d'informations sur le noyau?
1 Ce n'est pas spécifique à Linux, cependant - une construction similaire ou identique semble être utilisée dans le cadre des stratégies d'atténuation sur d'autres systèmes d'exploitation.
security
assembly
x86
cpu-architecture
BeeOnRope
la source
la source
gcc
que cela pointe de cette façon! Je n'ai pas reconnu lkml.org/lkml/2018/1/3/780 comme sur le site de la liste de diffusion du noyau Linux, pas même une fois que j'y ai regardé (et j'ai reçu un instantané car il était hors ligne).Réponses:
L'article mentionné par sgbj dans les commentaires écrits par Paul Turner de Google explique beaucoup plus en détail ce qui suit, mais je vais essayer:
Pour autant que je puisse reconstituer cela à partir des informations limitées pour le moment, une retpoline est un trampoline de retour qui utilise une boucle infinie qui n'est jamais exécutée pour empêcher le CPU de spéculer sur la cible d'un saut indirect.
L'approche de base peut être vue dans la branche du noyau d'Andi Kleen traitant de ce problème:
Il introduit le nouvel
__x86.indirect_thunk
appel qui charge la cible d'appel dont l'adresse mémoire (que j'appelleraiADDR
) est stockée au-dessus de la pile et exécute le saut à l'aide d'uneRET
instruction. Le thunk lui-même est ensuite appelé à l'aide de la macro NOSPEC_JMP / CALL , qui a été utilisée pour remplacer de nombreux (sinon tous) appels et sauts indirects. La macro place simplement la cible d'appel sur la pile et définit correctement l'adresse de retour, si nécessaire (notez le flux de contrôle non linéaire):Le placement de
call
à la fin est nécessaire pour que lorsque l'appel indirect est terminé, le flux de contrôle continue derrière l'utilisation de laNOSPEC_CALL
macro, de sorte qu'il peut être utilisé à la place d'un réguliercall
Le thunk lui-même ressemble à ceci:
Le flux de contrôle peut devenir un peu déroutant ici, alors permettez-moi de clarifier:
call
pousse le pointeur d'instruction actuel (étiquette 2) vers la pile.lea
ajoute 8 au pointeur de pile , éliminant efficacement le dernier mot-clé poussé, qui est la dernière adresse de retour (à l'étiquette 2). Après cela, le haut de la pile pointe à nouveau sur la véritable adresse de retour ADDR.ret
saute*ADDR
et réinitialise le pointeur de pile au début de la pile d'appels.En fin de compte, tout ce comportement équivaut pratiquement à sauter directement vers
*ADDR
. Le seul avantage que nous obtenons est que le prédicteur de branche utilisé pour les instructions de retour (Return Stack Buffer, RSB), lors de l'exécution de l'call
instruction, suppose que l'ret
instruction correspondante passera à l'étiquette 2.La partie après le label 2 n'est jamais exécutée, c'est simplement une boucle infinie qui, en théorie, remplirait le pipeline d'
JMP
instructions avec des instructions. En utilisantLFENCE
,PAUSE
ou plus généralement, une instruction entraînant le blocage du pipeline d'instructions, le processeur ne perd ni temps ni énergie pour cette exécution spéculative. En effet, au cas où l'appel à retpoline_call_target reviendrait normalement, ceLFENCE
serait la prochaine instruction à exécuter. C'est également ce que le prédicteur de branche prédira en fonction de l'adresse de retour d'origine (l'étiquette 2)Pour citer le manuel d'architecture d'Intel:
Notez cependant que la spécification ne mentionne jamais que LFENCE et PAUSE provoquent le blocage du pipeline, donc je lis un peu entre les lignes ici.
Revenons maintenant à votre question initiale: la divulgation d'informations sur la mémoire du noyau est possible en raison de la combinaison de deux idées:
Même si l'exécution spéculative doit être sans effet secondaire lorsque la spéculation est erronée, l' exécution spéculative affecte toujours la hiérarchie du cache . Cela signifie que lorsqu'un chargement de mémoire est exécuté de manière spéculative, il peut toujours avoir provoqué l'expulsion d'une ligne de cache. Ce changement dans la hiérarchie du cache peut être identifié en mesurant soigneusement le temps d'accès à la mémoire qui est mappée sur le même ensemble de cache.
Vous pouvez même divulguer quelques bits de mémoire arbitraire lorsque l'adresse source de la mémoire lue a elle-même été lue dans la mémoire du noyau.
Le prédicteur de branche indirecte des processeurs Intel utilise uniquement les 12 bits les plus bas de l'instruction source, il est donc facile d'empoisonner tous les 2 ^ 12 historiques de prédiction possibles avec des adresses mémoire contrôlées par l'utilisateur. Ceux-ci peuvent alors, lorsque le saut indirect est prédit dans le noyau, être exécutés de manière spéculative avec les privilèges du noyau. En utilisant le canal latéral de synchronisation du cache, vous pouvez ainsi fuir la mémoire du noyau arbitraire.
MISE À JOUR: Sur la liste de diffusion du noyau , il y a une discussion en cours qui m'amène à penser que les retpolines n'atténuent pas complètement les problèmes de prédiction de branche, comme lorsque le Return Stack Buffer (RSB) est vide, les architectures Intel plus récentes (Skylake +) retombent à la cible vulnérable Branch Buffer (BTB):
la source
push
/ret
qu'il ne déséquilibre le prédicteur adresse de retour pile. Il y a une erreur (aller àlfence
avant que l'adresse de retour réelle ne soit utilisée), mais l'utilisation d'unecall
modification + arsp
compensé celaret
.push
/ret
(dans mon dernier commentaire). re: votre montage: le sous-dépassement RSB devrait être impossible car la retpoline comprend acall
. Si la préemption du noyau faisait un changement de contexte là-bas, nous reprendrions l'exécution avec le RSB amorcé ducall
dans le planificateur. Mais peut-être qu'un gestionnaire d'interruption pourrait se terminer avec suffisamment deret
s pour vider le RSB.Une rétpoline est conçue pour protéger contre l'injection de cible de branche ( CVE-2017-5715 exploit d' ). Il s'agit d'une attaque dans laquelle une instruction de branchement indirect dans le noyau est utilisée pour forcer l'exécution spéculative d'un morceau de code arbitraire. Le code choisi est un "gadget" qui est en quelque sorte utile à l'attaquant. Par exemple, le code peut être choisi de manière à ce que les données du noyau fuient par la façon dont il affecte le cache. La retpoline empêche cet exploit en remplaçant simplement toutes les instructions de branchement indirect par une instruction de retour.
Je pense que la clé de la retpoline est juste la partie "ret", qu'elle remplace la branche indirecte par une instruction de retour afin que le CPU utilise le prédicteur de pile de retour au lieu du prédicteur de branche exploitable. Si une simple poussée et une instruction de retour étaient utilisées à la place, le code qui serait exécuté de manière spéculative serait le code auquel la fonction retournera finalement de toute façon, pas un gadget utile à l'attaquant. Le principal avantage de la partie trampoline semble être de maintenir la pile de retour, donc lorsque la fonction retourne réellement à son appelant, cela est prédit correctement.
L'idée de base derrière l'injection de cible de branche est simple. Il tire parti du fait que le CPU n'enregistre pas l'adresse complète de la source et de la destination des branches dans ses tampons cibles de branche. Ainsi, l'attaquant peut remplir le tampon en utilisant des sauts dans son propre espace d'adressage qui entraîneront des hits de prédiction lorsqu'un saut indirect particulier est exécuté dans l'espace d'adressage du noyau.
Notez que retpoline n'empêche pas la divulgation directe des informations sur le noyau, il empêche seulement les instructions de branchement indirectes d'être utilisées pour exécuter spéculativement un gadget qui divulguerait des informations. Si l'attaquant peut trouver d'autres moyens d'exécuter le gadget de manière spéculative, la retpoline n'empêche pas l'attaque.
L'article Specter Attacks: Exploiting Speculative Execution de Paul Kocher, Daniel Genkin, Daniel Gruss, Werner Haas, Mike Hamburg, Moritz Lipp, Stefan Mangard, Thomas Prescher, Michael Schwarz et Yuval Yarom donne l'aperçu suivant de la manière dont les branches indirectes peuvent être exploitées. :
Une entrée de blog intitulée Lire la mémoire privilégiée avec un canal latéral par l'équipe de Project Zero chez Google fournit un autre exemple de la façon dont l'injection de cible de branche peut être utilisée pour créer un exploit fonctionnel.
la source
Cette question a été posée il y a un certain temps et mérite une réponse plus récente.
Résumé :
Les séquences de «retpoline» sont une construction logicielle qui permet d'isoler les branches indirectes de l'exécution spéculative. Cela peut être appliqué pour protéger les binaires sensibles (tels que les implémentations de système d'exploitation ou d'hyperviseur) contre les attaques par injection de cible de branche contre leurs branches indirectes.
Le mot " ret poline " est un portemanteau des mots "return" et "trampoline", tout comme l'amélioration " rel poline " a été inventée à partir de "relative call" et "trampoline". Il s'agit d'une construction de trampoline construite à l'aide d'opérations de retour qui garantit également au sens figuré que toute exécution spéculative associée «rebondira» à l'infini.
L'utilisation de cette option de compilateur protège uniquement contre Spectre V2 dans les processeurs affectés qui ont la mise à jour du microcode requise pour CVE-2017-5715. Il " fonctionnera " sur n'importe quel code (pas seulement sur un noyau), mais seul le code contenant des "secrets" mérite d'être attaqué.
Le compilateur LLVM avait un
-mretpoline
commutateur depuis avant le 4 janvier 2018 . C'est à cette date que la vulnérabilité a été publiée pour la première fois . GCC a rendu ses correctifs disponibles le 7 janvier 2018.La date CVE suggère que la vulnérabilité a été `` découverte '' en 2017, mais elle affecte certains des processeurs fabriqués au cours des deux dernières décennies (elle a donc probablement été découverte il y a longtemps).
Tout d'abord, quelques définitions:
Trampoline - Parfois appelés trampolines à vecteurs de saut indirects, les emplacements de mémoire contiennent des adresses pointant vers des routines de service d'interruption, des routines d'E / S, etc. L'exécution saute dans le trampoline puis saute immédiatement ou rebondit, d'où le terme trampoline. GCC a traditionnellement pris en charge les fonctions imbriquées en créant un trampoline exécutable au moment de l'exécution lorsque l'adresse d'une fonction imbriquée est prise. Il s'agit d'un petit morceau de code qui réside normalement sur la pile, dans le cadre de pile de la fonction conteneur. Le trampoline charge le registre de chaîne statique puis saute à l'adresse réelle de la fonction imbriquée.
Thunk - Un thunk est un sous-programme utilisé pour injecter un calcul supplémentaire dans un autre sous-programme. Les Thunks sont principalement utilisés pour retarder un calcul jusqu'à ce que son résultat soit nécessaire, ou pour insérer des opérations au début ou à la fin de l'autre sous-programme
Mémorisation - Une fonction mémorisée "se souvient" des résultats correspondant à un ensemble d'entrées spécifiques. Les appels suivants avec des entrées mémorisées renvoient le résultat mémorisé plutôt que de le recalculer, éliminant ainsi le coût principal d'un appel avec des paramètres donnés de tous, sauf le premier appel effectué vers la fonction avec ces paramètres.
Très grossièrement, une rétpoline est un trampoline avec un retour en tant que thunk , pour « gâcher » la mémorisation dans le prédicteur de branche indirecte.
Source : La retpoline comprend une instruction PAUSE pour Intel, mais une instruction LFENCE est nécessaire pour AMD car sur ce processeur, l'instruction PAUSE n'est pas une instruction de sérialisation, donc la boucle pause / jmp utilisera une puissance excessive car elle est spéculée sur l'attente du retour de mal prédire la bonne cible.
Arstechnica a une explication simple du problème:
Extrait du document d'Intel: " Retpoline: A Branch Target Injection Mitigation " ( .PDF ):
la source