Intéressé par des cours d'informatique en ligne ?
Visitez mon nouveau site
https://www.yesik.it !
Au sens strict, User Mode Linux (UML) est un portage du noyau Linux vers Linux. L'idée peut sembler saugrenue au premier abord, mais ouvre des perspectives intéressantes en offrant la possibilité de démarrer un nouveau noyau comme un processus utilisateur ordinaire.
Vous l'avez compris, ce principe s'apparente à la notion de virtualisation tellement à la mode ces temps-ci. Comparativement à d'autres technologies comme Xen ou VMWare, UML a l'inconvénient de ne pouvoir lancer que des noyaux Linux. Pas d'autres OS. Par contre, une instance du noyau Linux lancée par UML tourne entièrement en mode utilisateur. Et n'exige pas d'avoir un noyau spécial sur la machine physique qui sert d'hôte. C'est pratique quand vous ne pouvez pas – ou ne voulez pas – installer un noyau spécifiquement patché pour faire tourner un système de virtualisation. Ou encore, comme c'est le cas avec mon portable, quand le hardware ne supporte pas ces solutions ou que vous ne voulez pas vous priver de fonctionnalités incompatibles comme la gestion d'énergie ACPI.
Dans cet article, nous allons faire nos premiers pas avec User Mode Linux en créant et démarrant notre toute première machine virtuelle UML. Il s'agira ici d'une machine virtuelle sous Debian/Lenny – sans accès au réseau.
Sommaire
Installation
Mon hôte (ma machine physique) est aussi une machine sous Debian. Et comme User Mode Linux est disponible dans le gestionnaire de paquets, l'installation à proprement parler se résume en une ligne:
sh# apt-get install user-mode-linux user-mode-linux-doc
Voilà, c'est tout! Fin? Non, pas tout à fait...
Démarrer le noyau
A strictement parler, l'installation d'UML est terminée. Désormais, vous pouvez utiliser la commande linux pour créer et démarrer une instance de machine virtuelle UML. Mais si vous essayez maintenant, vous aurez l'impression que quelque-chose manque. A juste titre:
sh$ linux Locating the bottom of the address space ... 0x0 Locating the top of the address space ... 0xc0000000 Core dump limits : soft - 0 hard - NONE Checking that ptrace can change system call numbers...OK Checking syscall emulation patch for ptrace...OK Checking advanced syscall emulation patch for ptrace...OK Checking for tmpfs mount on /dev/shm...OK Checking PROT_EXEC mmap in /dev/shm/...OK Checking for the skas3 patch in the host: - /proc/mm...not found: No such file or directory - PTRACE_FAULTINFO...not found - PTRACE_LDT...not found UML running in SKAS0 mode Linux version 2.6.26 (2.6.26) (root@lart) (gcc version 4.3.2 (Debian 4.3.2-1.1) ) #2 Thu Mar 11 18:42:19 UTC 2010 Built 1 zonelists in Zone order, mobility grouping on. Total pages: 8128 Kernel command line: root=98:0 PID hash table entries: 128 (order: 7, 512 bytes) Dentry cache hash table entries: 4096 (order: 2, 16384 bytes) Inode-cache hash table entries: 2048 (order: 1, 8192 bytes) Memory: 28492k available SLUB: Genslabs=12, HWalign=128, Order=0-3, MinObjects=0, CPUs=1, Nodes=1 Mount-cache hash table entries: 512 [...] Couldn't stat "root_fs" : err = 2 Failed to initialize ubd device 0 :Couldn't determine size of device's file registered taskstats version 1 VFS: Cannot open root device "98:0" or unknown-block(98,0) Please append a correct "root=" boot option; here are the available partitions: Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(98,0) EIP: 0073:[<b7f18410>] CPU: 0 Not tainted ESP: 007b:bff25894 EFLAGS: 00200246 Not tainted EAX: 00000000 EBX: 00003000 ECX: 00000013 EDX: 00003000 ESI: 00002ffc EDI: 0000003b EBP: bff25920 DS: 007b ES: 007b 09c67e7c: [<0809ef94>] notifier_call_chain+0x34/0x70 09c67ea0: [<08312f2a>] panic+0x71/0x104 09c67ebc: [<08049c03>] mount_block_root+0x15f/0x27f 09c67ef4: [<080e92e7>] sys_mknod+0x27/0x30 09c67f08: [<08049d7e>] mount_root+0x5b/0x60 09c67f1c: [<08049eb6>] prepare_namespace+0x133/0x17d 09c67f34: [<08049147>] kernel_init+0x92/0x290 09c67f50: [<0805878f>] tcp_congestion_default+0x0/0x13 09c67fa4: [<08080db8>] finish_task_switch+0x28/0x90 09c67fbc: [<08072e40>] run_kernel_thread+0x30/0x50 09c67fd8: [<08072e2f>] run_kernel_thread+0x1f/0x50 09c67fe4: [<0805f7bb>] new_thread_handler+0x6b/0xa0 09c67fe8: [<080490b5>] kernel_init+0x0/0x290 Segmentation fault
Ce premier test – bien que terminé par un segmentation fault – nous apprend que UML est correctement installé et fonctionne! En effet, si vous observez attentivement l'affichage vous noterez qu'une instance du noyau Linux 2.6 est bien démarrée. Remarquez aussi que j'ai utilisé cette commande sous un compte utilisateur (prompt se terminant par $).
Alors pourquoi ce plantage de la machine virtuelle? Et bien parce que pour démarrer une machine, vous avez besoin qu'elle soit équipée d'un système d'exploitation. Or, dans un système Unix-like, le noyau n'est qu'une partie de ce système. Il nous manque encore l'ensemble des utilitaires qui constituent le sytème de base. Pour parler plus trivialement, nous n'avons que la partie linux de la machine virtuelle GNU/Linux que nous tentons de lancer.
Installer un système de base
Création de la partition
Qui dit installer un système, dit créer une partition. Par contre, pour vous éviter de devoir monopoliser une partition réelle pour chaque machine virtuelle, UML peut utiliser divers supports pour servir de root filesystem. Le plus simple pour cette introduction sera de travailler sur un fichier image. Autrement dit, un fichier contenant l'image d'une partition linux. Une partition – pardon – un fichier de 300 méga-octets est très largement suffisant:
sh# mkdir uml-images sh# cd uml-images sh# dd if=/dev/zero of=lenny-image count=0 obs=1MB seek=300 0+0 records in 0+0 records out 0 bytes (0 B) copied, 1.8928e-05 s, 0.0 kB/s

