\documentclass[10pt]{article}

% import des packages nécessaires
\usepackage[margin=1.2in]{geometry}
\usepackage[french]{babel}
\usepackage[T1]{fontenc}
\usepackage{algorithm2e}
\usepackage{csquotes}
\usepackage{hyperref}
\usepackage{footmisc}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage{xcolor}
\usepackage{syntax}
\usepackage{float}

% configuration des packages
\hypersetup{colorlinks=false}
\graphicspath{ {./figs/} }
\SetKwComment{Comment}{/* }{ */}

% titre
\title{Caractérisation de l’instruction \texttt{clflush} sur systèmes multi-\ang{socket}}
\author{Augustin \textsc{Lucas}\\ENS de Lyon\\ \\Encadré par :\\
Guillaume \textsc{Didier}, Angeliki \textsc{Kritikakou}\\
Équipe \textsc{Taran}\\
Laboratoire \textsc{Irisa}\\
Université de \textsc{Rennes} 1}

\date{3 juin 2024 - 12 juillet 2024}

% 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}
  Les attaques par canaux auxiliaires sont particulièrement intéressantes car elles
  permettent un accès à des informations restreintes, par delà même les \ang{sandbox} ou
  machines virtuelles. Nous nous intéresserons plus particulièrement aux attaques par
  canaux auxiliaires sur le cache : Flush+Reload et Flush+Flush.

  Ce stage cherche à renseigner la topologie des appels à l'instruction \texttt{clflush}
  sur des systèmes \ang{Intel} à deux \ang{sockets} ; notamment pour mieux évaluer l'état d'une
  ligne de cache en fonction du temps d'exécution de l'instruction \texttt{clflush} sur celle-ci.
\end{abstract}

\newpage
\tableofcontents


\section{Contexte}

\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 des mémoires SRAM, plus petites mais plus rapides. Stocker en cache les éléments accédés
le plus fréquemment permet donc de réduire le nombre d'appels à la mémoire et donc le temps d'exécution.

Les processeurs que nous étudions disposent de 3 niveaux de cache : L1, L2, L3.
Chaque coeur possède, au premier niveau, un L1-I (cache des instructions) et
un L1-D (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 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}.

\begin{figure}[ht]
  \centering
  \includegraphics[width=0.4\textwidth]{broadwell-die-shot}
  \caption{Broadwell Deca-Core die shot by Intel - annotated by Wikichip~\cite{broadwell-wikichip}}
  % 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 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.

