Come iniziare a utilizzare la modalità utente in Linux
Introduzione del traduttore: Considerando il massiccio ingresso nelle nostre vite di contenitori di vario genere, può essere molto interessante e utile scoprire con quali tecnologie tutto è iniziato una volta. Alcuni di essi possono essere utilizzati utilmente fino ad oggi, ma non tutti ricordano tali metodi (o sanno se non sono stati colti durante il loro rapido sviluppo). Una di queste tecnologie è User Mode Linux. L'autore dell'originale ha scavato molto, cercando di capire quali dei vecchi sviluppi funzionano ancora e quali no, e ha messo insieme qualcosa come un'istruzione passo passo su come procurarsi un UML fatto in casa in 2k19. E sì, abbiamo invitato l'autore del post originale su Habr Cadey, quindi se hai domande, chiedi in inglese nei commenti.
La modalità utente in Linux è, infatti, un port del kernel Linux su se stesso. Questa modalità consente di eseguire un kernel Linux completo come processo utente ed è comunemente utilizzata dagli sviluppatori per testare i driver. Ma questa modalità è utile anche come strumento di isolamento generale, il cui principio è simile al funzionamento delle macchine virtuali. Questa modalità fornisce un maggiore isolamento rispetto a Docker, ma meno di una macchina virtuale a tutti gli effetti come KVM o Virtual Box.
In generale, la Modalità Utente può sembrare uno strumento strano e difficile da usare, ma ha comunque la sua utilità. Dopotutto, questo è un kernel Linux completo eseguito da un utente non privilegiato. Questa funzionalità consente l'esecuzione di codice potenzialmente non attendibile senza alcuna minaccia per il computer host. E poiché si tratta di un kernel a tutti gli effetti, i suoi processi sono isolati dalla macchina host i processi in esecuzione in modalità utente non saranno visibili all'host. Questo non è come il solito contenitore Docker, nel qual caso la macchina host vede sempre i processi all'interno del repository. Guarda questo pezzo di pstree da uno dei miei server:
E confronta questo con il pstree del kernel Linux in modalità utente:
linux─┬─5*[linux]
└─slirp
Quando lavoro con i contenitori Docker, posso vedere dall'host i nomi dei processi in esecuzione nel guest. Con la modalità utente Linux, questo non è possibile. Cosa significa? Ciò significa che gli strumenti di monitoraggio che vengono eseguiti attraverso il sottosistema di controllo di Linux non vedere processi in esecuzione nel sistema ospite. Ma in alcune situazioni, questa caratteristica può diventare un’arma a doppio taglio.
In generale, l'intero post seguente è una raccolta di ricerche e tentativi approssimativi per ottenere il risultato desiderato. Per fare questo, ho dovuto utilizzare vari strumenti antichi, leggere i sorgenti del kernel, eseguire un debug intenso del codice scritto ai tempi in cui ero ancora alle elementari e anche armeggiare con le build di Heroku utilizzando uno speciale binario per trovare gli strumenti di cui avevo bisogno . Tutto questo lavoro ha portato i ragazzi del mio IRC a chiamarmi magico. Spero che questo post serva come documentazione affidabile per qualcuno che possa provare la stessa cosa con kernel e versioni del sistema operativo più recenti.
registrazione
La configurazione della modalità utente Linux viene eseguita in diversi passaggi:
installazione delle dipendenze sull'host;
scaricare il kernel Linux;
configurazione della compilazione del kernel;
assemblaggio del nocciolo;
installazione binaria;
configurazione del file system ospite;
selezione dei parametri di avvio del kernel;
creazione di una rete ospite;
avviando il kernel guest.
Presumo che se decidi di farlo da solo, molto probabilmente farai tutto ciò che è descritto in qualche sistema simile a Ubuntu o Debian. Ho provato a implementare tutto quanto sopra nella mia distribuzione preferita, Alpine, ma non ne è venuto fuori nulla, apparentemente a causa del fatto che il kernel Linux ha un glibc-isms vincolante per i driver in modalità utente. Ho intenzione di segnalare questo a monte dopo aver finalmente compreso il problema.
Installazione delle dipendenze sull'host
Ubuntu richiede almeno i seguenti pacchetti per creare il kernel Linux (assumendo un'installazione pulita):
Tieni presente che l'esecuzione del programma di installazione del menu del kernel Linux richiederà l'installazione di libncurses-dev. Assicurati che sia installato con il seguente comando (come root o con sudo):
apt-get -y install libncurses-dev
Scaricamento del kernel
Decidi dove scaricare e poi costruisci il kernel. Per questa operazione dovrai allocare circa 1,3 GB di spazio su disco rigido, quindi assicurati di averlo.
Ora entriamo nella directory creata durante la decompressione del tarball:
cd linux-5.1.16
Configurazione della compilazione del kernel
Il sistema di compilazione del kernel è un set Makefile с molti strumenti e script personalizzati per automatizzare il processo. Innanzitutto, apri il programma di installazione interattivo:
make ARCH=um menuconfig
Costruirà e visualizzerà parzialmente una finestra di dialogo per te. Quando '[Select]', potrai effettuare la configurazione utilizzando i tasti Spazio o Invio. Naviga nella finestra, come al solito, con le frecce della tastiera "su" e "giù" e seleziona gli elementi "sinistra" o "destra".
Il puntatore di visualizzazione —> significa che ci si trova in un sottomenu, accessibile tramite il tasto Invio. La via d'uscita è ovviamente attraverso '[Exit]'.
Includi le seguenti opzioni in "[Select]' e assicurati che abbiano un '[*]' accanto a loro:
UML-specific Options:
- Host filesystem
Networking support (enable this to get the submenu to show up):
- Networking options:
- TCP/IP Networking
UML Network devices:
- Virtual network device
- SLiRP transport
Fatto, potete uscire da questa finestra selezionando successivamente '[Exit]'. Assicurati solo che ti venga chiesto di salvare la configurazione alla fine e seleziona "[Yes]'.
Ti consiglio di giocare con le opzioni di compilazione del kernel dopo aver letto questo post. Attraverso questi esperimenti, puoi imparare molto in termini di comprensione del lavoro della meccanica del kernel di basso livello e dell'impatto di vari flag sul suo assemblaggio.
Costruire il kernel
Il kernel Linux è un grande programma che fa molte cose. Anche con una configurazione così minima su un vecchio hardware, la creazione può richiedere parecchio tempo. Quindi costruisci il kernel con il seguente comando:
make ARCH=um -j$(nproc)
Per quello? Questo comando dirà al nostro builder di utilizzare tutti i core e thread della CPU disponibili nel processo di compilazione. Squadra $(nproc) alla fine di Build sostituisce l'output del comando nproc, di cui fa parte coreutils in una build Ubuntu standard.
Dopo un po' di tempo, il nostro kernel verrà compilato in un file eseguibile ./linux.
Installazione del binario
Poiché la modalità utente in Linux crea un file binario regolare, puoi installarlo come qualsiasi altra utility. Ecco come l'ho fatto:
mkdir -p ~/bin
cp linux ~/bin/linux
Vale anche la pena accertarsene ~/bin è nel tuo $PATH:
export PATH=$PATH:$HOME/bin
Configurazione del file system guest
Crea una directory per il file system guest:
mkdir -p $HOME/prefix/uml-demo
cd $HOME/prefix
Apri alpinelinux.org e accedi sezione download trovare il collegamento per il download effettivo MINI ROOT FILESYSTEM. Al momento in cui scrivo questo era:
Ora entriamo nella directory del file system guest ed estraiamo l'archivio:
cd uml-demo
tar xf ../alpine-rootfs.tgz
Le azioni descritte creeranno un piccolo modello di file system. A causa della natura del sistema, sarà estremamente difficile installare i pacchetti tramite il gestore apk Alpine. Ma questo FS sarà sufficiente per valutare l'idea generale.
Abbiamo anche bisogno di uno strumento tini per limitare il consumo di memoria processi zombie il nostro kernel ospite.
wget -O tini https://github.com/krallin/tini/releases/download/v0.18.0/tini-static
chmod +x tini
Creazione di una riga di comando del kernel
Il kernel Linux, come la maggior parte degli altri programmi, ha argomenti della riga di comando a cui è possibile accedere specificando la chiave --help.
Lui stesso: aiuto
linux --help
User Mode Linux v5.1.16
available at http://user-mode-linux.sourceforge.net/
--showconfig
Prints the config file that this UML binary was generated from.
iomem=<name>,<file>
Configure <file> as an IO memory region named <name>.
mem=<Amount of desired ram>
This controls how much "physical" memory the kernel allocates
for the system. The size is specified as a number followed by
one of 'k', 'K', 'm', 'M', which have the obvious meanings.
This is not related to the amount of memory in the host. It can
be more, and the excess, if it's ever used, will just be swapped out.
Example: mem=64M
--help
Prints this message.
debug
this flag is not needed to run gdb on UML in skas mode
root=<file containing the root fs>
This is actually used by the generic kernel in exactly the same
way as in any other kernel. If you configure a number of block
devices and want to boot off something other than ubd0, you
would use something like:
root=/dev/ubd5
--version
Prints the version number of the kernel.
umid=<name>
This is used to assign a unique identity to this UML machine and
is used for naming the pid file and management console socket.
con[0-9]*=<channel description>
Attach a console or serial line to a host channel. See
http://user-mode-linux.sourceforge.net/old/input.html for a complete
description of this switch.
eth[0-9]+=<transport>,<options>
Configure a network device.
aio=2.4
This is used to force UML to use 2.4-style AIO even when 2.6 AIO is
available. 2.4 AIO is a single thread that handles one request at a
time, synchronously. 2.6 AIO is a thread which uses the 2.6 AIO
interface to handle an arbitrary number of pending requests. 2.6 AIO
is not available in tt mode, on 2.4 hosts, or when UML is built with
/usr/include/linux/aio_abi.h not available. Many distributions don't
include aio_abi.h, so you will need to copy it from a kernel tree to
your /usr/include/linux in order to build an AIO-capable UML
nosysemu
Turns off syscall emulation patch for ptrace (SYSEMU).
SYSEMU is a performance-patch introduced by Laurent Vivier. It changes
behaviour of ptrace() and helps reduce host context switch rates.
To make it work, you need a kernel patch for your host, too.
See http://perso.wanadoo.fr/laurent.vivier/UML/ for further
information.
uml_dir=<directory>
The location to place the pid and umid files.
quiet
Turns off information messages during boot.
hostfs=<root dir>,<flags>,...
This is used to set hostfs parameters. The root directory argument
is used to confine all hostfs mounts to within the specified directory
tree on the host. If this isn't specified, then a user inside UML can
mount anything on the host that's accessible to the user that's running
it.
The only flag currently supported is 'append', which specifies that all
files opened by hostfs will be opened in append mode.
Questo pannello evidenzia i principali parametri del lancio. Eseguiamo il kernel con il set minimo di opzioni richiesto:
linux
root=/dev/root
rootfstype=hostfs
rootflags=$HOME/prefix/uml-demo
rw
mem=64M
init=/bin/sh
Le righe sopra dicono al nostro kernel quanto segue:
Supponiamo che il filesystem root sia uno pseudo dispositivo /dev/root.
Scegliere hostfs come driver del file system root.
Monta il filesystem guest che abbiamo creato sul dispositivo root.
E sì, in modalità lettura-scrittura.
Usa solo 64 MB di RAM (puoi usarne molto meno a seconda di cosa intendi fare, ma 64 MB sembra la quantità ottimale).
Il kernel si avvia automaticamente /bin/sh come init-processi.
Esegui questo comando e dovresti ottenere qualcosa di simile al seguente:
Un altro foglio
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 environment variables for a tempdir...none found
Checking if /dev/shm is on tmpfs...OK
Checking PROT_EXEC mmap in /dev/shm...OK
Adding 32137216 bytes to physical memory to account for exec-shield gap
Linux version 5.1.16 (cadey@kahless) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #30 Sun Jul 7 18:57:19 UTC 2019
Built 1 zonelists, mobility grouping on. Total pages: 23898
Kernel command line: root=/dev/root rootflags=/home/cadey/dl/uml/alpine rootfstype=hostfs rw mem=64M init=/bin/sh
Dentry cache hash table entries: 16384 (order: 5, 131072 bytes)
Inode-cache hash table entries: 8192 (order: 4, 65536 bytes)
Memory: 59584K/96920K available (2692K kernel code, 708K rwdata, 588K rodata, 104K init, 244K bss, 37336K reserved, 0K cma-reserved)
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
NR_IRQS: 15
clocksource: timer: mask: 0xffffffffffffffff max_cycles: 0x1cd42e205, max_idle_ns: 881590404426 ns
Calibrating delay loop... 7479.29 BogoMIPS (lpj=37396480)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
Mountpoint-cache hash table entries: 512 (order: 0, 4096 bytes)
Checking that host ptys support output SIGIO...Yes
Checking that host ptys support SIGIO on close...No, enabling workaround
devtmpfs: initialized
random: get_random_bytes called from setup_net+0x48/0x1e0 with crng_init=0
Using 2.6 host AIO
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex hash table entries: 256 (order: 0, 6144 bytes)
NET: Registered protocol family 16
clocksource: Switched to clocksource timer
NET: Registered protocol family 2
tcp_listen_portaddr_hash hash table entries: 256 (order: 0, 4096 bytes)
TCP established hash table entries: 1024 (order: 1, 8192 bytes)
TCP bind hash table entries: 1024 (order: 1, 8192 bytes)
TCP: Hash tables configured (established 1024 bind 1024)
UDP hash table entries: 256 (order: 1, 8192 bytes)
UDP-Lite hash table entries: 256 (order: 1, 8192 bytes)
NET: Registered protocol family 1
console [stderr0] disabled
mconsole (version 2) initialized on /home/cadey/.uml/tEwIjm/mconsole
Checking host MADV_REMOVE support...OK
workingset: timestamp_bits=62 max_order=14 bucket_order=0
Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
io scheduler noop registered (default)
io scheduler bfq registered
loop: module loaded
NET: Registered protocol family 17
Initialized stdio console driver
Using a channel type which is configured out of UML
setup_one_line failed for device 1 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 2 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 3 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 4 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 5 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 6 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 7 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 8 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 9 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 10 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 11 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 12 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 13 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 14 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 15 : Configuration failed
Console initialized on /dev/tty0
console [tty0] enabled
console [mc-1] enabled
Failed to initialize ubd device 0 :Couldn't determine size of device's file
VFS: Mounted root (hostfs filesystem) on device 0:11.
devtmpfs: mounted
This architecture does not have kernel memory protection.
Run /bin/sh as init process
/bin/sh: can't access tty; job control turned off
random: fast init done
/ #
Le manipolazioni di cui sopra ci daranno sistema ospite al minimo, senza cose come /proc o il nome host assegnato. Ad esempio, prova i seguenti comandi:
- uname -av
- cat /proc/self/pid
- hostname
Per disconnettersi dall'ospite, digitare exit oppure premi control-d. Questo ucciderà la shell seguito da un panico del kernel:
/ # exit
Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
fish: “./linux root=/dev/root rootflag…” terminated by signal SIGABRT (Abort)
Abbiamo avuto questo panico nel kernel perché il kernel Linux pensa che il processo di inizializzazione sia sempre in esecuzione. Senza di esso, il sistema non può più funzionare e si blocca. Ma poiché si tratta di un processo in modalità utente, l'output risultante si invia a SIGABRT, che si traduce in un output.
Configurazione della rete ospite
Ed è qui che le cose cominciano ad andare storte. Networking in modalità utente Linux è il luogo in cui l'intero concetto di "modalità utente" limitata inizia a cadere a pezzi. Dopotutto, di solito a livello di sistema, la rete è limitata privilegiato modalità di esecuzione per ragioni tutti comprensibili.
Nota. per .: puoi leggere di più sulle diverse opzioni per lavorare con una rete in UML qui.
Viaggio a Slirp
Tuttavia, esiste uno strumento antico e quasi non supportato chiamato scivolare, con la quale la modalità utente Linux può interagire con la rete. Funziona in modo molto simile a uno stack TCP/IP a livello utente e non richiede alcuna autorizzazione di sistema per essere eseguito. Questo strumento era uscito nel 1995, e l'ultimo aggiornamento è datato Anno 2006. Slipr è molto vecchio. Nel corso del tempo senza supporto e aggiornamenti, i compilatori sono arrivati al punto che ora questo strumento può essere descritto solo come marciume del codice.
Scarichiamo quindi Slirp dai repository di Ubuntu e proviamo a eseguirlo:
sudo apt-get install slirp
/usr/bin/slirp
Slirp v1.0.17 (BETA)
Copyright (c) 1995,1996 Danny Gasparovski and others.
All rights reserved.
This program is copyrighted, free software.
Please read the file COPYRIGHT that came with the Slirp
package for the terms and conditions of the copyright.
IP address of Slirp host: 127.0.0.1
IP address of your DNS(s): 1.1.1.1, 10.77.0.7
Your address is 10.0.2.15
(or anything else you want)
Type five zeroes (0) to exit.
[autodetect SLIP/CSLIP, MTU 1500, MRU 1500, 115200 baud]
SLiRP Ready ...
fish: “/usr/bin/slirp” terminated by signal SIGSEGV (Address boundary error)
Oh dei. Installiamo il debugger di Slirp e vediamo se riusciamo a capire cosa sta succedendo qui:
sudo apt-get install gdb slirp-dbgsym
gdb /usr/bin/slirp
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/bin/slirp...Reading symbols from /usr/lib/debug/.build-id/c6/2e75b69581a1ad85f72ac32c0d7af913d4861f.debug...done.
done.
(gdb) run
Starting program: /usr/bin/slirp
Slirp v1.0.17 (BETA)
Copyright (c) 1995,1996 Danny Gasparovski and others.
All rights reserved.
This program is copyrighted, free software.
Please read the file COPYRIGHT that came with the Slirp
package for the terms and conditions of the copyright.
IP address of Slirp host: 127.0.0.1
IP address of your DNS(s): 1.1.1.1, 10.77.0.7
Your address is 10.0.2.15
(or anything else you want)
Type five zeroes (0) to exit.
[autodetect SLIP/CSLIP, MTU 1500, MRU 1500, 115200 baud]
SLiRP Ready ...
Program received signal SIGSEGV, Segmentation fault.
ip_slowtimo () at ip_input.c:457
457 ip_input.c: No such file or directory.
L'errore batte in noi questa linea. Diamo un'occhiata allo stacktrace, forse qualcosa ci aiuterà lì:
(gdb) bt full
#0 ip_slowtimo () at ip_input.c:457
fp = 0x55784a40
#1 0x000055555556a57c in main_loop () at ./main.c:980
so = <optimized out>
so_next = <optimized out>
timeout = {tv_sec = 0, tv_usec = 0}
ret = 0
nfds = 0
ttyp = <optimized out>
ttyp2 = <optimized out>
best_time = <optimized out>
tmp_time = <optimized out>
#2 0x000055555555b116 in main (argc=1, argv=0x7fffffffdc58) at ./main.c:95
No locals.
Qui vediamo che l'arresto anomalo avviene durante l'avvio del ciclo principale quando slipr tenta di verificare i timeout. A questo punto, ho dovuto rinunciare a provare a eseguire il debug. Ma vediamo se Slirp costruito in questo modo funziona. Ho riscaricato l'archivio direttamente dal sito Sourceforge, perché trascinare qualcosa da lì attraverso la riga di comando è una seccatura:
cd ~/dl
wget https://xena.greedo.xeserv.us/files/slirp-1.0.16.tar.gz
tar xf slirp-1.0.16.tar.gz
cd slirp-1.0.16/src
./configure --prefix=$HOME/prefix/slirp
make
Qui vediamo avvisi su funzioni integrate non definite, ovvero sull'impossibilità di collegare il file binario risultante. Sembra che tra il 2006 e questo punto, gcc abbia smesso di produrre simboli utilizzati nelle funzioni integrate dei file compilati intermedi. Proviamo a sostituire la parola chiave inline su un commento vuoto e guarda il risultato:
vi slirp.h
:6
a
<enter>
#define inline /**/
<escape>
:wq
make
No. Anche questo non funziona. Ancora non riesco a trovare i simboli per queste funzioni.
A questo punto ho rinunciato e ho iniziato a cercare su Github Pacchetti di creazione di Heroku. La mia teoria era che qualche pacchetto di build di Heroku contenesse i binari di cui avevo bisogno. Alla fine, la ricerca mi ha portato qui. Ho scaricato e scompattato uml.tar.gz e ho trovato quanto segue:
total 6136
-rwxr-xr-x 1 cadey cadey 79744 Dec 10 2017 ifconfig*
-rwxr-xr-x 1 cadey cadey 373 Dec 13 2017 init*
-rwxr-xr-x 1 cadey cadey 149688 Dec 10 2017 insmod*
-rwxr-xr-x 1 cadey cadey 66600 Dec 10 2017 route*
-rwxr-xr-x 1 cadey cadey 181056 Jun 26 2015 slirp*
-rwxr-xr-x 1 cadey cadey 5786592 Dec 15 2017 uml*
-rwxr-xr-x 1 cadey cadey 211 Dec 13 2017 uml_run*
Questo è il binario sliprp! Lui lavora?
./slirp
Slirp v1.0.17 (BETA) FULL_BOLT
Copyright (c) 1995,1996 Danny Gasparovski and others.
All rights reserved.
This program is copyrighted, free software.
Please read the file COPYRIGHT that came with the Slirp
package for the terms and conditions of the copyright.
IP address of Slirp host: 127.0.0.1
IP address of your DNS(s): 1.1.1.1, 10.77.0.7
Your address is 10.0.2.15
(or anything else you want)
Type five zeroes (0) to exit.
[autodetect SLIP/CSLIP, MTU 1500, MRU 1500]
SLiRP Ready ...
Non si blocca, quindi dovrebbe funzionare! Inseriamo questo binario ~/bin/slirp:
cp slirp ~/bin/slirp
Nel caso in cui il creatore del pacchetto lo rimuova, I fatto uno specchio.
I primi due comandi di configurazione /proc и /sys necessari per il lavoro ifconfig, che imposta l'interfaccia di rete per comunicare con Slirp. Squadra route imposta la tabella di routing del kernel per forzare l'invio di tutto il traffico attraverso il tunnel Slirp. Verifichiamolo con una query DNS:
Nota per.: A quanto pare, il post originale è stato scritto su un desktop con una scheda di rete cablata o qualche altra configurazione che non richiedeva driver aggiuntivi. Su un laptop con WiFi 8265 di Intel, si verifica un errore durante l'avvio della rete
/ # ifconfig eth0 10.0.2.14 netmask 255.255.255.240 broadcast 10.0.2.15
slirp_tramp failed - errno = 2
ifconfig: ioctl 0x8914 failed: No such file or directory
/ #
Apparentemente il kernel non riesce a comunicare con il driver della scheda di rete. Un tentativo di compilare il firmware nel kernel, sfortunatamente, non ha risolto la situazione. Al momento della pubblicazione non è stato possibile trovare una soluzione in questa configurazione. Nelle configurazioni più semplici (ad esempio in Virtualbox), l'interfaccia si alza correttamente.
Automatizziamo il reindirizzamento con il seguente script di shell:
E poi apporteremo modifiche alla riga di comando del kernel:
linux
root=/dev/root
rootfstype=hostfs
rootflags=$HOME/prefix/uml-demo
rw
mem=64M
eth0=slirp,,$HOME/bin/slirp
init=/init.sh
E ripetiamo:
SLiRP Ready ...
networking set up
/bin/sh: can't access tty; job control turned off
nslookup google.com 8.8.8.8
Server: 8.8.8.8
Address 1: 8.8.8.8 dns.google
Name: google.com
Address 1: 172.217.12.206 lga25s63-in-f14.1e100.net
Address 2: 2607:f8b0:4004:800::200e iad30s09-in-x0e.1e100.net
La rete è stabile!
file della finestra mobile
Per facilitarti il controllo di tutto questo, ho raccolto Dockerfile, che automatizza la maggior parte dei passaggi descritti e dovrebbe fornire una configurazione funzionante. Ho anche kernel preconfigurato, che ha tutto ciò che è descritto nel post. Ma è importante capire che qui ho delineato solo l'impostazione minima.
Spero che questo post ti abbia aiutato a capire come generare un kernel guest. Si è rivelato una specie di mostro, ma la pubblicazione è stata concepita come una guida completa sulla creazione, installazione e configurazione della modalità utente in Linux nelle versioni moderne dei sistemi operativi di questa famiglia. I passaggi successivi dovrebbero includere l'installazione di servizi e altro software già all'interno del sistema ospite. Poiché le immagini del contenitore Docker sono solo tarball pubblicizzati, dovresti essere in grado di estrarre l'immagine tramite docker export, quindi determinarne il percorso di installazione nella radice del file system del kernel guest. Bene, allora esegui lo script di shell.
Un ringraziamento speciale a Rkeene di #lobsters su Freenode. Senza il suo aiuto nel debug di Slirp, non sarei arrivato fin qui. Non ho idea di come il suo sistema Slackware funzioni correttamente con slirp, ma i miei sistemi Ubuntu e Alpine non accettavano slirp e il binario suggerito da Rkeene. Ma mi basta che almeno qualcosa funzioni per me.