300MB ou 0B?
J'attire votre attention sur la commande dd ci-dessus. Celle-ci indique 0 octet copié. Or j'ai demandé la création d'un fichier de 300 méga-octets. Et j'ai pourtant l'air content de moi...
L'explication s'appelle sparse file. En effet, certains systèmes de fichiers (dont ext3) permettent de créer des fichiers sans que ceux-ci n'utilisent réellement de place sur le disque tant que rien n'y est écrit. Vous pouvez le vérifier avec la commande ls -ls:
sh# ls -ls total 0 0 -rw-r--r-- 1 root root 300000000 2010-03-19 21:41 lenny-image
Remarquez comme mon fichier a pour taille logique 300000000 octets, alors que physiquement il n'occupe que 0 bloc d'espace disque. L'espace disque ne sera réellement occupé qu'au fur et à mesure des écritures sur le disque.
Maintenant que le fichier image est créé, il faut le formater. Comme n'importe quelle partition. Ici, je choisis de formater avec le système de fichier ext3:
sh# mkfs -t ext3 lenny-image 2fs 1.41.3 (12-Oct-2008) lenny-image is not a block special device. Proceed anyway? (y,n) y Filesystem label= OS type: Linux Block size=1024 (log=0) Fragment size=1024 (log=0) 73440 inodes, 292968 blocks 14648 blocks (5.00%) reserved for the super user First data block=1 Maximum filesystem blocks=67633152 36 block groups 8192 blocks per group, 8192 fragments per group 2040 inodes per group Superblock backups stored on blocks: 8193, 24577, 40961, 57345, 73729, 204801, 221185 Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 20 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override.
Installer le système de base

Installation
Sous Debian vous aurez besoin du paquet debootstrap pour ce qui suit. Si ce logiciel n'est pas déjà sur votre machine utilisez le gestionnaire de paquets de votre distribution pour procéder à l'installation.
sh# apt-get install debootstrap
Maintenant que nous disposons d'une partition prète à l'accueillir, reste à installer le système de base. Ici, ce sera un système GNU/Debian installé avec l'utilitaire Debian ad-hoc: debootstrap. debootstrap ne peut pas directement installer sur une image, c'est pourquoi il est nécessaire de d'abord monter l'image via un loop device:
sh# mount lenny-image /mnt -t ext3 -o loop
sh# debootstrap lenny /mnt http://10.129.36.102:9999/debian
[...]
I: Base system installed successfully.