\label{poweroftwo} Si les fonctions initialement utilisées
étaient simplement basés sur certains bits de l'adresse,
la fonction de hachage utilisée à partir de la micro-architecture Sandy Bridge
(et au moins jusqu'à Tiger Lake) utilise le XOR de plusieurs bits de chaque adresse physique
pour générer chaque bit du numéro de \ang{slice}. Alors, la fonction de hachage est linéaire sur les
processeurs avec un nombre de coeurs qui est une puissance de 2, mais une composante non-linéaire
s'ajoute sur les autres processeurs.

\subsubsection{\ang{NUMA}}

\begin{figure}[ht]
  \centering
  \includegraphics[width=1.0\textwidth]{lstopo}
  \caption{Topologie \ang{NUMA} de la machine \textit{paravance} extraite
    avec l'outil \texttt{lstopo} de \texttt{hwloc}}
\end{figure}

Dans un système à plusieurs \ang{sockets}, chaque \ang{socket} a de la mémoire DRAM à laquelle il
peut accéder directement. Sur les machines Intel, le \ang{QPI} (\ang{QuickPath Interconnect})
permet à un processeur d'accéder aux données localisées dans la mémoire rattachée à un autre processeur.

Le principe \ang{NUMA} (\ang{Non-uniform memory access}) délimite alors des groupes contenant
un processeur et les adresses mémoire qui en sont rapprochées et les transmet au système d'exploitation.
Cela permet à ce dernier d'allouer la mémoire dans les adresses proche du processeurs qui en a besoin.

Sur Linux, si beaucoup d'accès mémoire sont réalisés d'un processeur
à des adresses qui lui sont éloignées, les pages correspondantes sont migrées.

\subsection{Protocoles de cohérence de cache}

Dans des systèmes à plusieurs coeurs, d'autant plus avec plusieurs processeurs, où chaque coeur a
un cache qui lui est propre, un problème de cohérence apparaît. Comment s'assurer qu'une ligne de données
ne soit pas réécrite de différentes manières en plusieurs caches du système ?

On peut commencer par définir des états dans lesquels
sont considérées les lignes de cache :
\begin{itemize}
  \item \emph{M} Modifié : la ligne est stockée modifiée dans un unique cache
  \item \emph{E} Exclusif : la ligne est stockée intacte dans un unique cache
  \item \emph{S} Partagé : la ligne est stockée intacte dans plusieurs caches
    (plusieurs caches disjoints, des L1 de coeurs différents par exemple)
  \item \emph{I} Invalide : la ligne a été invalidée dans ce cache,
    car modifiée dans un autre cache par exemple
\end{itemize}
D'autres sont parfois ajoutés à cette liste comme \ang{Forward}.

Une première solution au problème de cohérence de cache,
dite par annuaire (\ang{directory}), consiste à avoir à côté des différents
caches un \ang{directory} qui contient pour chaque ligne de mémoire en cache
son état dans les différents endroits où elle est stockée.
Lorsqu'une donnée partagée est modifiée, le \ang{directory} est chargé d'envoyer
aux autres caches une requête invalidant la ligne modifiée

Dans l'autre solution principalement utilisée, dite par \ang{snooping},
chaque cache surveille de son côté les lignes qu'il a en mémoire.

Dans le système étudié, la cohérence se gère par \ang{directory} au sein d'une
même \ang{socket}, mais par \ang{snooping} entre les deux \ang{sockets}.

\subsection{Attaques par canaux auxiliaires}

\subsubsection{Mémoire partagée}

Les systèmes d'exploitation utilisent le principe de mémoire partagée pour
réduire l'utilisation totale de mémoire physique. C'est-à-dire que différentes
pages de mémoire virtuelle correspondent à une même page de mémoire physique,
partagée potentiellement entre plusieurs processus.

Par exemple, les bibliothèques utilisées par plusieurs programmes ne sont chargées
qu'une seule fois en mémoire pour tous les programmes les utilisant.

De la même manière, lorsque un processus est dupliqué (via \ang{fork})
ou lancé deux fois, les données qu'ils ont en commun
(le code du programme par exemple) sont partagées entre
les différentes instances du programme.

Une autre forme de déduplication consiste à regarder
les pages de mémoire contenant les mêmes données et à les combiner.
Cela peut amener différents processus \ang{sandbox}és
même de machines virtuelles différentes à partager des données en commun.

\subsubsection{L'instruction \texttt{clflush}}

D'après le manuel Intel~\cite{intel-man-vol1}:
\begin{displayquote}
  \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 processor’s 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ées 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 auxquelles il a accès.

\subsubsection{Flush+Reload}

Le temps de chargement d'une donnée est largement influencé par sa présence en cache.
Mesurer le temps de chargement d'une adresse permet donc de déterminer aisément si la ligne de
cache associée était déjà présente en cache.

Flush+Reload~\cite{flushreload} propose donc la méthode suivante:

\begin{algorithm}[ht]
  \caption{Flush+Reload}\label{alg:flushreload}
  \KwData{$x$ : addresse à surveiller}
  \KwResult{Y a t-il eu un accès à $x$ ?}
  $clflush(x)$ \Comment*[l]{$x$ n'est plus en cache}
  $sleep(n)$ \Comment*[l]{Si un coeur accède à $x$, $x$ est à nouveau dans le L3}
  $t \gets rdtsc()$\;
  $read(x)$\;
  $total\_time \gets rdtsc() - t$\;
\end{algorithm}

La différence entre le temps de lecture depuis le cache et depuis la DRAM étant conséquent,
cette méthode permet de déterminer avec un faible taux d'erreur si un accès a été fait à une adresse,
le grand nombre de \ang{reload} effectués par les \texttt{clflush} et \texttt{read} successifs est
cependant visible via des compteurs de performance et donc détectable,
et ne permet pas une haute fréquence d'observation.

\subsubsection{Flush+Flush}

Le temps d'exécution de l'instruction \texttt{clflush} dépendant de l'état de cohérence de la ligne
de cache concernée, la connaissance de son temps d'exécution permet de la même manière
de déterminer dans quel état était la ligne.
Flush+Flush~\cite{flushflush} propose la méthode suivante :

\begin{algorithm}[ht]
  \caption{Flush+Flush}\label{alg:flushflush}
  \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 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 à Flush+Reload 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 \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

  \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ées,
qui occupent les mêmes zones de la mémoire physique pour différents processus.

Daniel Gruss et al.~\cite{cachetemplateattacks} proposent 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.

\

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 \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.
Mais la connaissance des coeurs attaquant et victime et de la \ang{slice} de la ligne surveillée
permettent potentiellement une meilleure précision.

\label{nonprivilegedinfo} Dans un scénario réel,
l'attaquant peut choisir le coeur sur lequel il s'exécute,
a accès au coeur sur lequel le processus victime s'exécute via \texttt{/proc/pid}.
La \ang{slice} peut-être trouvée en utilisant l'adresse physique mais cette information demande
généralement des privilèges qu'un attaquant n'aura pas. En revanche, si la fonction de hachage
est linéaire -- ce qui est le cas si le nombre de coeurs
est une puissance de 2 (\ref{poweroftwo}) --
il est possible de définir une classe d'équivalence des adresses des pages qui appartiennent aux
mêmes \ang{slices}. Une connaissance fine d'éléments dépendants du numéro de \ang{slice} -- comme
le temps d'exécution de \texttt{clflush} dans certaines conditions -- permettrait alors
de déterminer la \ang{slice}.

\section{Motivation}

Guillaume \textsc{Didier} et Clémentine
\textsc{Maurice}~\cite{calibrationdoneright} proposent une rétro-ingénierie des
messages échangés en fonction de l'état de cohérence des lignes
évincées du cache. Cela passe par l'étude des sources de variabilité et permet de
mieux choisir un seuil propre à chaque combinaison attaquant/victime/\ang{slice}.

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

\section{Organisation des expériences}

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
  \item Micro-architecture antérieure à SkyLake\footnote{Le L3 n'est plus inclusif
    sur les processeurs serveur à partir de SkyLake et la topologie devient plus complexe}
\end{itemize}

Les machines suivantes ont donc été utilisées~\cite{g5k-nodes}

\begin{center}
  \begin{tabular}{|c||c|c|c|}
    \hline
    Nom & Nombre de coeurs & Processeur & Micro-architecture \\
    \hline
    rennes/roazhon11 & 16 & Xeon E5-2660 & Sandy Bridge \\
    rennes/roazhon12 & 16 & Xeon E5-2660 & Sandy Bridge \\
    rennes/parasilo & 16 & Xeon E5-2630 v3 & Haswell \\
    rennes/paravance & 16 & Xeon E5-2630 v3 & Haswell \\
    lyon/nova & 16 & Xeon E5-2620 v4 & Broadwell \\
    rennes/abacus2 & 16 & Xeon E5-2609 v4 & Broadwell \\
    \hline
  \end{tabular}
\end{center}

La prise de mesure consistait à relever pour un lot d'adresses
(chacune correspondant à une \ang{slice})
les temps d'exécution de l'instruction \texttt{clflush} pour toutes les paires de coeurs
et tous les états de cohérence possibles.

Initialement, le turbo était désactivé sur toutes les machines, la fréquence des coeurs était fixée
à la fréquence maximale en activant le mode "performance" via \texttt{cpufreq}.

Nous avons trouvé que:
\begin{itemize}
  \item Contrairement aux machine \ang{Intel Core}, le mode performance ne permet pas
    de fixer la fréquence de tous les coeurs à la fréquence maximale possible.
    Nous avons donc fixé la fréquence des coeurs à la fréquence minimale (généralement 400MHz) ;
  \item L'architecture \ang{NUMA} impliquant de déplacer les pages exploitées principalement par un
    processeur distant, les adresses physiques changeaient durant l'expérience, ce qui rendait
    tous les résultats complètement incohérents.
    Nous avons donc désactivé le \ang{NUMA balancing} via \texttt{numactl},
    ce qui peut se faire pour le processus courant sans privilèges\footnote{
      Il faudrait vérifier que cela fonctionne aussi pour les pages
      partagées comme les bibliothèques
    }.
  \item Nous avons également fixé la fréquence de l'\ang{uncore} via un MSR, mais cela n'a
    pas eu de grand impact sur la clarté des résultats.
\end{itemize}

Les fichiers de résultats bruts sont accessibles en ligne~\cite{g5k-results}.

\section{Analyse des résultats}

\begin{figure}[ht]
  \centering
  \includegraphics[width=0.5\textwidth]{low-core-count}
  \caption{Topologie LCC Haswell EP d'après~\cite{tuningXeon}}
\end{figure}

Les schémas de présentation d'Intel suggèrent une topologie en anneau, avec un CPU divisé en deux grandes parties.

\subsection{Questions génériques}

\subsubsection{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 façon suivante,
c'est la numérotation que nous utiliserons pour la suite:

\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 la méthode proposée pour un attaquant non-privilégié (\ref{nonprivilegedinfo}).
    Cela nécessite une connaissance préalable de la topologie ;
  \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.
\end{itemize}

\subsubsection{Coeurs fantômes}

Pour répondre à des demandes variées, \ang{Intel} base ses processeurs serveurs sur
trois tailles à compter de la micro-architecture Haswell:
\begin{itemize}
  \item LCC (\ang{Low Core Count}) : de 4 à 8 coeurs physiques pour
    la micro-architecture Haswell (jusqu'à 10 pour Broadwell)
  \item MCC (\ang{Medium Core Count}) : de 10 à 12 coeurs pour Haswell (12 à 14 pour Broadwell)
  \item HCC (\ang{High Core Count}) : de 14 à 18 coeurs pour Haswell (16 à 24 pour Broadwell)
\end{itemize}

Les machines que nous utiliserons sont uniquement basées sur la \ang{die} LCC, mais certaines
(les Broadwell à 8 coeurs par exemple) sont alors livrées avec des coeurs désactivés. La \ang{slice}
de cache L3 associée est alors désactivée également. Cela pose tout de même question sur la possibilité
de sauts supplémentaires dûs à ces coeurs manquants: quel est le coeur désactivé ? Est-ce le même
sur tous les processeurs du même modèle ? Quel est alors l'impact sur le temps d'exécution ?
Par la suite, nous avons étudié principalement les résultats de la machine \textit{paravance}
pour éviter ces questions et établir plus facilement un premier modèle.

\subsection{Topologie \ang{miss}}

\begin{figure}[ht]
  \centering
  \includegraphics[width=1\textwidth]{predicted-miss}
  \caption{durée prédite et réelle d'un cache \ang{miss} selon
  les différents paramètres (\textit{paravance})}
\end{figure}


Les résultats obtenus quand le \ang{socket} attaquant et victime diffèrent
suggèrent l'échange des messages suivants lors d'un \texttt{clflush} qui provoque un \ang{cache miss}:
\begin{enumerate}
  \item Le coeur attaquant contacte la \ang{slice} locale suivant \ref{figs:topology-miss}.
  \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}

\begin{figure}[H]
  \centering
  \includegraphics[width=0.7\textwidth]{pattern}
  \caption{trajet coeur attaquant $\rightarrow$ \ang{slice} locale}
  \label{figs:topology-miss}
\end{figure}

Ainsi, le chemin privilégié pour le trajet coeur attaquant $\rightarrow$ \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{Topologie \ang{hit} exclusif}

On peut diviser le \ang{hit} en deux grands cas :
\begin{itemize}
  \item L'attaquant et la victime sont dans la même \ang{socket}
  \item L'attaquant et la victime ne sont pas dans la même \ang{socket}
\end{itemize}

Initialement, le trajet de l'information est le même que dans le cas d'un \ang{miss},
et ce n'est qu'au moment où le message parvient au niveau de la \ang{slice} contenant
la ligne en cache que les choses changent. La \ang{slice} contacte alors le coeur victime,
et le message fait le chemin retour une fois la ligne de cache évincée.

\begin{figure}[H]
  \centering
  \includegraphics[width=0.4\textwidth]{miss-v-hit}
  \caption{Nombre de cache \ang{hit} et cache \ang{miss} selon
  la durée d'exécution de l'instruction \texttt{clflush}}
\end{figure}

Alors, on note une différence de coût significative entre un \ang{hit} local et un \ang{hit}
distant, dû au passage par le \ang{QPI}. Dans le cas où l'attaquant et la victime partagent la
même \ang{socket}, le coût d'un \ang{hit} devient alors généralement beaucoup
moins élevé que celui d'un \ang{miss} ; contrairement au comportement sur
des systèmes à une seule \ang{socket}.

\begin{figure}[H]
  \centering
  \includegraphics[width=0.79\textwidth]{predicted-remote-hit}
  \caption{durée prédite et réelle d'un cache \ang{hit} selon les différents paramètres
  (\textit{paravance})}
\end{figure}

Si ce modèle est assez proche des données, on comprend que celui-ci est loin d'être parfait.
La majeure difficulté dans l'établissement d'un modèle dans le cas d'un \ang{cache hit}
est la grande quantité de données : on ajoute une dépendance en une nouvelle variable, le
coeur victime, qui n'était pas prise en compte pour un \ang{miss}.
De plus, les différents facteurs sont ici difficiles à décorréler,
ce qui a rendu l'analyse plus chronophage.

\section{Conclusion}

Si nous n'avons pas pu trouver un modèle parfaitement cohérents
avec les résultats analysés pour une question de temps,
nous avons désormais une méthode pour prendre les mesures,
tout en maîtrisant les principales sources de bruit.

Plusieurs pistes se proposent alors pour continuer le travail présenté ici :
\begin{itemize}
  \item Affiner le modèle, qui nes't pas parfait sur les \ang{cache miss} et ne colle pas
    bien aux \ang{cache hit}. On pourrait ensuite voir comment celui-ci s'étend aux autres
    états de cohérrence de cache ;
  \item Clarifier les hypothèses avancées dans ce rapport en effectuant certaines vérifications :
    \texttt{numactl} permet-il bien de verrouiller les pages partagées ? Peut-on proposer une
    renumérotation automatique des slices ? Cela permettra de créer un modèle crédible d'attaquant ;
  \item Proposer une méthode de réassignation automatique des slices pour savoir depuis un
    utilisateur non privilégié la \ang{slice} d'une adresse virtuelle ;
  \item Réaliser l'attaque Flush+Flush sur des systèmes à 2 \ang{sockets}
\end{itemize}

%\TODO{Extension au Xeon SP, L3 non inclusif+topologie différente

%Extension aux nouveaux proc avec slice != 1/coeur}


\newpage{}
%\nocite{*}
\bibliographystyle{plain}
\bibliography{refs}


\newpage{}
\section*{Annexe}

\subsection*{Contexte du stage}

Ce stage a été effectué dans l'université de \textsc{Rennes} 1,
dans le laboratoire de l'\textsc{Irisa} (Institut de Recherche en Informatique
et Systèmes Aléatoires), l'un des plus grands laboratoires de recherche français dans le domaine
de l'informatique avec plus de 850 personnes.

Il accueille 7 départements et une quarantaine d'équipes, j'ai été encadré par deux chercheurs de
l'équipe \textsc{Taran} (Architectures matérielles spécialisées pour l’ère post loi-de-Moore ) : Guillaume \textsc{Didier} et Angeliki \textsc{Kritikakou}.
En discutant avec les autres membres de l'équipe, j'ai pu découvrir de loin des problématiques
liées aux FPGA, l'ISA RISC-V et l'injection de fautes notamment.

J'ai beaucoup apprécié l'ambiance générale et tout ce que j'ai dû comprendre pour avancer sur
ce sujet de recherche, mais j'ai regretté qu'il soit trop spécifique pour pouvoir demander des conseils
facilement autour d'une pause café.

\subsection*{Contributions de code}

Le code utilisé pour prendre les mesures a principalement été
réutilisé de travaux existants~\cite{dendrobates}.
J'y ai contribué en résolvant quelques problèmes liés aux machines utilisées, et en ajoutant un
exécutable limitant la fréquence de l'\ang{uncore}.

Le code que j'ai écrit ou auquel j'ai apporté des modifications consiste principalement en:

\begin{itemize}
  \item Toute la logique d'analyse des résultats, afin d'afficher les données qui m'intéressaient et de comprendre les relations. Il est disponible dans~\cite{dendrobates} \texttt{cache\_utils/*.py}
  \item Un environnement et un script pour déployer l'expérience automatiquement sur des noeuds de Grid'5000~\cite{g5k-results}
\end{itemize}

\subsection*{Remerciements}

Je remercie toute l'équipe \textsc{Taran}, Guillaume \textsc{Didier} et Angeliki
\textsc{Kritikakou} tout particulièrement pour leur accueil chaleureux au sein du
laboratoire de l'\textsc{Irisa}.
Je suis très reconnaissant pour toutes les connaissances et l'expérience acquises durant ce stage.

\

\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},
\textsc{Renater} and several Universities as well as other organizations (see \url{https://www.grid5000.fr} ).

\end{document}
