Cómo empezar a utilizar el Modo Usuario en Linux

Introducción del traductor: En el contexto de la entrada masiva en nuestras vidas de diversos tipos de contenedores, puede resultar muy interesante y útil descubrir con qué tecnologías empezó todo. Algunos de ellos pueden usarse de manera útil hasta el día de hoy, pero no todos recuerdan tales métodos (o saben si no fueron descubiertos durante su rápido desarrollo). Una de esas tecnologías es el modo de usuario Linux. El autor del original investigó mucho, averiguando cuáles de los desarrollos antiguos todavía funcionan y cuáles no, y preparó algo así como una instrucción paso a paso sobre cómo conseguir un UML casero en 2k19. Y sí, invitamos al autor de la publicación original a Habr. Claro, así que si tienes dudas, pregunta en inglés en los comentarios.

Cómo empezar a utilizar el Modo Usuario en Linux

El modo de usuario en Linux es, de hecho, una adaptación del kernel de Linux a sí mismo. Este modo le permite ejecutar un kernel de Linux completo como proceso de usuario y los desarrolladores lo utilizan comúnmente para probar controladores. Pero este modo también es útil como herramienta de aislamiento general, cuyo principio es similar al funcionamiento de las máquinas virtuales. Este modo proporciona más aislamiento que Docker, pero menos que una máquina virtual completa como KVM o Virtual Box.

En general, el Modo Usuario puede parecer una herramienta extraña y difícil de usar, pero aún así tiene sus usos. Después de todo, este es un kernel de Linux completo que se ejecuta desde un usuario sin privilegios. Esta característica permite que se ejecute código potencialmente no confiable sin ninguna amenaza para la máquina host. Y dado que se trata de un núcleo completo, sus procesos están aislados de la máquina host, es decir Los procesos que se ejecutan dentro del modo de usuario no serán visibles para el host.. Esto no es como el contenedor Docker habitual, en cuyo caso la máquina host siempre ve los procesos dentro del repositorio. Mire este fragmento de pstree de uno de mis servidores:

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}]

Y compare esto con el pstree del kernel de Linux en Modo Usuario:

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

Cuando trabajo con contenedores Docker, puedo ver desde el host los nombres de los procesos que se ejecutan en el invitado. Esto no es posible con el modo de usuario de Linux. ¿Qué significa? Esto significa que las herramientas de monitoreo que se ejecutan a través del subsistema de auditoría de Linux no veo procesos que se ejecutan en el sistema invitado. Pero en algunas situaciones esta característica puede ser un arma de doble filo.

En general, la publicación completa a continuación es una colección de investigaciones e intentos aproximados para lograr el resultado deseado. Para hacer esto, tuve que usar varias herramientas antiguas, leer las fuentes del kernel, hacer una depuración intensiva del código escrito en los días en que todavía estaba en la escuela primaria y también jugar con las compilaciones de Heroku usando un binario especial para encontrar las herramientas que necesitaba. . Todo este trabajo llevó a los chicos de mi IRC a llamarme mágico. Espero que esta publicación sirva como documentación confiable para que alguien intente lo mismo con kernels y versiones de sistema operativo más nuevos.

Ajuste

La configuración del modo de usuario de Linux se realiza en varios pasos:

  • instalar dependencias en el host;
  • descargar el kernel de Linux;
  • configuración de compilación del kernel;
  • ensamblaje del núcleo;
  • instalación binaria;
  • configurar el sistema de archivos de invitados;
  • selección de parámetros de lanzamiento del kernel;
  • configurar una red de invitados;
  • iniciando el kernel invitado.

Supongo que si decides hacerlo tú mismo, lo más probable es que hagas todo lo descrito en algún sistema tipo Ubuntu o Debian. Intenté implementar todo lo anterior en mi distribución favorita, Alpine, pero no salió nada, aparentemente debido al hecho de que el kernel de Linux tiene glibc-ismos vinculantes para los controladores en el modo de usuario. Planeo informar esto a upstream después de que finalmente comprenda el problema.

Instalación de dependencias en el host

Ubuntu requiere al menos los siguientes paquetes para compilar el kernel de Linux (suponiendo una instalación limpia):

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

Puedes instalarlos con el siguiente comando (como root o con sudo):

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

Tenga en cuenta que ejecutar el programa de personalización del menú para el kernel de Linux requerirá instalación libncurses-dev. Asegúrese de que esté instalado con el siguiente comando (como root o con sudo):

apt-get -y install libncurses-dev

Descarga del núcleo

Determine dónde descargar y luego compilar el kernel. Necesitará asignar aproximadamente 1,3 GB de espacio en el disco duro para esta operación, así que asegúrese de tenerlo.

Después de ir a kernel.org y obtenga la URL para descargar el último kernel estable. Al momento de escribir esto es: https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

Descargue este archivo usando 'wget':

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

Y extraerlo con 'tar':

tar xJf linux-5.1.16.tar.xz

Ahora ingresamos al directorio creado al descomprimir el tarball:

cd linux-5.1.16