Miroir, miroir...
L'installation par debootstrap nécessite de télécharger beaucoup de paquets. Je vous conseille donc d'utiliser un miroir local ou un cache apt. C'est cette dernière option que j'ai choisie dans l'exemple ci-dessus. En effet, sur ma machine http://10.129.36.102 tourne apt-cacher-ng.
Si vous préférez télécharger à partir d'un miroir officiel, vous modifierez la commande en conséquence:
sh# debootstrap lenny /mnt http://ftp.fr.debian.org/debian
Ceci dit, je ne peux que vous encourager à installer un cache apt pour réduire votre consommation en bande passante – et accessoirement la charge sur les miroirs officiels de Debian.
Post-installation
debootstrap étant entièrement automatique, certaines étapes liées à la configuration du nouveau système sont laissées à la charge de l'utilisateur en post-installation. Ici, nous nous contenterons:
- De changer le nom de la machine virtuelle (en modifiant le fichier /etc/hostname);
- De donner un mot de passe root (en utilisant la commande passwd);
- D'autoriser l'ouverture de session à partir de la console de démarrage d'UML (en modifiant les fichiers /etc/inittab et /etc/securetty).
Pour faire ces (petites) configurations, nous allons nous chrooter dans la partition. Ceci nous permettra d'agir comme si nous étions logué sur la machine:
sh# chroot /mnt sh# echo uml > /etc/hostname sh# passwd root Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully sh# perl -i -n -e ' print "0:2345:respawn:/sbin/getty 38400 tty0\n" if /1:.*tty1$/; print if not /^0:.*tty0/' /etc/inittab sh# perl -i -n -e ' print "tty0\n" if /^tty1$/; print if not /^tty0$/' /etc/securetty sh# exit # quitte chroot

