Com començar a utilitzar el mode d'usuari a Linux

Introducció del traductor: En el context de l'entrada massiva a les nostres vides de diversos tipus de contenidors, pot ser força interessant i útil esbrinar amb quines tecnologies va començar tot una vegada. Alguns d'ells es poden utilitzar de manera útil fins avui, però no tothom recorda aquests mètodes (o sap si no van ser capturats durant el seu ràpid desenvolupament). Una d'aquestes tecnologies és User Mode Linux. L'autor de l'original va fer moltes investigacions, esbrinant quins dels antics desenvolupaments encara funcionen i quins no, i va elaborar alguna cosa com una instrucció pas a pas sobre com aconseguir un UML homebrew en 2k19. I sí, vam convidar l'autor del post original a Habr Cadey, així que si teniu cap pregunta, pregunteu-ho en anglès als comentaris.

Com començar a utilitzar el mode d'usuari a Linux

El mode d'usuari a Linux és, de fet, un port del nucli de Linux per si mateix. Aquest mode us permet executar un nucli complet de Linux com a procés d'usuari i és utilitzat habitualment pels desenvolupadors per provar controladors. Però aquest mode també és útil com a eina d'aïllament general, el principi de la qual és similar al funcionament de les màquines virtuals. Aquest mode proporciona més aïllament que Docker, però menys que una màquina virtual completa com KVM o Virtual Box.

En general, el mode d'usuari pot semblar una eina estranya i difícil d'utilitzar, però encara té els seus usos. Després de tot, es tracta d'un nucli de Linux complet que s'executa des d'un usuari sense privilegis. Aquesta característica permet que el codi potencialment no fiable s'executi sense cap amenaça per a la màquina amfitriona. I com que es tracta d'un nucli complet, els seus processos estan aïllats de la màquina host, és a dir els processos que s'executen dins del mode d'usuari no seran visibles per a l'amfitrió. Això no és com el contenidor Docker habitual, en aquest cas la màquina host sempre veu els processos dins del dipòsit. Mireu aquest tros de pstree d'un dels meus servidors:

containerd─┬─containerd-shim─┬─tini─┬─dnsd───19*[{dnsd}]
           │                 │      └─s6-svscan───s6-supervise
           │                 └─10*[{containerd-shim}]
           ├─containerd-shim─┬─tini─┬─aerial───21*[{aerial}]
           │                 │      └─s6-svscan───s6-supervise
           │                 └─10*[{containerd-shim}]
           ├─containerd-shim─┬─tini─┬─s6-svscan───s6-supervise
           │                 │      └─surl
           │                 └─9*[{containerd-shim}]
           ├─containerd-shim─┬─tini─┬─h───13*[{h}]
           │                 │      └─s6-svscan───s6-supervise
           │                 └─10*[{containerd-shim}]
           ├─containerd-shim─┬─goproxy───14*[{goproxy}]
           │                 └─9*[{containerd-shim}]
           └─32*[{containerd}]

I compareu això amb el pstree del nucli de Linux en mode d'usuari:

linux─┬─5*[linux]
      └─slirp

Quan treballo amb contenidors Docker, puc veure des de l'amfitrió els noms dels processos que s'estan executant al convidat. Amb el mode d'usuari de Linux, això no és possible. Què vol dir? Això significa que les eines de supervisió que s'executen a través del subsistema d'auditoria de Linux no ho veig processos que s'executen al sistema convidat. Però en algunes situacions, aquesta característica es pot convertir en una arma de doble tall.

En general, tota la publicació següent és un recull d'investigacions i intents aproximats per aconseguir el resultat desitjat. Per fer-ho, vaig haver d'utilitzar diverses eines antigues, llegir fonts del nucli, participar en una depuració intensiva de codi escrit quan encara era a l'escola primària i també jugar amb les compilacions d'Heroku mitjançant un binari especial a la recerca de les eines que necessitava. Tot aquest treball va fer que els nois del meu IRC em diguessin mag. Espero que aquesta publicació serveixi com a documentació fiable perquè algú faci el mateix, però amb nuclis i versions del sistema operatiu més nous.

ajust

La configuració del mode d'usuari de Linux es fa en diversos passos:

  • instal·lar dependències a l'amfitrió;
  • descarregar el nucli de Linux;
  • configuració de construcció del nucli;
  • muntatge del nucli;
  • instal·lació binària;
  • configurar el sistema de fitxers convidat;
  • selecció dels paràmetres de llançament del nucli;
  • configurar una xarxa de convidats;
  • iniciant el nucli convidat.

