Objectif du document

publicité
Titre
Propriétaire
Classification
Date dernière
modification
Chemin et NomFichier
Isolation des VMs (ViSaG)
Penas Cédric
Public
19.12.11
\\10.1.1.2\Doc_Labo\Penas\ViSaG\isolation_vm.doc
Objectif du document
Analyser le comportement d’une VM lors d’accès RAM avec du code (C/Assembleur) afin d’essayer
de déterminer si le niveau de sécurité au niveau de l’isolation entre les VMs est vraiment garanti
comme VMware l’affirme.
4 objectifs atteints avec ce document :
1. Persistance des données en RAM
2. Connaître le niveau de privilège de la VM
3. Adressage RAM (VMM)
4. Test d’instructions nécessitant le RING0
Le code source produit la VM suivante :
HEPIA – Labo de transmission de données -1-
Initiales / 19-09-2011
Contexte
Utilisation du travail de Christian Abegg portant sur l’étude bas niveau de la mémoire et sur la porte
dérobée de VMware1.
Pour résumé, il s’agit d’utiliser le projet SOS2 (Simple Operating System) afin de disposer d’un noyau
minimal de système d’exploitation qui est censé me donner un accès non restreint aux ressources
physiques.
Ce noyau sera installé dans une VM et permettra de booter sur le code C que j’aurais écrit.
Détails de la VM (sans OS) :
Fichiers utiles
1. Ce rapport :
http://www.tdeig.ch/visag/sos/SOS_Rapport.pdf
2. VM Ubuntu contenant les codes source + script de déploiement :
http://www.tdeig.ch/visag/sos/ova/Ubuntu.ova
3. VM SOS
http://www.tdeig.ch/visag/sos/SOS.ova
4. Code source Abegg modifi par Penas
http://www.tdeig.ch/visag/sos/SOS_penas.tar.gz
1
http://www.tdeig.ch/vmware/Abegg_R.pdf
http://sos.enix.org
HEPIA – Labo de transmission de données -22
Initiales / 19-09-2011
Utilisation
Pour pouvoir compiler mon code source et l’exécuter, il faut un ESXi 4.0 prêt à l’emploi. Il faudra
ensuite déployer les deux VMs de la section « Fichiers utiles » juste avant.
Dans l’ordre il faudra ensuite :
1. Lancer la VM Ubuntu
2. Exécuter le script de déploiement présent dans Bureau/SOS_penas/extra/deploiement.bash
(voir section suivante)
3. Lancer la VM SOS
Script de déploiement
Pour faciliter le processus de compilation et déploiement du projet sur un ESXi, j’ai réalisé un script
bash disponible dans SOS_penas/extra/deploiement.bash.
Exécution du script :
1. Prend l’IP du serveur ESXi en paramètre
2. Compile le projet afin de créer l’image bootable .img
3. Transfère cette image dans le datastore1 de l’ESXi
Exemple :
> cd SOS_penas/extra
> ./deploiement.bash 10.1.40.17
Attention : Il faut avoir activé le SSH sur le serveur pour que le script fonctionne correctement.
HEPIA – Labo de transmission de données -3-
Initiales / 19-09-2011
Objectif 1
Le premier objectif est repris du travail de Christian Abegg qui vise à montrer que la mémoire attribuée
à une VM est réinitialisée à chaque démarrage.
Pour faire cette démonstration, il a suffi de lire le contenu d’une partie de la mémoire et de l’afficher
puis écrire par-dessus. Ensuite, exécuter un redémarrage de la VM pour effectivement voir que la
mémoire est complétement réinitialisée.
Dans mon code source j’ai simplifié l’exemple d’Abegg en ne faisant une lecture/écriture que sur 2Mo
afin de pouvoir l’afficher sur une seule ligne.
Nous obtenons donc la première lecture au démarrage.
La lecture après l’écriture de motifs aléatoires.
Puis au redémarrage de la VM nous voyons que la mémoire est réinitialisée.
Les différents motifs verts représentent le pourcentage de bits à 1 dans la zone lue comme nous
pouvons le voir sur la légende ci-dessous.
HEPIA – Labo de transmission de données -4-
Initiales / 19-09-2011
Objectif 2
Le second objectif de cette étude, vise à trouver le moyen de savoir dans quel niveau de privilège
x863 nous nous trouvons dans la VM.
Logiquement cette information se trouve dans un registre du processeur. Pour savoir lequel, il faut se
4
plonger un peu dans la documentation INTEL x86 pour les développeurs .
5
J’ai trouvé le registre en question à la section 3.4.3 du document. Il s’agit du registre EFLAGS qui
possède 32 bits dans notre cas puisque nous sommes sur une architecture x86.
Il contient de nombreuses informations ou « flags » utiles comme l’overflow, la parité, le zéro etc…
mais ceux qui nous intéressent plus particulièrement, sont les bits 12 et 13.
3
http://en.wikipedia.org/wiki/Privilege_ring
http://www.intel.com/content/dam/doc/manual/64-ia-32-architectures-software-developer-manual325462.pdf
5
http://fr.wikipedia.org/wiki/EFLAGS
HEPIA – Labo de transmission de données -5Initiales / 19-09-2011
4
IOPL (bits 12 and 13)
“I/O privilege level field — indicates the I/O privilege level of the currently running program
or task. The current privilege level (CPL) of the currently running program or task must be less
than or equal to the I/O privilege level to access the I/O address space. This field can only be
modified by the POPF and IRET instructions when operating at a CPL of 0.”
Source: Intel Developer Manual
Il me faut donc accéder à ces deux bits via mon code en C. Pour se faire, je suis parti d’un exemple
6
C++ disponible sous Wikipédia qui utilise du code assembleur :
#include <iostream>
int main(void)
{
unsigned long long var_RFLAGS = 0;
__asm{
PUSHFQ; // pousse les 64 bits de RFLAGS sur la pile
POP var_RFLAGS; // met RFLAGS dans la variable var_RFLAGS
}
std::cout << std::hex << "Valeur du registre RFLAGS : 0x" <<
var_RFLAGS;
return 0;
}
Il m’a donc fallu l’adapter pour qu’il se compile correctement avec GCC. Ce qui nous donne :
unsigned int var_FLAGS = 0 ;
asm(" PUSHF ;") ;
asm(" POP %0 ;" : "=r"(var_FLAGS)) ;
Résultats
Ce code de 3 lignes nous permet donc de récupérer le registre FLAGS dans la variable var_FLAGS. Il
ne reste ensuite plus qu’à convertir les bits 12 et 13 pour trouver une valeur de 0 à 3.
Le screenshot suivant montre ce que j’obtiens dans la même VM que pour le test précédent.
Nous observons donc les bits suivants dans le registre :
0000 0000 0010 0000 0000 0010 0000 0110
6
http://fr.wikipedia.org/wiki/RFLAGS
HEPIA – Labo de transmission de données -6-
Initiales / 19-09-2011
Objectif 3
La troisième tâche que j’ai réalisée, est de tenter une écriture/lecture de la mémoire depuis la VM afin
de vérifier quel espace est effectivement accessible.
Le code qui réalise cette opération peut être résumé avec le pseudo code suivant :
for adresse=0 ; adresse<=LIMITE ; adresse+32768 do
pointeur = adresse
ecriture caractère ‘A’ => adresse
lecture de Pointeur => variable1
if variable1 == ‘A’
 Mémoire accessible