perl -i
J'utilise ci-dessus perl pour modifier deux fichiers de configuration. Mon idée étant de pouvoir incorporer l'ensemble des étapes dans un script afin d'automatiser la configuration d'une machine virtuelle.
Mais si vous êtes allergiques à perl – et que vous préférez modifier les fichiers à la main voici le détail. Donc, tout d'abord, j'ajoute au fichier /etc/inittab la ligne suivante pour que le login soit possible sur la console 0 (la console 0 étant la console dans laquelle UML démarre – celle où s'affichent les messages du noyau):
0:2345:respawn:/sbin/getty 38400 tty0
De plus, sur un système Linux moderne, il est aussi nécessaire d'indiquer à partir de quels terminaux root peut se connecter. Or, par défaut, sous Debian, tty0 ne fait pas parti des terminaux autorisés. C'est pour y remédier que j'ajoute également une ligne contenant tty0 au fichier /etc/securetty.
La post-installation est maintenant terminée. Nous pouvons démonter la partition:
sh# umount /mnt
Démarrer la machine
Il est possible de passer à UML un certain nombre de paramètres au démarrage. En fait, le mécanisme mis en jeu est sensiblement le même que celui utilisé pour passer des paramètres de boot au noyau à partir d'un bootloader comme LILO ou GRUB.
Ainsi, pour indiquer à UML d'utiliser notre fichier image comme partition de démarrage, nous utiliserons l'option ubda=lenny-image. Je vais aussi utiliser plusieurs autres options histoire de vous familiariser avec:
- con=pts
- Cette option précise à UML d'attacher les terminaux de la machine virtuelle sur les pseudo-terminaux de la machine réelle. Je l'utilise ici, car, par défaut, UML attache un certain nombre de consoles sur des terminaux X. D'abord, ça m'énerve ces pop up qui surgissent quand je lance une machine virtuelle, mais surtout, ça pose des problèmes quand on lance une machine UML à partir d'une connexion à l'hôte distante (par ssh, par exemple).
- con0=fd:0,fd:1
- J'utilise une règle spéciale pour la console 0 qui sera attachée à l'entrée standard et à la sortie standard de la console dans laquelle la machine virtuelle a été lancée (en clair: la console virtuelle 0 sera la console réelle dans laquelle vous aurez lancé UML). Toujours pour la même raison: si je lance une machine UML à distance, je souhaite pouvoir me loguer dessus via le même terminal.
- umid=uml
- Cette option est juste un identifiant pour administrer la machine virtuelle à l'aide de uml_mconsole que nous verrons dans quelques instants. Si vous l'omettez, UML générera un identifiant aléatoire. L'utilisation de cette option est à ranger au chapitre des bonnes habitudes.
sh$ linux ubda=lenny-image con=pts con0=fd:0,fd:1 umid=uml
Locating the bottom of the address space ... 0x0
Locating the top of the address space ... 0xc0000000
Core dump limits :
soft - 0
hard - NONE
Checking that ptrace can change system call numbers...OK
Checking syscall emulation patch for ptrace...OK
Checking advanced syscall emulation patch for ptrace...OK
Checking for tmpfs mount on /dev/shm...OK
Checking PROT_EXEC mmap in /dev/shm/...OK
Checking for the skas3 patch in the host:
- /proc/mm...not found: No such file or directory
- PTRACE_FAULTINFO...not found
- PTRACE_LDT...not found
UML running in SKAS0 mode
Linux version 2.6.26 (2.6.26) (root@lart) (gcc version 4.3.2 (Debian 4.3.2-1.1) ) #2 Thu Mar 11 18:42:19 UTC 2010
[...]
Virtual console 1 assigned device '/dev/pts/6'
Virtual console 2 assigned device '/dev/pts/7'
Virtual console 3 assigned device '/dev/pts/8'
Virtual console 4 assigned device '/dev/pts/10'
Virtual console 5 assigned device '/dev/pts/11'
Virtual console 6 assigned device '/dev/pts/12'
Debian GNU/Linux 5.0 uml tty0
uml login:
Et voilà: vous avez démarré une machine virtuelle UML. J'insiste un peu, mais remarquez que j'ai lancé cette machine virtuelle en tant qu'utilisateur de la machine hôte. Mais je peux me connecter en administrateur à la machine virtuelle:
uml login: root Password: Last login: Mon Mar 22 18:13:07 UTC 2010 on tty0 Linux uml 2.6.26 #2 Thu Mar 11 18:42:19 UTC 2010 i686 Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. uml:~#

Piège:
Si vous n'êtes pas familier avec la notion de virtualisation, la situation peut sembler étrange: vous pouvez être root sur une machine lancée en tant qu'utilisateur.
Faille de sécurité? Escalade de privilège? Non: en fait vous êtes root, mais sur votre machine virtuelle. Et ce root n'est pas le même que le root de la machine hôte. Toute la subtilité est là. Autrement dit, vous pouvez faire tout ce que vous voulez de votre machine virtuelle – mais vous êtes limité dans vos actions sur l'hôte aux privilèges qu'y possède l'utilisateur qui a lancé la machine virtuelle.
Console d'administration
Avant de terminer, un mot sur uml_mconsole, la console d'administration. Celle-ci permet d'agir sur la machine virtuelle de l'extérieur de celle-ci. Par analogie, la console d'administration vous permet un peu de faire ce que vous pouvez faire dans le monde réel avec une machine physique, comme appuyer sur le bouton marche/arrêt ou installer une nouvelle carte réseau. A ceci prêt que vous pouvez agir à chaud sur la machine:
sh$ uml_mconsole uml
(uml) help
OK Commands:
version - Get kernel version
help - Print this message
halt - Halt UML
reboot - Reboot UML
config <dev>=<config> - Add a new device to UML;
same syntax as command line
config <dev> - Query the configuration of a device
remove <dev> - Remove a device from UML
sysrq <letter> - Performs the SysRq action controlled by the letter
cad - invoke the Ctrl-Alt-Del handler
stop - pause the UML; it will do nothing until it receives a 'go'
go - continue the UML after a 'stop'
log <string> - make UML enter <string> into the kernel log
proc <file> - returns the contents of the UML's /proc/<file>
stack <pid> - returns the stack of the specified pid
Additional local mconsole commands:
quit - Quit mconsole
switch <socket-name> - Switch control to the given machine
log -f <filename> - use contents of <filename> as UML log messages
mconsole-version - version of this mconsole program
int - Interrupt UML session

Piège:
uml_mconsole est à utiliser à partir d'une console de la machine hôte! Pas à partir d'une console de la machine virtuelle.
Pour essayer la console d'administration, vous pouvez par exemple rebooter la machine:
(uml) reboot OK
Si vous avez sous les yeux la console de la machine virtuelle, vous constaterez qu'après avoir tapé cette commande, la machine virtuelle redémarre comme si vous aviez appuyé sur le bouton reset d'une machine physique.
Conclusion
Ce rapide tour d'horizon est terminé. La machine virtuelle que nous avons installée est totalement utilisable. Bien qu'isolée du réseau – et de son hôte – pour l'instant. Je vous encourage à jouer un peu avec, pour vous familiariser avec UML. Ou plutôt pour bien vous rendre compte que cette machine virtuelle se comporte presqu'en tout point comme une machine réelle.
Ressources
- (en) Jeff Dike. User Mode Linux (livre). Prentice Hall, 2006. ISBN 0-131-86505-6.
- (en) http://wiki.debian.org/Debootstrap
- (en) http://user-mode-linux.sourceforge.net/configure.html
- (fr) http://www.us.debian.org/releases/lenny/i386/apds03.html.fr