Suposo que si decideixes fer tot això tu mateix, el més probable és que facis tot el que es descriu en algun sistema de tipus Ubuntu o Debian. Vaig intentar implementar tot l'anterior a la meva distribució preferida: Alpine, però res no va funcionar, aparentment perquè el nucli de Linux està estretament lligat als glibc-isms per als controladors en mode d'usuari. Tinc la intenció d'informar-ho a aigües amunt després que finalment esbringui el problema.

Instal·lació de dependències a l'amfitrió

Ubuntu requereix almenys els paquets següents per construir el nucli Linux (suposant una instal·lació neta):

- 'build-essential'
- 'flex'
- 'bison'
- 'xz-utils'
- 'wget'
- 'ca-certificates'
- 'bc'
- 'linux-headers'

Podeu instal·lar-los amb l'ordre següent (com a root o amb sudo):

apt-get -y install build-essential flex bison xz-utils wget ca-certificates bc 
                   linux-headers-$(uname -r)

Tingueu en compte que l'execució del programa de personalització de menús per al nucli Linux requerirà la instal·lació libncurses-dev. Assegureu-vos que estigui instal·lat amb l'ordre següent (com a root o amb sudo):

apt-get -y install libncurses-dev

Descàrrega del nucli

Decidiu on descarregar-lo i després creeu el nucli. Per a aquesta operació, haureu d'assignar uns 1,3 GB d'espai al disc dur, així que assegureu-vos que el teniu.

Després aneu a kernel.org i obteniu l'URL per descarregar la darrera versió estable del nucli. En el moment d'escriure aquesta publicació: https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

Baixeu aquest fitxer utilitzant 'wget':

wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

I extreu-lo amb 'tar':

tar xJf linux-5.1.16.tar.xz

Ara entrem al directori creat en desempaquetar el tarball:

cd linux-5.1.16

Configuració de la construcció del nucli

El sistema de construcció del nucli és un conjunt Makefiles с molts eines i scripts personalitzats per automatitzar el procés. Primer, obriu el programa de configuració interactiu:

make ARCH=um menuconfig

Completarà parcialment el muntatge i us mostrarà un quadre de diàleg. Quan la llum apareix a la part inferior de la finestra[Select]', podreu configurar amb les tecles Espai o Enter. Navegueu per la finestra, com és habitual, amb les fletxes del teclat "amunt" i "avall" i seleccioneu elements: "esquerra" o "dreta".

El punter de vista —> significa que esteu en un submenú, al qual s'accedeix amb la tecla Enter. La sortida és, òbviament, a través de "[Exit]'.

Incloeu les opcions següents a '[Select]' i assegureu-vos que tinguin un '[*]' al costat:

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

Això és tot, podeu sortir d'aquesta finestra seleccionant successivament '[Exit]'. Només assegureu-vos que al final se us demanarà que deseu la configuració i seleccioneu "[Yes]'.

Us recomano que jugueu amb les opcions de creació del nucli després de llegir aquesta publicació. Mitjançant aquests experiments, podeu aprendre molt pel que fa a la comprensió del treball de la mecànica del nucli de baix nivell i l'impacte de diverses banderes en el seu muntatge.

Construint el nucli

El nucli de Linux és un gran programa que fa moltes coses. Fins i tot amb una configuració tan mínima al maquinari antic, la creació pot trigar força temps. Així que creeu el nucli amb la següent comanda:

make ARCH=um -j$(nproc)

Per a què? Aquesta ordre dirà al nostre constructor que utilitzi tots els nuclis i fils de CPU disponibles en el procés de creació. Equip $(nproc) al final de Build substitueix la sortida de l'ordre nproc, que forma part de coreutils a la compilació estàndard d'Ubuntu.

Després d'un temps, el nostre nucli es compilarà en un fitxer executable ./linux.

Instal·lació del binari

Com que el mode d'usuari a Linux crea un binari normal, podeu instal·lar-lo com qualsevol altra utilitat. Així és com ho vaig fer:

mkdir -p ~/bin
cp linux ~/bin/linux

També val la pena assegurar-se-ho ~/bin està en el teu $PATH:

export PATH=$PATH:$HOME/bin

Configuració del sistema de fitxers convidat

Creeu un directori per al sistema de fitxers convidat:

mkdir -p $HOME/prefix/uml-demo
cd $HOME/prefix

Obriu alpinelinux.org i a secció de descàrrega trobar l'enllaç de descàrrega real MINI ROOT FILESYSTEM. En el moment d'escriure això era:

http://dl-cdn.alpinelinux.org/alpine/v3.10/releases/x86_64/alpine-minirootfs-3.10.0-x86_64.tar.gz

Baixeu aquest tarball amb wget:

wget -O alpine-rootfs.tgz http://dl-cdn.alpinelinux.org/alpine/v3.10/releases/x86_64/alpine-minirootfs-3.10.0-x86_64.tar.gz