else
 Mémoire inaccessible
end if
end for
Pour le code C complet voir le fichier SOS_penas/sos/main.c
Le principe de parcours de la mémoire a été repris du code d’Abegg. Nous avançons donc par blocs
de 32768 octets jusqu’à atteindre la limite fixée.
Il suffit ensuite de simplement écrire à l’adresse courante puis de lire cette même adresse. Si ce que
nous lisons est ce que nous venons d’écrire, la mémoire est accessible.
Résultats
Pour mon test, étant donné que la VM que j’ai créée possède 64Mo de RAM, j’ai effectué une
écriture/lecture sur les 75'464'704 premiers octets de la mémoire.
Le résultat obtenu est bien celui qui était prévu, à savoir que nous ne pouvons pas sortir de l’espace
mémoire qui est attribué à la VM par l’hyperviseur.
1. Nous pouvons voir sur l’image ci-dessus que les 2 premiers Mo ne sont pas accessibles. Ceci est
dû à une protection manuelle placé par Abegg dans la fonction qui me permet d’écrire dans la
mémoire pour éviter d’écrire dans la mémoire vidéo ou le Bios de la VM.
HEPIA – Labo de transmission de données -7-
Initiales / 19-09-2011
Voir le fichier SOS_penas/laboesx/mémoire.c
if(baseaddr < 2200000)
return;
2. Ensuite la ligne verte représente tout l’espace mémoire attribué à la VM qui est logiquement
accessible.
3. Puis vient une dernière plage adresse que j’ai mise exprès en dehors des 64Mo pour justement
tester si le dépassement était possible. Ce qui n’est apparemment pas le cas et donc la conclusion de
notre 1er objectif.
Pour plus d’informations sur le fonctionnement de la mémoire dans le projet SOS, les 3 articles
suivants sont disponibles sur le site officiel :
1. Gestion de la mémoire physique
2. Gestion de la pagination
3. Gestion de la mémoire virtuelle du noyau
HEPIA – Labo de transmission de données -8-
Initiales / 19-09-2011
Objectif 4
Pour ce quatrième objectif, je me suis donné pour but de tester un peu le comportement de la VM
lorsque j’essaye d’utiliser des instructions nécessitant d’être en RING0.
Car le résultat obtenu à l’objectif 2 m’a tout d’abord semblé troublant étant donné que selon
l’architecture virtualisée de VMware, le VMM se trouve être en ring 0 et les VMs avec un RING plus
élevé.
J’en arrive donc à la première conclusion que nous nous trouvons dans le cas de la figure de droite de
l’image ci-dessus comme la fonctionnalité intel-vt est activée.
“In order to run one or more virtual machines safely on a single host, ESX must isolate the virtual
machines so that they cannot interfere with each other or with the VMkernel. In particular, it must
prevent the virtual machines from directly executing privileged instructions that could affect the state of
the physical machine as a whole. Instead, it must intercept such instructions and emulate them so
their effect is applied to the virtual machine’s hardware, not the physical machine’s hardware. For
example, issuing the reboot command in a virtual machine should reboot just that virtual machine, not
the entire host.”
Source: Software and Hardware Techniques for x86 Virtualization7
Test – SYSENTER/SYSEXIT :
Ces deux instructions permettent de basculer entre le mode « kernel » (RING0) et le mode utilisateur
(RING3). Etant donné que je suis déjà censé être en RING0, je n’ai aucune idée dans quelle mesure
je peux les utiliser mais j’ai décidé de faire quand même l’essai.
Le résultat obtenu était vraiment loin de celui attendu. VMware me renvoie le message d’erreur
suivant dès qu’une des deux instructions assembleur tente d’être exécutée :
7
http://www.vmware.com/files/pdf/software_hardware_tech_x86_virt.pdf
HEPIA – Labo de transmission de données -9-
Initiales / 19-09-2011
HEPIA – Labo de transmission de données -10-
Initiales / 19-09-2011
Problèmes rencontrés
1. Erreurs à la compilation (GRUB)
La première erreur que j’ai obtenue à la compilation, était due au fait qu’il faut GRUB en version 1 et
non en version 2 comme il est dans les versions récentes de Ubuntu.
Résolution : J’ai donc décidé de travailler sur une ancienne version d’Ubuntu  8.04 LTS
2. Erreur à la compilation (Paquets)
La seconde erreur obtenue était due à un paquet dont on a besoin qui manquait.
Résolution : Ne pas oublier d’installer le paquet « mtools »
3. Syntaxe du code assembleur
J’ai obtenu des erreurs de compilation de mon code C lorsque j’ai tenté d’utiliser du code trouvé sur
internet pour lire le registre FLAGS.
J’ai donc découvert par la même occasion que la fonction asm() qui nous permet d’exécuté du code
assembleur ne fait pas partie du langage C mais est un ajout propre à chaque compilateur. Il faut
donc respecté une syntaxe précise en fonction de celui qu’on utilise.
HEPIA – Labo de transmission de données -11-
Initiales / 19-09-2011
Téléchargement