Configuración de compilación del kernel

El sistema de construcción del kernel es un conjunto Archivos Make с por muchos herramientas y scripts personalizados para automatizar el proceso. Para comenzar, abra el programa de configuración en línea:

make ARCH=um menuconfig

Creará y mostrará parcialmente un cuadro de diálogo. Cuando '[Select]', puede configurar los ajustes usando la barra espaciadora o las teclas Enter. La navegación por la ventana se realiza como de costumbre utilizando las flechas del teclado “arriba” y “abajo”, y la selección de elementos es “izquierda” o “derecha”.

El puntero de vista —> significa que está en un submenú, al que se accede presionando la tecla Intro. La salida es obviamente a través de '[Exit]'.

Incluya las siguientes opciones en '[Select]' y asegúrese de que haya un símbolo '[*]' junto a ellos:

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

Eso es todo, puedes salir de esta ventana seleccionando sucesivamente '[Exit]'. Solo asegúrese de que al final se le solicite guardar la configuración y seleccione '[Yes]'.

Te recomiendo que juegues con las opciones de compilación del kernel después de leer esta publicación. A través de estos experimentos, puede aprender mucho en términos de comprender el trabajo de la mecánica del kernel de bajo nivel y el impacto de varios indicadores en su ensamblaje.

Construyendo el núcleo

El kernel de Linux es un gran programa que hace muchas cosas. Incluso con una configuración tan mínima en hardware antiguo, la construcción puede llevar bastante tiempo. Así que construye el kernel con el siguiente comando:

make ARCH=um -j$(nproc)

¿Para qué? Este comando le indicará a nuestro constructor que utilice todos los núcleos y subprocesos de CPU disponibles en el proceso de compilación. Equipo $(nproc) al final de Build sustituye la salida del comando nproc, que es parte de coreutils en una versión estándar de Ubuntu.

Después de un tiempo, nuestro kernel se compilará en un archivo ejecutable. ./linux.

Instalando el binario

Dado que el modo de usuario en Linux crea un binario normal, puedes instalarlo como cualquier otra utilidad. Así es como lo hice:

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

También vale la pena asegurarse de que ~/bin está en tu $PATH:

export PATH=$PATH:$HOME/bin

Configurar el sistema de archivos de invitados

Cree un directorio para el sistema de archivos invitado:

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

Abra alpinelinux.org y en sección de descarga encuentre el enlace de descarga real MINI ROOT FILESYSTEM. Al momento de escribir esto era:

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

Descarga este tarball usando 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

Ahora ingrese al directorio del sistema de archivos invitado y extraiga el archivo:

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

Las acciones descritas crearán una pequeña plantilla de sistema de archivos. Debido a la forma en que funciona el sistema, instalar paquetes a través del administrador de apk de Alpine será extremadamente difícil. Pero este FS será suficiente para evaluar la idea general.

También necesitamos una herramienta tini para frenar el consumo de memoria procesos zombies nuestro núcleo invitado.

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

Creando una línea de comando del kernel

El kernel de Linux, como la mayoría de los otros programas, tiene argumentos de línea de comando a los que se puede acceder especificando la clave --help.

Él mismo—ayuda

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.

Este panel resalta los principales parámetros del lanzamiento. Ejecutemos el kernel con el conjunto mínimo de opciones requerido:

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

Las líneas anteriores le dicen a nuestro kernel lo siguiente:

  • Supongamos que el sistema de archivos raíz es un pseudodispositivo /dev/root.
  • Escoger hostfs como controlador del sistema de archivos raíz.
  • Monte el sistema de archivos invitado que creamos en el dispositivo raíz.
  • Y sí, en modo lectura-escritura.
  • Utilice sólo 64 MB de RAM (puede utilizar mucho menos dependiendo de lo que planee hacer, pero 64 MB parece la cantidad óptima).
  • El kernel se inicia automáticamente. /bin/sh cómo init-proceso.

Ejecute este comando y debería obtener algo como lo siguiente:

una hoja mas

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

Las manipulaciones anteriores nos darán sistema de invitados al mínimo, sin cosas como /proc o nombre de host asignado. Por ejemplo, pruebe los siguientes comandos:

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

Para cerrar sesión como invitado, escriba exit o presione control-d. Esto matará el shell seguido de un pánico en el kernel:

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

Recibimos este pánico del kernel porque el kernel de Linux cree que el proceso de inicialización siempre está ejecutándose. Sin él, el sistema ya no puede funcionar y falla. Pero dado que este es un proceso en modo de usuario, la salida resultante se envía a sí misma a SIGABRT, lo que da como resultado una salida.

Configuración de la red de invitados

Pero aquí es donde las cosas empiezan a irnos mal. Conexión en red en modo de usuario Linux es donde todo el concepto de un "modo de usuario" limitado comienza a desmoronarse. Después de todo, generalmente a nivel del sistema, la red es limitada. privilegiado modos de ejecución por razones comprensibles para todos nosotros.

Nota. por .: puede leer más sobre las diferentes opciones para trabajar con una red en UML aquí.