Ara introduïu el directori del sistema de fitxers convidat i extreu l'arxiu:

cd uml-demo
tar xf ../alpine-rootfs.tgz

Les accions descrites crearan una petita plantilla de sistema de fitxers. A causa de la naturalesa del sistema, serà extremadament difícil instal·lar paquets mitjançant el gestor d'apk Alpine. Però aquest FS serà suficient per avaluar la idea general.

També necessitem una eina tini per frenar el consum de memòria processos zombis el nostre nucli convidat.

wget -O tini https://github.com/krallin/tini/releases/download/v0.18.0/tini-static
chmod +x tini

Creació d'una línia d'ordres del nucli

El nucli de Linux, com la majoria dels altres programes, té arguments de línia d'ordres als quals es pot accedir especificant la clau --help.

Ell mateix: ajuda

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.

Aquest panell destaca els principals paràmetres del llançament. Executem el nucli amb el conjunt mínim d'opcions requerides:

linux 
  root=/dev/root 
  rootfstype=hostfs 
  rootflags=$HOME/prefix/uml-demo 
  rw 
  mem=64M 
  init=/bin/sh

Les línies anteriors diuen al nostre nucli el següent:

  • Suposem que el sistema de fitxers arrel és un pseudodispositiu /dev/root.
  • Trieu hostfs com a controlador del sistema de fitxers arrel.
  • Munteu el sistema de fitxers convidat que hem creat al dispositiu arrel.
  • I sí, en mode lectura-escriptura.
  • Utilitzeu només 64 MB de RAM (podeu utilitzar molt menys segons el que penseu fer, però 64 MB sembla ser la quantitat òptima).
  • El nucli s'inicia automàticament /bin/sh как init-procés.

Executeu aquesta comanda i hauríeu d'obtenir alguna cosa com el següent:

Un full més

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
/ # 

Les manipulacions anteriors ens donaran sistema de convidats com a mínim, sense coses com /proc o el nom d'amfitrió assignat. Per exemple, proveu les ordres següents:

- uname -av
- cat /proc/self/pid
- hostname

Per tancar la sessió del convidat, escriviu exit o premeu control-d. Això matarà el shell seguit d'un pànic del nucli:

/ # exit
Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
fish: “./linux root=/dev/root rootflag…” terminated by signal SIGABRT (Abort)

Hem rebut aquest pànic del nucli perquè el nucli de Linux creu que el procés d'inicialització sempre s'està executant. Sense ell, el sistema ja no pot funcionar i es bloqueja. Però com que es tracta d'un procés en mode usuari, la sortida resultant s'envia a SIGABRT, que dóna lloc a una sortida.

Configuració de la xarxa de convidats

Però aquí és on les coses comencen a sortir malament per a nosaltres. La xarxa en mode d'usuari Linux és on tot el concepte d'un "mode d'usuari" limitat comença a desfer-se. Després de tot, la xarxa sol estar limitada a nivell de sistema privilegiats modes d'execució per raons comprensibles per a tots.

Nota. per .: podeu llegir més sobre les diferents opcions per treballar amb una xarxa en UML aquí.

Viatge a Slirp

Tanmateix, hi ha una eina antiga i gairebé sense suport anomenada Lliscar, amb el qual el Mode d'usuari Linux pot interactuar amb la xarxa. Funciona molt com una pila TCP/IP a nivell d'usuari i no requereix cap permís del sistema per executar-se. Aquesta eina era llançat l'any 1995, i la darrera actualització està datada Any 2006. Slirp és molt vell. Durant el temps sense suport i actualitzacions, els compiladors han arribat tan lluny que ara aquesta eina només es pot descriure com podridura del codi.

Per tant, descarreguem Slirp dels dipòsits d'Ubuntu i provem d'executar-lo:

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 déus meus. Instal·lem el depurador Slirp i veiem si podem esbrinar què passa aquí:

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'error ens està colpejant aquesta línia. Mirem la traça de pila, potser alguna cosa ens ajudarà:

