User Mode Linux

Condividi:

UML è un sistema di virtualizzazione di linux comparso come patch del kernel dalle versioni 2.2 del sistema operativo, che è stato poi integrato nello sviluppo del kernel di linux dalla versione 2.6.

Permette di eseguire un sistema operativo completo in user space come una macchina virtuale a cui assegnare varie risorse (drive, schede di rete, console, ecc…) ed è utile per virtualizzare macchine linux complete oppure per testare diverse versioni di kernel, driver, programmi ecc… all’interno di un sistema isolato che non può intaccare l’host che esegue uml.

E’ possibile eseguire varie macchine uml contemporaneamente simulando varie topologie di rete, implementare honetpots, testare la sicurezza di reti ecc…

Il sistema da eseguire è tutto contenuto in un root file system che viene montato da uml alla partenza. Può essere contenuto in un uno o più file separati il cui contenuto può essere popolato e modificato tramite script prima dell’esecuzione del binario uml in modo da automatizzare la pubblicazione di macchine virtuali. Insomma le possibilità sono davvero numerevoli.

Nota: Non funziona su raspberry, perchè il processore arm non è dotato delle caratteristiche hardware necessarie per la virtualizzazione, funziona di sicuro su architetture x86 e x86_64.

1 – Installazione
1.1 – Via semplice

Installiamo il pacchetto uml della distribuzione (debian o ubuntu):

L’eseguibile del kernel viene installato in /usr/bin/linux

1.2 – Via meno semplice

Abbiamo bisogno di alcuni strumenti per la compilazione del kernel che se non presenti vanno installati:

  • gcc
  • make
  • bc
  • libncurses5-dev

Per prima cosa scarichiamo da www.kernel.org l’archivio contenente la versione del kernel in esecuzione sull’host:

A meno di issue note, è possibile eseguire qualunque kernel guest all’interno di un kernel host, ma per non incorrere inutilmente in problemi si fa prima ad utilizzare la stessa versione.

Ora configuriamo e compiliamo il kernel. E’ indispensabile specificare sempre l’architettura del kernel che compiliamo inserendo ARCH=um

Possiamo modificare le impostazioni di default del kernel, ma non è necessario. In alternativa a config si può usare menuconfig per una configurazione tramite menù in console oppure xconfig se siamo in una console grafica.

Eseguiamo la compilazione.

Terminata la compilazione abbiamo a disposizione l’eseguibile ./linux che è il nostro kernel da eseguire da riga di comando.

2 – Installazione delle utilities

Sia che abbiamo installato l’eseguibile uml, sia che ce lo siamo compilato, ci serviranno le uml utilities, in insieme di programmi di contorno che vengono richiesti per l’esecuzione delle virtual machines.

2.1 – Pacchetto deb precompilato

2.2 – Compilazione da codice sorgente

2.3 – Note

Potrebbe esserci un problema con il pacchetto uml_utilities per cui alla fine del boot di una VM non viene trovato il programma port-helper compromettendo l’avvio degli xterms.

port-helper è presente in /usr/lib64/uml ma questa directory non è presente nella variabile PATH.

Per ovviare al problema si può aggiungere la directory nella variabile PATH per tutti gli utenti:

In alternativa si può creare un link simbolico che punta a quel file in /usr/local/bin:

3 – Creazione di un root filesystem

Da qui possiamo eseguire uml come un normale utente, per la creazione del root filesystem utilizzeremo un file vuoto che popoleremo con debootstrap che va installato:

Il root filesystem per un sistema debian minimale occupa qualche centinaio di mega, in questo esempio ne creeremo uno da 400M:

Non appena debootstrap termina di installare i pacchetti della debian stable, nella cartella ./umlroot potremo vedere un sistema linux completo.

Per prima cosa dobbiamo impostare la password di root di questo sistema, cosa che può essere fatta facilmente utilizzando passwd montando la cartella umlroot in charoot:

Ora dobbiamo impostare il nome della macchina uml, ad esempio uml-00:

Impostiamo anche fstab in modo da non avere / montato read-only

Timezone, locales …

Usciamo da chroot e smontiamo il root filesistem:

4 – Esecuzione del sistema uml
4.1 – Avvio di una VM in ambiente grafico

Se ci troviamo in un ambiente grafico possiamo eseguire la VM senza specificare nessuna console ed alla fine del processo di boot verranno aperti alcuni xterm collegati alle virtual console tty mostrate nel log di boot.

4.2 – Avvio di una VM in console

Se non siamo in un ambiente grafico invece, dovremo specificare su quali console, linee seriali ecc vogliamo collegarci per fare login.

Eseguiamo il sistema appena configurato assegnandogli 512M di memoria ram e mappando tutte le console con gli pseudo terminali dell’ host:

5 – Login

Normalmente se siamo in un ambiente grafico ogni virtual console viene presentata in un xterm. E’ possibile configurare delle linee seriali, delle console oppure configurare interfacce di rete per accedere alla macchina uml.