Viaje a Slipp

Sin embargo, existe una herramienta antigua y prácticamente sin soporte llamada deslizamiento, con el cual User Mode Linux puede interactuar con la red. Funciona de manera muy similar a una pila TCP/IP a nivel de usuario y no requiere ningún permiso del sistema para ejecutarse. Esta herramienta fue lanzado en 1995, y la última actualización tiene fecha Año 2006. Slipp es muy viejo. Durante el tiempo sin soporte ni actualizaciones, los compiladores han llegado tan lejos que ahora esta herramienta solo puede describirse como código podrido.

Entonces, descarguemos Slirp de los repositorios de Ubuntu e intentemos ejecutarlo:

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 mis dioses. Instalemos el depurador Slirp y veamos si podemos descubrir qué está pasando 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.

El error late en nosotros esta línea. Miremos el seguimiento de la pila, tal vez algo nos ayude allí:

(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í vemos que el bloqueo ocurre durante el inicio del ciclo principal cuando slirp intenta verificar los tiempos de espera. En este punto, tuve que dejar de intentar depurar. Pero veamos si Slirp construido a partir de tipos funciona. Volví a descargar el archivo directamente desde el sitio. Sourceforge, porque arrastrar algo desde allí a través de la línea de comando es una molestia:

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í vemos alertas sobre funciones integradas no definidas, es decir, sobre la imposibilidad de vincular el archivo binario resultante. Parece que entre 2006 y este momento, gcc dejó de producir símbolos utilizados en funciones integradas de archivos compilados intermedios. Intentemos reemplazar la palabra clave. inline en un comentario vacío y mira el resultado:

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

No. Esto tampoco funciona. Todavía no puedo encontrar símbolos para estas funciones.

En este punto, me di por vencido y comencé a buscar en Github. Paquetes de compilación de Heroku. Mi teoría era que algún paquete de compilación de Heroku contendría los archivos binarios que necesitaba. Al final, la búsqueda me llevó aquí está. Lo descargué y lo descomprimí uml.tar.gz y encontré lo siguiente:

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*

¡Este es el binario slirp! ¿Él trabaja?

./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 se cae, ¡así que debería funcionar! Plantemos este binario en ~/bin/slirp:

cp slirp ~/bin/slirp

En caso de que el creador del paquete lo elimine, yo hizo un espejo.

Configuración de red

Ahora configuremos la red en nuestro kernel invitado. Actualizar opciones de inicio:

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

Ahora encendamos la red:

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

Los dos primeros comandos de configuración. /proc и /sys necesario para el trabajo ifconfig, que configura la interfaz de red para comunicarse con Slirp. Equipo route establece la tabla de enrutamiento del kernel para forzar que todo el tráfico se envíe a través del túnel Slirp. Comprobemos esto con 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

Работает!

Nota por .: Aparentemente, la publicación original se escribió en una computadora de escritorio con una tarjeta de red cableada o alguna otra configuración que no requiriera controladores adicionales. En un portátil con WiFi 8265 de Intel se produce un error al subir la red

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

Aparentemente, el kernel no puede comunicarse con el controlador de la tarjeta de red. Desafortunadamente, un intento de compilar el firmware en el kernel no solucionó la situación. En el momento de esta publicación, no fue posible encontrar una solución en esta configuración. En configuraciones más simples (por ejemplo, en Virtualbox), la interfaz aparece correctamente.

Automatizamos la redirección con el siguiente 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

Y márcalo como ejecutable:

chmod +x init.sh

Y luego haremos cambios en la línea de 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

Y repitamos:

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 red es estable!

archivo acoplable

Para que te resulte más fácil comprobar todo esto, he recopilado Dockerfile, que automatiza la mayoría de los pasos descritos y debería proporcionarle una configuración funcional. tambien tengo kernel preconfigurado, que tiene todo lo que se describe en el post. Pero es importante comprender que aquí solo he descrito la configuración mínima.

Espero que esta publicación te haya ayudado a comprender cómo abrir un kernel invitado. Resultó ser una especie de monstruo, pero la publicación fue concebida como una guía completa sobre cómo crear, instalar y configurar el modo de usuario en Linux en versiones modernas de sistemas operativos de esta familia. Los próximos pasos deberían incluir la instalación de servicios y otro software que ya esté dentro del sistema invitado. Dado que las imágenes del contenedor Docker son solo archivos comprimidos publicitados, debería poder extraer la imagen a través de docker exporty luego determine su ruta de instalación en la raíz del sistema de archivos del kernel invitado. Bueno, entonces ejecuta el script de shell.

Un agradecimiento especial a Rkeene de #lobsters en Freenode. Sin su ayuda para depurar a Slirp, no habría llegado tan lejos. No tengo idea de cómo funciona correctamente su sistema Slackware con slirp, pero mis sistemas Ubuntu y Alpine no aceptaron slirp y me sugirió el binario Rkeene. Pero a mí me basta con que al menos algo me funcione.

Fuente: habr.com

Añadir un comentario