(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.

Aquí veiem que l'error es produeix durant l'inici del bucle principal quan slirp intenta comprovar si hi ha temps d'espera. En aquest punt, vaig haver de renunciar a intentar depurar. Però anem a veure si Slirp construït a partir de tipus funciona. Vaig tornar a baixar l'arxiu directament des del lloc Sourceforge, perquè arrossegar alguna cosa des d'allà mitjançant la línia d'ordres és un dolor:

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

Aquí veiem alertes sobre funcions integrades no definides, és a dir, sobre la incapacitat d'enllaçar el fitxer binari resultant. Sembla que entre el 2006 i aquest punt, gcc va deixar de produir símbols utilitzats en les funcions integrades dels fitxers compilats intermedis. Intentem substituir la paraula clau inline en un comentari buit i mira el resultat:

vi slirp.h
:6
a
<enter>
#define inline /**/
<escape>
:wq
make

No. Això tampoc funciona. Encara no es poden trobar símbols per a aquestes funcions.

En aquest moment, em vaig rendir i vaig començar a buscar a Github Paquets de construcció Heroku. La meva teoria era que algun paquet de compilació Heroku contindria els binaris que necessitava. Al final, la recerca em va portar per aquí. Vaig descarregar i desempaquetar uml.tar.gz i va trobar el següent:

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*

Aquest és el binari slirp! Ell treballa?

./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 ...

No cau, així que hauria de funcionar! Plantem aquest binari ~/bin/slirp:

cp slirp ~/bin/slirp

En cas que el creador del paquet l'elimini, jo fet un mirall.

Configuració de la xarxa

Ara configurem la xarxa al nostre nucli convidat. Actualitza les opcions de llançament:

linux 
  root=/dev/root 
  rootfstype=hostfs 
  rootflags=$HOME/prefix/uml-demo 
  rw 
  mem=64M 
  eth0=slirp,,$HOME/bin/slirp 
  init=/bin/sh

Ara encenem la xarxa:

mount -t proc proc proc/
mount -t sysfs sys sys/

ifconfig eth0 10.0.2.14 netmask 255.255.255.240 broadcast 10.0.2.15
route add default gw 10.0.2.2

Les dues primeres ordres de configuració /proc и /sys necessàries per treballar ifconfig, que configura la interfície de xarxa perquè es comuniqui amb Slirp. Equip route estableix la taula d'encaminament del nucli per forçar que tot el trànsit s'enviï a través del túnel Slirp. Comprovem-ho amb una consulta DNS:

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:4006:81b::200e lga25s63-in-x0e.1e100.net

Funciona!

Nota per .: Pel que sembla, la publicació original es va escriure en un escriptori amb una targeta de xarxa per cable o alguna altra configuració que no requeria controladors addicionals. En un ordinador portàtil amb WiFi 8265 d'Intel, es produeix un error en augmentar la xarxa

/ # 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
/ #

Pel que sembla, el nucli no es pot comunicar amb el controlador de la unitat de xarxa. Malauradament, un intent de compilar el microprogramari al nucli no va corregir la situació. En el moment de la publicació, encara no es podia trobar cap solució en aquesta configuració concreta. En configuracions més senzilles (per exemple, a Virtualbox), la interfície es planteja correctament.

Automatitzem la redirecció amb el següent script de shell:

#!/bin/sh
# init.sh

mount -t proc proc proc/
mount -t sysfs sys sys/
ifconfig eth0 10.0.2.14 netmask 255.255.255.240 broadcast 10.0.2.15
route add default gw 10.0.2.2

echo "networking set up"

exec /tini /bin/sh

I marca-ho com a executable:

chmod +x init.sh

I després farem canvis a la línia d'ordres del nucli:

linux 
  root=/dev/root 
  rootfstype=hostfs 
  rootflags=$HOME/prefix/uml-demo 
  rw 
  mem=64M 
  eth0=slirp,,$HOME/bin/slirp 
  init=/init.sh

I repetim:

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 xarxa és estable!

fitxer docker

Per facilitar-vos la comprovació de tot això, he recollit Dockerfile, que automatitza la majoria dels passos descrits i us hauria de proporcionar una configuració de treball. també tinc configuració del nucli a punt, que té tot el que es descriu a la publicació. Però és important entendre que aquí només he descrit la configuració mínima.

Espero que aquesta publicació us hagi ajudat a entendre com crear un nucli convidat. Va resultar ser una mena de monstre, però la publicació es va concebre com una guia completa sobre la construcció, instal·lació i configuració del mode d'usuari a Linux sota les versions modernes dels sistemes operatius d'aquesta família. Els passos següents haurien d'incloure la instal·lació de serveis i altres programaris que ja estan dins del sistema convidat. Com que les imatges dels contenidors de Docker són només arxius publicitaris, hauríeu de poder extreure la imatge mitjançant docker export, i després determineu la seva ruta d'instal·lació a l'arrel del sistema de fitxers del nucli convidat. Bé, llavors executeu l'script de l'intèrpret d'ordres.

Un agraïment especial a Rkeene de #lobsters a Freenode. Sense la seva ajuda per depurar Slirp, no hauria arribat tan lluny. No tinc ni idea de com funciona correctament el seu sistema Slackware amb slirp, però els meus sistemes Ubuntu i Alpine no van acceptar slirp i el binari Rkeene em va suggerir. Però ja n'hi ha prou que almenys alguna cosa em funcioni.

Font: www.habr.com

Afegeix comentari