Update main.tex

This commit is contained in:
augustin64 2024-07-12 12:03:28 +02:00
parent 056b338c9b
commit f78ad5147b
3 changed files with 250 additions and 69 deletions

Binary file not shown.

286
main.tex
View File

@ -7,6 +7,7 @@
\usepackage{algorithm2e}
\usepackage{csquotes}
\usepackage{hyperref}
\usepackage{footmisc}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage{xcolor}
@ -18,7 +19,7 @@
\SetKwComment{Comment}{/* }{ */}
% titre
\title{Caractérisation de linstruction \texttt{clflush} sur systèmes multi-socket}
\title{Caractérisation de linstruction \texttt{clflush} sur systèmes multi-\ang{socket}}
\author{\textsc{Augustin LUCAS}\\ENS de Lyon\\ \\Encadré par :\\
\textsc{Guillaume DIDIER}, \textsc{Angeliki KRITIKAKOU}\\
Équipe \textsc{Taran}\\
@ -29,80 +30,86 @@ Université de \textsc{Rennes} 1}
% quelques macros
\newcommand{\TODO}[1]{{\color{red}#1}}
\newcommand{\ang}[1]{\emph{#1}} % texte anglais
% le document lui-même
\begin{document}
\maketitle
\begin{abstract}
\TODO{Réécrire parce qu'il fallait juste que je démarre mais ça ne ressemblait à rien}
\end{abstract}
\tableofcontents
\newpage
\section{\TODO{Abstract}}
\TODO{Réécrire parce qu'il fallait juste que je démarre mais ça ne ressemblait à rien}
\section{Introduction}
\subsection{Hiérarchie de cache}
La mémoire DRAM d'un ordinateur est lente comparée à la fréquence du CPU. Le CPU dispose donc de caches,
basés sur une mémoire SRAM, plus petite mais plus rapide.
basés sur une mémoire SRAM, plus petite mais plus rapide. Stocker en cache les éléments accédés
le plus fréquemment permet donc de réduire le nomre d'appels à la mémoire et donc le temps d'exécution.
La politique de fonctionnement du cache cherche à minimiser le nombre d'accès à la mémoire DRAM.
Une politique optimale serait donc de charger en priorité les données qui vont être utilisées dans
un futur proche et d'évicter les données qui seront utilisées dans plus longtemps ou qui ne sont
plus utiles. Comme on ne peut pas aisément déterminer quels seront les prochains accès mémoire,
une heuristique de type LRU (Least Recently Used) est généralement mise en place pour déterminer
les données à évicter.
\begin{figure}[ht]
\centering
\includegraphics[width=0.3\textwidth]{cachehierarchy}
\caption{Différents niveaux de cache}
\end{figure}
Les processeurs que nous étudions disposent de 3 niveaux de cache : L1, L2, L3. À la différence du L1 et L2,
le cache L3 est partagé et inclusif
\footnote{Cela dépend de l'architecture considérée : à partir de SkyLake, le L3 n'est plus inclusif}:
le L3 est le même pour tous les coeurs,
alors que chaque coeur dispose de son L1 et son L2 ; toutes les données contenues dans au
moins un L1 ou un L2 sont aussi dans le L3
Les processeurs que nous étudions disposent de 3 niveaux de cache : L1, L2, L3.
Chaque processeur possède, au premier niveau, un L1i (cache des instructions) et
un L1d (cache des données). Au second niveau, il possède un L2 qui contient potentiellement
des données et des instructions. Au dernier niveau, le L3 est partagé entre tous les coeurs de la
\ang{socket}, et celui-ci est inclusif de tous les caches de niveau inférieur : toute ligne
stockée dans le cache L1 ou L2 est également dans le L3.
Si le L3 est partagé, il n'est cependant pas situé en un seul endroit dans le CPU
mais est séparé en différentes slices : des tranches de mémoire accolées chacune à un coeur. Dans le modèle
étudié, chaque coeur a exactement une slice\footnote{\TODO{c'est plus compliqué sur les nouveaux proc}}.
mais est réparti en différentes \ang{slices} : des tranches de mémoire accolées chacune à un coeur. Dans le modèle
étudié, chaque coeur a exactement une \ang{slice}\footnote{\TODO{c'est plus compliqué sur les nouveaux proc}}.
\begin{figure}[ht]
\centering
\includegraphics[width=0.4\textwidth]{broadwell-die-shot}
\caption{Broadwell Deca-Core die shot by Intel - annotated by Wikichip \cite{broadwelldieshot}}
% L'espace vide l'est bien sur le die-shot, donc sûrement "Intel being stupid"
\end{figure}
Lorsqu'un coeur accède à une donnée qui n'est pas encore dans son cache, c'est toute la ligne de mémoire:
les 64 bytes environnants (généralement) qui sont chargés dans son L1 ou L2. Comme le L3 est inclusif,
la ligne y est chargée également. Une fonction de hachage non documentée prenant en entrée
l'adresse mémoire de la donnée permet de choisir dans quelle slice du L3 celle-ci sera stockée.
Le travail de Clémentine Maurice et al.\cite{slice-reverse} a permis de révéler cette fonction.
les 64 octets environnants (généralement) qui sont chargés dans son L1 ou L2. Comme le L3 est inclusif,
la ligne y est chargée également. Une fonction de hachage non-documentée attribue à chaque adresse
physique une unique \ang{slice} dans laquelle elle peut être mise en cache.
Différents travaux\cite{slice-reverse, practicalTiming} ont permis de déterminer cette fonction.
\subsection{\TODO{Protocoles de cohérence de cache}}
\TODO{
\begin{enumerate}
\item Problème à résoudre
\item Expliquer la solution par "directory"
\item Expliquer le snooping
\end{enumerate}
}
\subsection{Attaques par canaux auxiliaires}
\TODO{Expliquer le concept général}
\subsubsection{L'instruction \texttt{clflush}}
D'après le manuel Intel\cite{intel-man-vol1}:
\begin{displayquote}
(flush cache line) instruction writes and invalidates the cache line associated
with a specified linear address. The invalidation is for all levels of the processors cache
hierarchy, and it is broadcast throughout the cache coherency domain.
\sffamily \emph{
CLFLUSH (flush cache line) instruction writes and invalidates the cache line associated
with a specified linear address. The invalidation is for all levels of the processors cache
hierarchy, and it is broadcast throughout the cache coherency domain.
}
\end{displayquote}
Lorsque l'instruction \texttt{clflush} est exécutée, l'adresse et la ligne de cache associée sont
évincés de tous les caches L1, L2 et L3 où elles se trouvaient possiblement.
Si des modifications avaient eu lieu, les modifications sont réécrites dans la mémoire DRAM.
évincés de tous les caches L1, L2 et L3 où elles se trouvaient possiblement, et cela dans tous les
\ang{sockets} du système. Si des modifications avaient eu lieu,
les modifications sont réécrites dans la mémoire DRAM.
L'instruction \texttt{clflush} est accessible à tout utilisateur non privilégié sur
les adresses mémoires \TODO{auxquelles il a accès}.
les adresses mémoires auxquelles il a accès.
\subsubsection{\TODO{Flush+Reload}}
\subsubsection{Flush+Flush}
@ -117,60 +124,188 @@ Flush+Flush \cite{flushflush} propose la méthode suivante :
\KwData{$x$ : addresse à surveiller}
\KwResult{Y a t-il eu un accès à $x$ ?}
$clflush(x)$ \Comment*[l]{$x$ est dans l'état $I$}
$sleep(n)$ \Comment*[l]{$x$ passe dans l'état $E$ si un coeur y accède}
$sleep(n)$ \Comment*[l]{$x$ passe dans l'état $E$ si un unique coeur y accède en lecture}
$t \gets rdtsc()$\;
$clflush(x)$\;
$total\_time \gets rdtsc() - t$\;
\end{algorithm}
Les avantages de cette méthode par rapport à Prime+Probe ou Flush+Reload\TODO{[?]} sont multiples :
Les avantages de cette méthode par rapport à Flush+Reload\cite{flushreload} sont multiples :
\begin{itemize}
\item Aucun accès mémoire n'est réalisé pour surveiller l'adresse, ce qui rend les méthodes de détection
qui comptent le nombre de \textit{cache miss} inefficaces.
\cite{flushflush} propose des solutions de détection alternatives mais montre qu'elles auraient toutes
un coût bien trop élevé.
\item Comme aucun accès mémoire n'est réalisé, la vitesse de traitement et le débit de données qui peuvent
être extraites est bien plus élevé : $496$KB/s contre $298$KB/s pour Flush+Reload
\item Aucun accès mémoire n'est réalisé pour surveiller l'adresse, ce qui rend les méthodes de
détection qui comptent le nombre de \ang{cache miss} inefficaces.
\cite{flushflush} propose des solutions de détection alternatives mais montre qu'elles
auraient toutes un coût bien trop élevé.
\item Comme aucun accès mémoire n'est réalisé, la vitesse de traitement et le débit
de données qui peuvent être extraites est bien plus élevé :
$496$KB/s contre $298$KB/s pour Flush+Reload
\TODO{what are packets in \cite{flushflush} ?}
\TODO{what are packets in \cite{flushflush} ?
$\rightarrow$ j'ai eu une réponse il faut que je regarde}
\item Comme l'opération mesurée agit sur tous les caches du système et pas seulement sur ceux
utilisés par l'attaquant, Flush+Flush peut opérer dans un système avec une
hiérarchie de cache non inclusive. Ce qui est le cas des systèmes à deux
\ang{sockets} notamment, alors que Flush+Reload nécessite de partager un cache en commun
(le L3 par exemple).
\end{itemize}
Similairement à ces autres méthodes, Flush+Flush peut extraire des données du fonctionnement des
autres processus en regardant les accès mémoires faits dans les bibliothèques partagés,
qui occupent les mêmes zones de la mémoire physique pour différents processus.
\cite{cryptoeprint:2014/140} propose par exemple de récupérer le nonce d'une clé OpenSSL avec Flush+Reload
en regardant les zones mémoire accédées pendant le chiffrement de données.
La possibilité de créer un enregistreur de frappe (\textit{keylogger}) en se basant sur
les pages accédées dans la librairie \textsc{Gtk} \texttt{libgdk.so} est également
mise en oeuvre dans \cite{cachetemplateattacks}.
\subsubsection{Améliorer la précision}
\TODO{changer le titre}
Daniel Gruss et al.\cite{cachetemplateattacks} propose par exemple de récupérer
le nonce d'une clé OpenSSL avec Flush+Reload
en regardant les zones mémoire accédées pendant le chiffrement de données.
Un enregistreur de frappe (\ang{keylogger}) basé sur
les pages accédées dans la librairie \textsc{Gtk} \texttt{libgdk.so} y est également mis en oeuvre.
\section{Motivation}
Là où Flush+Reload choisit de mesurer le temps pour charger à nouveau une adresse en mémoire,
Flush+Flush choisit de mesurer le temps nécessaire pour l'évincer : la différence entre
un \textit{cache hit} et un \textit{cache miss} est alors beaucoup moins perceptible (moins de 12 cycles de CPU).
un \ang{cache hit} et un \ang{cache miss} est alors beaucoup moins perceptible (moins de 12 cycles de CPU).
De bons résultats\cite{flushflush} ont toutefois été obtenus en appliquant un seuil global.
Guillaume DIDIER et al.\cite{calibrationdoneright} proposent une autre approche :
comprendre le trajet des messages échangés dans le
CPU dans le cas d'un \textit{hit} ou d'un \textit{miss}, afin d'en déduire un modèle mathématique
qui fera office de calibration et permettra de meilleurs résultats en connaissant le coeur attaquant, victime,
voire la slice où est une ligne de cache. Cela permet également de trouver les paramètres avec la plus faible
incertitude quant aux résultats et de les ajuster en conséquence si possible (le coeur attaquant est facilement
controllable par exemple).
Guillaume \textsc{Didier} et Clémentine \textsc{Maurice}~\cite{calibrationdoneright}
proposent une autre approche : comprendre les messages échangés en fonction de l'état de cohérence
du cache ainsi que les autres sources de variabilité pour bien étalonner sur
l'ensemble des combinaisons pertinentes et choisir les bons seuils en fonction.
Ce travail s'était intéressé à certains processeurs Intel de micro-architectures \ang{Coffee Lake} et
\ang{Haswell} à une seule \ang{socket}, mais a révélé que les résultats seraient bien plus complexes
sur des systèmes à plusieurs \ang{sockets}.
Ce travail s'était intéressé à certains processeurs Intel de micro-architectures \textit{Coffee Lake} et
\textit{Haswell} à une seule \textit{socket}, mais a révélé que les résultats seraient bien plus complexes
sur des systèmes à plusieurs \textit{socket}.
\section{Organisation des expériences}
\section{\TODO{Systèmes multi-socket}}
\TODO{trouver un titre approprié}
Les expériences ont été faites sur 6 machines différentes,
via la plateforme \href{https://www.grid5000.fr/}{Grid'5000} afin d'échantillonner au moins une machine
par processeur répondant aux critères suivants:
\begin{itemize}
\item Processeur Intel ;
\item Exactement 2 \ang{socket} ;
\item Nombre de coeurs par \ang{socket} est une puissance de
deux \footnote{\TODO{l'expliquer en amont et le rappeler ici}} ;
\item Micro-architecture antérieure à SkyLake\footnote{Le L3 n'est plus inclusif
sur les processeurs serveur à partir de SkyLake}
\end{itemize}
Les machines suivantes ont donc été utilisées
\begin{center}
\begin{tabular}{| c c c c |}
\hline
Nom & Nombre de coeurs & Processeur & Micro-architecture \\
\hline
rennes/abacus2 & 16 & \TODO{Xeon E5-2609 v4} & \TODO{Sandy Bridge} \\
cell4 & cell5 & cell6 & a \\
cell7 & cell8 & cell9 & a \\
\hline
\end{tabular}
\end{center}
Le turbo a été désactivé sur toutes les machines.
La fréquence des coeurs fixée : à la fréquence minimale supportée par les processeurs ;
le mode performance ne donnant pas le même résultat que sur les machines \ang{Intel Core}.
\TODO{(Parler du NUMA balancing dans le Background)} Le \ang{NUMA balancing} a
également été désactivé (à l'échelle du système),
ce qui peut se faire pour le processus courant sans
privilèges\footnote{\TODO{à vérifier ! voir les "À faire"}}.
\section{Analyse des résultats}
\subsection{\TODO{Conduite des expériences}}
\begin{figure}[ht]
\centering
\includegraphics[width=0.5\textwidth]{low-core-count}
\caption{Topologie \TODO{LCC} Haswell EP d'après \cite{tuningXeon} \TODO{schéma à déplacer}}
\end{figure}
Les schémas de présentation d'Intel suggèrent une topologie en anneau, avec un CPU divisé en deux grandes parties.
Pour la numérotation des coeurs, les premiers tests semblent révéler une numérotation
suivant ce schéma\footnote{Il est possible que la numérotation soit en fait tournée à 180°. Comme nous
avons appliqué la même rotation aux \ang{slice}, cela n'affecterait que les positions respectives
du QPI et du \ang{Home Agent}}:
\begin{center}
\begin{tabular}{|c|c|}
\hline
0 & 1 \\ \hline
2 & 3 \\ \hline
4 & 5 \\ \hline
6 & 7 \\ \hline
\end{tabular}
\end{center}
Pour simplifier les interprétations, nous les avons renumérotés de la sorte,
c'est la numérotation que nous utiliserons pour la suite:
\TODO{Faire une minipage pour perdre moins de place}
\begin{center}
\begin{tabular}{|c|c|}
\hline
0 & 7 \\ \hline
1 & 6 \\ \hline
2 & 5 \\ \hline
3 & 4 \\ \hline
\end{tabular}
\end{center}
Pour trouver la numérotation des \ang{slices}, deux méthodes sont possibles:
\begin{itemize}
\item Utiliser les compteurs de performance pour déterminer la \ang{slice} d'une adresse. Cela nécessite
de lire les MSR correspondants donc d'avoir un accès \ang{root}. Nous avons suivi cette méthode
afin d'être sûr que les numéros de \ang{slice} correspondent aux numéros de coeurs ;
\item Utiliser la fonction de hachage (linéaire)\cite{slice-reverse} pour
déterminer la \ang{slice} de chaque adresse. Comme la
fonction est appliquée sur l'adresse virtuelle et non pas physique, l'ordre des \ang{slices} n'est pas le
bon mais deux adresses sont envoyées dans la même \ang{slice} uniquement si elles le sont réellement.
\TODO{clarifier, le côté math est mal expliqué}
Il serait envisageable de donner une méthode permettant de réordonner automatiquement les \ang{slices},
et donc d'exploiter ceci depuis un utilisateur non privilégié
\TODO{à réécrire aussi}
\end{itemize}
\subsection{Topologie Miss}
\TODO{graphiques comparaison prédiction/réel}
\TODO{Je ne sais plus, en enlevant $S_R$,
est-ce que le modèle marchait bien avec socket(A) = socket(V) ?}
Les résultats obtenus quand le \ang{socket} attaquant et victime diffèrent suggèrent l'échange des messages suivant lors d'un \texttt{clflush} qui provoque un \ang{cache miss}:
\begin{enumerate}
\item Le coeur attaquant contacte la \ang{slice} locale suivant le schéma \TODO{ref figure en dessous}
\item La \ang{slice} locale contacte la \ang{slice} distante en passant par le QPI.
Le trajet de la \ang{slice} locale au QPI se fait dans le sens horaire,
celui du QPI à la \ang{slice} distante dans le sens anti-horaire.
\item Si le \ang{Home Agent} distant doit être contacté, cela se fait à ce moment, en faisant
un tour complet de la \ang{socket} pour revenir à la \ang{slice} distante.
Nous n'avons effectivement pas trouvé d'élément permettant de montrer un trajet différent.
\item Le chemin est parcouru à l'envers pour repasser par la \ang{slice} locale jusqu'au coeur attaquant
\end{enumerate}
\TODO{À quel point faut-il justifier ce qui est avancé ici ? La progression qui suggère le 2.
vient du \texttt{optimize.curve\_fit} et affichait qqchose d'étrange (les coeurs 2 par 2).
J'imagine que c'est toujours bon à préciser}
\begin{figure}[ht]
\centering
\rotatebox{270}{
\includegraphics[width=0.7\textwidth]{topology-miss}
}
\caption{\TODO{schéma propre}}
\end{figure}
Ainsi, le chemin privilégié pour le trajet coeur attaquant - \ang{slice} locale serait assez proche du plus court, mais tenterait de limiter les passages
par le \ang{Home Agent} possiblement pour éviter de ralentir les opérations qui ont besoin de
passer par lui.
\subsection{\TODO{Topologie Hit}}
\subsection{\TODO{Analyse des résultats}}
\textbf{Aknowledgements} Experiments presented in this paper were carried out using the Grid'5000 testbed,
supported by a scientific interest group hosted by Inria and including \textsc{Cnrs},
@ -179,6 +314,19 @@ supported by a scientific interest group hosted by Inria and including \textsc{C
\bibliographystyle{plain}
\bibliography{refs}
\TODO{\textit{Recovering OpenSSL ECDSA nonces using the FLUSH+RELOAD cache side-channel attack} lu transversalement, citable quand-même ?}
\section{À faire pour continuer le stage}
\TODO{rédiger mieux qu'une liste}
\begin{itemize}
\item vérifier que \texttt{numactl} permet de verrouiller les pages "partagées"
\item modèle hit : coût des sauts $A \rightarrow S$ cohérent avec $S_L \rightarrow S_R$ ?
\item \TODO{en plottant A=S=V pour toutes les valeurs possibles, ça ne montrait pas de preuve
du trajet \ang{slice}\_l-\ang{slice}\_r}
\end{itemize}
\TODO{Faire un passage sur le code : qu'est-ce que j'ai apporté,
qu'est-ce qui était déjà fait. Où le trouver}
\TODO{Passage sur le labo, l'équipe, l'ambiance}
\end{document}

View File

@ -8,6 +8,16 @@
url={https://arxiv.org/abs/1511.04594},
}
@proceedings{flushreload,
title={SEC'14: Proceedings of the 23rd USENIX conference on Security Symposium},
year={2014},
isbn={9781931971157},
publisher={USENIX Association},
address={USA},
location={San Diego, CA},
url={https://www.usenix.org/system/files/conference/usenixsecurity14/sec14-paper-yarom.pdf}
}
@inproceedings{calibrationdoneright,
TITLE = {{Calibration Done Right: Noiseless Flush+Flush Attacks}},
@ -25,6 +35,7 @@
@misc{broadwelldieshot,
title={Broadwell - Microarchitectures - Intel - WikiChip (2024)},
url={https://en.wikichip.org/wiki/intel/microarchitectures/broadwell_(client)#Deca-core_Broadwell},
note={\url{https://en.wikichip.org/wiki/intel/microarchitectures/broadwell_(client)#Deca-core_Broadwell}},
}
@ -82,3 +93,25 @@
note={\url{https://eprint.iacr.org/2014/140}},
url={https://eprint.iacr.org/2014/140}
}
@misc{tuningXeon,
author={Michael Klemm},
from={Software and Service Group Intel},
title={Programming and Tuning for Intel Xeon Processors},
year={2015},
url={https://docs.dkrz.de/_downloads/31658e1743d2d33f0664ae4c69d39360/Programming_and_Tuning_for_Intel_Xeon_Processors_2015-07-01_M.Klemm.pdf},
note={\url{https://docs.dkrz.de/_downloads/31658e1743d2d33f0664ae4c69d39360/Programming_and_Tuning_for_Intel_Xeon_Processors_2015-07-01_M.Klemm.pdf}}
}
@INPROCEEDINGS{practicalTiming,
author={Hund, Ralf and Willems, Carsten and Holz, Thorsten},
booktitle={2013 IEEE Symposium on Security and Privacy},
title={Practical Timing Side Channel Attacks against Kernel Space ASLR},
year={2013},
volume={},
number={},
pages={191-205},
keywords={Kernel;Aerospace electronics;Layout;Timing;Memory management;Linux;Address Space Layout Randomization;Timing Attacks;Kernel Vulnerabilities;Exploit Mitigation},
doi={10.1109/SP.2013.23}
}