Virtualizzazioni in Linux (Parte 1 - User Mode Linux)
by admin on Oct.19, 2010, under Hacking, Linux
Inizia con questo articolo una miniserie riguardante varie tecnologie di virtualizzazione disponibili sotto Linux.
User Mode Linux (UML) esegue un intero Linux system come un processo in userspace . Cio implica che il crash dell’ OS ospite in UML non influenza il sistema ospitante. In tal modo l’isolamento è garantito.
Passo per passo vedremo come:
- preparare una Ubuntu come OS ospite per eseguirvi UML
- creare una Debian Etch guest OS image
- mandare in esecuzione l’ OS ospite sotto UML
- Sarà necessario innanzitutto installare l’ UML kernel e relative utilities sull’ OS ospitante.
# apt-get install user-mode-linux uml-utilities debootstrap
user-mode-linux contiene il binario userspace chiamato “linux”, che è il linux kernel eseguibile in userspace. Al momento in cui scrivo, su Ubuntu 10.04.1, la versione del kernel UML disponibile è la 2.6.32. Il package uml-utilities mette a disposizione le utilities necessarie a gestire l’OS in UML sulla macchina che lo ospita.
Avremo bisogno di debootstrap se intendiamo costruire un completo sistema base del Debian OS ospite.
Di seguito, dovremo creare il rootfs image file che sarà usato per accogliere l’ OS ospite.
# dd if=/dev/zero of=my-uml.rootfs bs=1M seek=4096 count=0
# mkfs.ext3 -F my-uml.rootfs
mke2fs 1.41.11 (14-Mar-2010)
warning: Unable to get device geometry for my-uml.rootfs
Etichetta del filesystem=
Tipo SO: Linux
Dimensione blocco=4096 (log=2)
Dimensione frammento=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
262144 inode, 1048576 blocchi
52428 blocchi (5.00%) riservati per l'utente root
Primo blocco dati=0
Maximum filesystem blocks=1073741824
32 gruppi di blocchi
32768 blocchi per gruppo, 32768 frammenti per gruppo
8192 inode per gruppo
Backup del superblocco salvati nei blocchi:
32768, 98304, 163840, 229376, 294912, 819200, 884736
...
Nell’ esempio precedente, una disk image di 4GB (my-uml.rootfs) viene creata e formattata come ext3.
Se si desiderasse una disk image più ampia occorrerebbe intervenire sul parametro seek, ad esempio seek=16384 per una image di 16GB.
Desiderando invece un filesystem ext2, basterebbe specificare mkfs.ext2 invece di mkfs.ext3.
Quindi, creeremo un file image di 512MB (my-uml.swapfs), per la partizione di swap nell’ hosting OS.
# dd if=/dev/zero of=my-uml.swapfs bs=1M count=512
512+0 records in
512+0 records out
536870912 bytes (537 MB) copied, 6,28842 s, 85,4 MB/s
# mkswap my-uml.swapfs
mkswap: my-uml.swapfs: warning: don't erase bootbits sectors
on whole disk. Use -f to force.
Setting up swapspace version 1, size = 524284 KiB
no label, UUID=e8164ec5-6fcd-41f4-ac09-c2fa16a16ba0
Una volta che la disk image sia stata creata, vi verrà installato il sistema di base.
Pertanto, sarà necessario creare il punto di mount /mnt/uml per montarvi la rootfs image:
# export MOUNT=/mnt/uml
# mkdir -p $MOUNT
# mount -o loop my-uml.rootfs $MOUNT
Quindi invocare debootstrap per installare un sistema Debian base nella rootfs.
# debootstrap --include=ssh,udev lenny $MOUNT ftp://ftp.debian.org/debian/
I: Retrieving Release
I: Retrieving Packages
I: Validating Packages
I: Resolving dependencies of required packages...
I: Resolving dependencies of base packages...
I: Found additional base dependencies: libedit2 libkeyutils1 libkrb53 libvolume-id0 openssh-blacklist openssh-client openssh-server
I: Checking component main on ftp://ftp.debian.org/debian...
I: Retrieving libacl1
I: Validating libacl1
[...]
I: Configuring ssh…
I: Configuring aptitude…
I: Configuring tasksel-data…
I: Configuring tasksel…
I: Base system installed successfully.
Verrebbero così installati i packages base Debian Lenny nel rootfs insieme a ssh ed udev.
Nell’esempio precedente, l’eseguibile debootstrap ha effettuato il download e l’ installazione dei packages di base da ftp.debian.org.
A questo punto, si rende necessario un setup manuale dell’ OS ospitante. Pertanto dovremo impostare network interface, hostname, timezone, fstab e root password.
Imposteremo la network interface modificando $MOUNT/etc/network/interfaces, ad esempio:
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 192.168.1.33
netmask 255.255.255.0
broadcast 192.168.1.255
gateway 192.168.1.1
# export HOST_NAME="umlhost"
# echo "$HOST_NAME" > $MOUNT/etc/hostname
Per quanto riguarda $MOUNT/etc/timezone e localtime, trovandoci in Italia, creeremo un link /etc/localtime a /usr/share/zoneinfo/Europe/Rome:
# export TZ=Europe/Rome
# echo $TZ > $MOUNT/etc/timezone
# rm -f $MOUNT/etc/localtime
# ln -sf /usr/share/zoneinfo/$TZ $MOUNT/etc/localtime
Impostando $MOUNT/etc/fstab, occorre considerare che i disk devices UML sotto udev sono ubda, ubdb, ecc. Non usando udev, sarebbero ubd1, ubd2, ecc.
Pertanto la rootfs image risultera essere /dev/ubda e sarà montata come / mentre la swap image risulterà essere /dev/ubdb.
# vi $MOUNT/etc/fstab
/dev/ubd0 / ext3 defaults 0 1
/dev/ubd1 none swap sw 0 0
none /proc proc defaults 0 0
none /dev/shm tmpfs
defaults 0 0
Occorre quindi impostare la password di root per l’OS ospite.
# chroot $MOUNT passwd
NOTA: Non utilizzando udev occorrerà anche creare i device node ubd[0-7]:
# chroot $MOUNT rm /dev/ubd*
# chroot $MOUNT mknod /dev/ubd0 b 98 0
# chroot $MOUNT mknod /dev/ubd1 b 98 16
# chroot $MOUNT mknod /dev/ubd2 b 98 32
# chroot $MOUNT mknod /dev/ubd3 b 98 48
# chroot $MOUNT mknod /dev/ubd4 b 98 64
# chroot $MOUNT mknod /dev/ubd5 b 98 80
# chroot $MOUNT mknod /dev/ubd6 b 98 96
# chroot $MOUNT mknod /dev/ubd7 b 98 112
Infine, installeremo i moduli kernel UML. debootstrap non installa il kernel dal momento che utilizza il kernel uml. Tuttavia potrebbe essere necessario qualche modulo kernel nell’ OS ospite (ad es. per montare nfs o smbfs). Dal momento che il package UML viene fornito con i moduli kernel UML, si può copiarli nell’OS ospite.
# cp -Rp /usr/lib/uml/modules/* $MOUNT/lib/modules/
I moduli si trovano ora installati in /usr/lib/uml/modules/.
Un modo alternativo di averli a disposizione dall’interno di UML consiste nell’utilizzare hostfs, ad es:
# echo "hostfs /lib/modules hostfs /usr/lib/uml/modules 0 0" >> $MOUNT/etc/fstab
Desiderando migliori performance per l’OS ospite UML, si può indicare ad UML di utilizzare tmpfs.
Per allocare ad esempio 1G di ram disk e montarlo su /tmp/uml.
# mkdir /tmp/uml
e poi editare /etc/fstab sull’ host ospitante
# vi /etc/fstab tmpfs /tmp/uml tmpfs defaults,size=1024M 0 0
eseguendo quindi “mount -a” per attivarlo.
3. Avvio dell’ OS ospite con UML
Per prima cosa smontiamo il rootfs.
# umount $MOUNT
Ora è possibile mandare in esecuzione (come root) l’ OS ospite. Assumendo che rootfs e swap disk image si trovino nella directory corrente:
# TMPDIR=/tmp/uml linux root=/dev/ubda ubd0=my-uml.rootfs ubd1=my-uml.swapfs mem=256M con=pts con0=fd:0,fd:1 eth0=tuntap,,,192.168.1.88 umid=umlhost 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 /tmp/uml/...OK Checking for the skas3 patch in the host: ... INIT: Entering runlevel: 2 Starting system log daemon: syslogd. Starting kernel log daemon: klogd. ...
L’ esempio precedente avvia l’OS ospite sotto UML con 256MB di ram, usando my-uml.rootfs come partizione root e my-uml.swapfs come partizione di swap. L’interfaccia di rete viene configurata com eth0 ed utilizza tuntap per stabilire un tunnel tra l’ OS host (192.168.1.88) e quello ospite (192.168.1.33).
Dopo aver lanciato il comando, dovreste osservare nel terminale qualcosa di simile alla abituale sequenza di boot del kernel linux. Dopo che tutti i demoni di servizio sono stati avviati, la sessione sul terminale risulta bloccata, ma si può utilizzare ssh per effettuare il login. In tal caso, potremo accedere all’ OS ospite impartendo semplicemente:
$ ssh root@192.168.1.33
The authenticity of host '192.168.1.33 (192.168.1.33)' can't be established. RSA key fingerprint is c9:c6:17:58:09:8e:4b:36:ce:2e:f4:5c:5e:f9:14:65. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.1.33' (RSA) to the list of known hosts.
root@192.168.1.33's password:
Linux umlhost 2.6.32.15+drm33.5 #2 Tue Aug 17 06:09:58 UTC 2010 i686
[...]
umlhost:~#
Dal punto di vista del networking, se lo vediamo dal lato host abbiamo:
# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.1.33 0.0.0.0 255.255.255.255 UH 0 0 0 tap0
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
169.254.0.0 0.0.0.0 255.255.0.0 U 1000 0 0 eth0
0.0.0.0 192.168.1.1 0.0.0.0 UG 100 0 0 eth0
# ifconfig tap0
tap0 Link encap:Ethernet HWaddr f2:e6:0a:0b:3d:e2
inet addr:192.168.1.88 Bcast:192.168.1.255 Mask:255.255.255.255
inet6 addr: fe80::f0e6:aff:fe0b:3de2/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:26 errors:0 dropped:0 overruns:0 frame:0
TX packets:52 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
RX bytes:3641 (3.6 KB) TX bytes:7350 (7.3 KB)
Per terminare l’ OS ospite nell’ OS host, si può usare la uml utility mconsole;
# uml_mconsole umlhost sysrq s; \
uml_mconsole umlhost sysrq u; \
uml_mconsole umlhost sysrq e; \
uml_mconsole umlhost halt
Per motivi di sicurezza non bisognerebbe eseguire l’OS ospite UML come root. Pertanto sarà opportuno creare un utente uml ed aggiungerlo al gruppo uml-net.
# useradd -m uml
# adduser uml uml-net
# chown uml:uml-net my-uml.rootfs my-uml.swapfs
In modo da poter mandare in esecuzione l’ OS ospite come utente locale non-privilegiato:
# su uml -c \
"TMPDIR=/tmp/uml linux root=/dev/ubda ubd0=my-uml.rootfs ubd1=my-uml.swapfs mem=256M con=pts con0=fd:0,fd:1 eth0=tuntap,,,192.168.1.88 umid=umlhost"
Volendolo eseguire come daemon, si può usare il comando screen:
# screen -S $SESSION -d -m su uml -c \
"TMPDIR=/tmp/uml linux root=/dev/ubda ubd0=my-uml.rootfs ubd1=my-uml.swapfs mem=256M con=pts con0=fd:0,fd:1 eth0=tuntap,,,192.168.1.88 umid=umlhost"