In questo esempio abbiamo avviato la VM da una semplice console configurando delle interfacce con che vengono mappate con i dispositivi /dev/pts/* disponibili nell’ host.

Appena la macchina uml finisce di fare il boot, gli ultimi messaggi ci comunicano come vengono mappati i device pts:

Aprendo un’altra console nell’ host possiamo accedere agli pseudo terminali tramite screen, minicom ecc:

oppure

Possiamo effettuare il login e finire di configurare la macchina uml, tutte le modifiche rimarranno salvate nel file uml-00-root

6 – Utilizzare più virtual block devices

Le partizioni vengono viste all’interno di uml come device chiamati /dev/udb* dove il primo è /dev/udba.

Quando eseguiamo uml montiamo il root filesystem su questo block device tramite questa opzione:

Avendo a disposizione altri file possiamo far si che il sistema li veda in altre partizioni ( ubdb, ubdc, … ) e montarle correttamente all’avvio inserendo le voci corrispondenti nel file /etc/fstab.

Costruiamo ad esempio un sistema con due file, uml-01-root da 256 M che conterrà / ed uml-01-var da 128 M che conterrà la cartella /var

Li monteremo nella cartella ./umlroot prima di lanciare debootstrap in modo che questo inserisca tutti i file nella cartella /var del rootfilesystem, dopodichè editeremo il file /etc/fstab.

Molti passaggi sono identici all’esempio precedente:

All’ interno di chroot dopo aver impostato password ed hostname, definiamo come montare le due partizioni inserendo le due righe in /etc/fstab

Smontiamo i due file

Eseguiamo il login come nell’esempio precedente:

7 – Networking

UML mette a disposizione diversi tipi di transport con cui configurare un’interfaccia di rete:

  • ethertap
  • tuntap
  • slip
  • slirp
  • pcap
  • daemon
  • multicast

tuntap, ethertap, slip e slirp si usano per realizzare scambi di pacchetti ip tra la VM e l’host, che può essere configurato come un router per ridirezionarli verso l’esterno o verso altre VM.

pcap è un transport di solo ascolto, è utile per realizzare sniffer e analizzatori di traffico.

multicast e daemon sono utili per realizzare reti virtuali tra VM, la rete rimane completamente scollegata dalle altre interfacce a meno che una delle VM faccia da gateway per la rete.

Nel sistema host impostiamo un’interfaccia virtuale tuntap per avere un collegamento point-to-point tra l’host e la virtual machine assegnandole un indirizzo:

Abilitiamo anche l’inoltro dei pacchetti tra questa interfaccia ( tap0 ) e quella collegata ad internet ( nel mio host enp0s3 ) altrimenti la comunicazione sarebbe limitata unicamente alla rete formata da host e macchina virtuale:

Avviamo la macchina virtuale impostando l’interfaccia eth0 impostando passando i paramentri tuntap come transport, tap0 e l’indirizzo di tap0:

Una volta avviata la vm ed effettuato il login possiamo configurare l’interfaccia eth0.

Verifichiamo innanzi tutto la presenza del device:

Ora possiamo configurare eth0 assegnando indirizzo e routing table:

Verifica:

La VM comunica con se stessa, con l’host e con internet:

Siamo in grado di aggiornare il sistema ed installare pacchetti con apt, avviare servizi accessibili dalla rete in cui è collegata la VM ecc..

Per rendere permanente la configurazione di rete dell’interfaccia eth0 inseriamo le informazioni nel file /etc/network/interfaces:

8 – Swap

Assegnamo dello spazio di swap alla VM:

Effettuiamo login e verifichiamo la presenza di /dev/ubdb:

Attiviamo lo swap:

Si può montare a partizione di swap al boot della VM, ricordarsi poi di passare sempre il parametro ubdb=… quando la si avvia altrimenti init inizierà a cercare un device che non esiste.

 9 – Condividere filesystem tra VM

Per risparmiare spazio nell’ host, UML mette a disposizione un sistema per creare i virtual block device ( ubda, ubdb, … ) tramite due file, uno in cui scrivere le modifiche ( il cowfile ) ed uno condiviso che viene montato read-only ( sharedfile che può essere il root file system ).

La sintassi è la seguente:

Utilizzando la VM uml-01, creaiamo 4 cow files (2 per la root e 2 per var):

I file appena creati sono molto più piccoli del root file system a cui fanno riferimento e si può essere tratti in inganno facendo un semplice ls -lh:

Sembra che occupino 257M ma essendo sparse file, la loro dimensione reale è molto minore, come mostra una lettura più attenta:

In realtà, non avendo delta da memorizzare, occupano solo 12K. In due diverse console, avviamo le VM in cui modificheremo gli hostname:

Effettuiamo login in altre 2 console ( utilizzando i /dev/pts/* mostrati nei messaggi di boot delle due VM ) e modifichiamo l’hostname:

Nell’ host possiamo verificare che i cowfile sono stati modificati passando da 12K a 208K e 168K:

Se la avviamo di nuovo le due VM con i due cowfile tra i messaggi di boot vediamo che gli hostname sono cambiati:

Cowfiles e Sharedfiles sono strettamente legati, se ora avviamo la VM come nei primi esempi senza cowfile, corromperemo questa relazione. Avviamo la VM senza cowfile, facciamo login e shutdown:

Tra i messaggi di boot notiamo che l’hostname è ancora quello originale:

Ora avviamo con i cowfiles:

Notiamo che la VM non si avvia mostrando diversi errori di questo tipo:

Non possiamo più utilizzare i vecchi cowfiles ed abbiamo perso le modifiche che contengono, quindi attenzione :=)

10 – Accesso alle risorse host

UML mette a disposizione il filesystem della macchina host attraverso il mount type hostfs, cosa molto utile per scambiare files. I permessi vengono ereditati dall’utente che ha avviato la VM quindi a meno che non stiamo utilizzando la VM come root, non è possibile fare danni nell’ host.

Dentro la VM:

11 – Aumentare lo spazio disco

E’ possibile aumentare lo spazio in un virtual block device aggiungendo spazio nel file utilizzato.

Ad esempio nell’ host abbiamo il root filesystem si 256M:

Aggiungiamo 0 alla fine del file, partendo dalla file (seek=256 con blocchi da 1024K) per aòtrettanti 256M (count=256):

Ora avviamo la VM, facciamo login e ridimensioniamo il file system del device /dev/ubda:

Riferimenti