Comment commencer à utiliser le mode utilisateur sous Linux

Introduction du traducteur : Dans le contexte de l'entrée massive dans nos vies de divers types de conteneurs, il peut être très intéressant et utile de savoir avec quelles technologies tout a commencé. Certaines d'entre elles peuvent être utilisées utilement à ce jour, mais tout le monde ne se souvient pas de ces méthodes (ou ne sait pas si elles n'ont pas été détectées au cours de leur développement rapide). L’une de ces technologies est User Mode Linux. L'auteur de l'original a beaucoup creusé, déterminant lesquels des anciens développements fonctionnent toujours et lesquels ne fonctionnent pas, et a élaboré quelque chose comme une instruction étape par étape sur la façon de se procurer un UML homebrew en 2k19. Et oui, nous avons invité l'auteur du message original sur Habr Clair, donc si vous avez des questions, posez-les en anglais dans les commentaires.

Comment commencer à utiliser le mode utilisateur sous Linux

Le mode utilisateur sous Linux est, en fait, un portage du noyau Linux sur lui-même. Ce mode vous permet d'exécuter un noyau Linux complet en tant que processus utilisateur et est couramment utilisé par les développeurs pour tester les pilotes. Mais ce mode est également utile comme outil d'isolation général, dont le principe s'apparente au fonctionnement des machines virtuelles. Ce mode offre plus d'isolation que Docker, mais moins qu'une machine virtuelle à part entière comme KVM ou Virtual Box.

En général, le mode utilisateur peut sembler un outil étrange et difficile à utiliser, mais il a toujours son utilité. Après tout, il s'agit d'un noyau Linux à part entière exécuté par un utilisateur non privilégié. Cette fonctionnalité permet à du code potentiellement non fiable de s'exécuter sans aucune menace pour la machine hôte. Et comme il s'agit d'un noyau à part entière, ses processus sont isolés de la machine hôte, c'est-à-dire les processus exécutés en mode utilisateur ne seront pas visibles par l'hôte. Ce n'est pas comme le conteneur Docker habituel, auquel cas la machine hôte voit toujours les processus à l'intérieur du référentiel. Regardez ce morceau de pstree provenant d'un de mes serveurs :

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

Et comparez cela au pstree du noyau Linux en mode utilisateur :

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

Lorsque je travaille avec des conteneurs Docker, je peux voir depuis l'hôte les noms des processus en cours d'exécution dans l'invité. Avec le mode utilisateur Linux, cela n'est pas possible. Qu'est-ce que ça veut dire? Cela signifie que les outils de surveillance qui s'exécutent via le sous-système d'audit de Linux ne vois pas processus exécutés dans le système invité. Mais dans certaines situations, cette fonctionnalité peut devenir une arme à double tranchant.

En général, l'intégralité du message ci-dessous est un recueil de recherches et de tentatives approximatives pour atteindre le résultat souhaité. Pour ce faire, j'ai dû utiliser divers outils anciens, lire les sources du noyau, effectuer un débogage intensif du code écrit à l'époque où j'étais encore à l'école primaire, et également bricoler les builds Heroku en utilisant un binaire spécial pour trouver les outils dont j'avais besoin. . Tout ce travail a amené les gars de mon IRC à me qualifier de magique. J'espère que cet article servira de documentation fiable pour permettre à quelqu'un d'essayer la même chose avec des noyaux et des versions de système d'exploitation plus récents.

réglage

La configuration du mode utilisateur Linux se fait en plusieurs étapes :

  • installer des dépendances sur l'hôte ;
  • télécharger le noyau Linux ;
  • configuration de la construction du noyau ;
  • assemblage du noyau ;
  • installation binaire ;
  • configurer le système de fichiers invité ;
  • sélection des paramètres de lancement du noyau ;
  • mettre en place un réseau d'invités ;
  • démarrer le noyau invité.

Je suppose que si vous décidez de le faire vous-même, vous ferez probablement tout ce qui est décrit dans un système de type Ubuntu ou Debian. J'ai essayé d'implémenter tout ce qui précède dans ma distribution préférée - Alpine, mais rien n'en est sorti, apparemment en raison du fait que le noyau Linux a des glibc-ismes à liaison dure pour les pilotes en mode utilisateur. Je prévois de signaler cela en amont une fois que j'aurai enfin compris le problème.

Installation des dépendances sur l'hôte

Ubuntu nécessite au moins les packages suivants pour construire le noyau Linux (en supposant une nouvelle installation) :

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

Vous pouvez les installer avec la commande suivante (en root ou avec sudo) :

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

Notez que l'exécution du programme de configuration du menu du noyau Linux nécessitera l'installation de libncurses-dev. Veuillez vous assurer qu'il est installé avec la commande suivante (en tant que root ou avec sudo) :

apt-get -y install libncurses-dev

Téléchargement du noyau

Décidez où télécharger, puis construisez le noyau. Pour cette opération, vous devrez allouer environ 1,3 Go d’espace disque dur, alors assurez-vous de l’avoir.

Après aller à kernel.org et obtenez l'URL pour télécharger le dernier noyau stable. Au moment de la rédaction, voici : https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

Téléchargez ce fichier en utilisant 'wget':

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

Et extrayez-le avec 'tar':

tar xJf linux-5.1.16.tar.xz

Nous entrons maintenant dans le répertoire créé lors du déballage de l'archive tar :

cd linux-5.1.16

Configuration de la construction du noyau

Le système de construction du noyau est un ensemble Fichiers Make с beaucoup outils et scripts personnalisés pour automatiser le processus. Tout d'abord, ouvrez le programme d'installation interactif :

make ARCH=um menuconfig

Il construira et affichera partiellement une boîte de dialogue pour vous. Quand '[Select]', vous pourrez configurer à l'aide des touches Espace ou Entrée. Naviguez dans la fenêtre, comme d'habitude, avec les flèches du clavier "haut" et "bas" et sélectionnez les éléments - "gauche" ou "droite".

Le pointeur de vue —> signifie que vous êtes dans un sous-menu, accessible par la touche Entrée. La solution pour s'en sortir passe évidemment par '[Exit]'.

Incluez les options suivantes dans '[Select]' et assurez-vous qu'ils ont un '[*]' à côté d'eux :

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

Voilà, vous pouvez quitter cette fenêtre en sélectionnant successivement '[Exit]'. Assurez-vous simplement que vous êtes invité à enregistrer la configuration à la fin et à sélectionner '[Yes]'.

Je vous recommande de jouer avec les options de construction du noyau après avoir lu cet article. Grâce à ces expériences, vous pouvez apprendre beaucoup en termes de compréhension du travail de la mécanique du noyau de bas niveau et de l'impact des différents drapeaux sur son assemblage.

Construire le noyau

Le noyau Linux est un gros programme qui fait beaucoup de choses. Même avec une configuration aussi minimale sur du matériel ancien, la construction peut prendre un certain temps. Construisez donc le noyau en utilisant la commande suivante :

make ARCH=um -j$(nproc)

Pour quoi? Cette commande indiquera à notre constructeur d'utiliser tous les cœurs et threads de processeur disponibles dans le processus de construction. Équipe $(nproc) à la fin de Build remplace la sortie de la commande nproc, qui fait partie de coreutils dans une version Ubuntu standard.

Après un certain temps, notre noyau sera compilé dans un fichier exécutable ./linux.

Installer le binaire

Étant donné que le mode utilisateur sous Linux crée un binaire standard, vous pouvez l'installer comme n'importe quel autre utilitaire. Voici comment j'ai procédé :

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

Il convient également de s'assurer que ~/bin est dans votre $PATH:

export PATH=$PATH:$HOME/bin

Configuration du système de fichiers invité

Créez un répertoire pour le système de fichiers invité :

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

Ouvrez alpinelinux.org et dans section de téléchargement trouver le lien de téléchargement réel MINI ROOT FILESYSTEM. Au moment de la rédaction, c'était :

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

Téléchargez cette archive tar en utilisant 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

Entrez maintenant dans le répertoire du système de fichiers invité et décompressez l'archive :

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

Les actions décrites créeront un petit modèle de système de fichiers. En raison de la nature du système, il sera extrêmement difficile d'installer des packages via le gestionnaire d'apk Alpine. Mais ce FS suffira à évaluer l'idée générale.

Nous avons également besoin d'un outil tini pour limiter la consommation de mémoire processus zombies notre noyau invité.

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

Création d'une ligne de commande du noyau

Le noyau Linux, comme la plupart des autres programmes, possède des arguments de ligne de commande accessibles en spécifiant la clé --help.

Lui-même - aider

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.

Ce panneau met en évidence les principaux paramètres du lancement. Exécutons le noyau avec l'ensemble minimum d'options requis :

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

Les lignes ci-dessus indiquent à notre noyau ce qui suit :

  • Supposons que le système de fichiers racine soit un pseudo-périphérique /dev/root.
  • Choisir hôtefs en tant que pilote de système de fichiers racine.
  • Montez le système de fichiers invité que nous avons créé sur le périphérique racine.
  • Et oui, en mode lecture-écriture.
  • Utilisez seulement 64 Mo de RAM (vous pouvez en utiliser beaucoup moins en fonction de ce que vous envisagez de faire, mais 64 Mo semble être la quantité optimale).
  • Le noyau démarre automatiquement /bin/sh comme init-processus.

Exécutez cette commande et vous devriez obtenir quelque chose comme ce qui suit :

Encore une feuille

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 manipulations ci-dessus nous donneront système invité au minimum, sans des choses comme /proc ou le nom d'hôte attribué. Par exemple, essayez les commandes suivantes :

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

Pour vous déconnecter de l'invité, tapez exit ou appuyez sur Ctrl-d. Cela tuera le shell suivi d'une panique du noyau :

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

Nous avons eu cette panique du noyau parce que le noyau Linux pense que le processus d'initialisation est toujours en cours. Sans cela, le système ne peut plus fonctionner et plante. Mais comme il s'agit d'un processus en mode utilisateur, la sortie résultante s'envoie à SIGABRT, ce qui aboutit à une sortie.

Configuration du réseau invité

Et c’est là que les choses commencent à mal tourner. Mise en réseau en mode utilisateur C'est sous Linux que tout le concept de « mode utilisateur » limité commence à s'effondrer. Après tout, généralement au niveau du système, le réseau est limité privilégié modes d'exécution pour nous tous, pour des raisons compréhensibles.

Note. par .: vous pouvez en savoir plus sur les différentes options pour travailler avec un réseau en UML ici.

Voyage à Slirp

Cependant, il existe un outil ancien et presque non pris en charge appelé Glisser, avec lequel User Mode Linux peut interagir avec le réseau. Il fonctionne un peu comme une pile TCP/IP au niveau de l'utilisateur et ne nécessite aucune autorisation système pour s'exécuter. Cet outil a été sorti en 1995, et la dernière mise à jour est datée Année 2006. Slirp est très vieux. Pendant la période sans support ni mise à jour, les compilateurs sont allés si loin que désormais cet outil ne peut être décrit que comme pourriture du code.

Téléchargeons donc Slirp depuis les référentiels Ubuntu et essayons de l'exécuter :

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 dieux. Installons le débogueur de Slirp et voyons si nous pouvons comprendre ce qui se passe ici :

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'erreur bat en nous cette ligne. Regardons le stacktrace, peut-être que quelque chose nous aidera là-bas :

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

Ici, nous voyons que le crash se produit lors du démarrage de la boucle principale lorsque slirp essaie de vérifier les délais d'attente. À ce stade, j'ai dû renoncer à essayer de déboguer. Mais voyons si Slirp construit à partir de sortes fonctionne. J'ai retéléchargé l'archive directement depuis le site Sourceforge, car faire glisser quelque chose à partir de là via la ligne de commande est pénible :

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

Ici, nous voyons des alertes concernant des fonctions intégrées non définies, c'est-à-dire sur l'impossibilité de lier le fichier binaire résultant. Il semble qu'entre 2006 et aujourd'hui, gcc a cessé de produire des symboles utilisés dans les fonctions intégrées des fichiers compilés intermédiaires. Essayons de remplacer le mot-clé inline à un commentaire vide et regardez le résultat :

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

Non. Cela ne fonctionne pas non plus. Je ne trouve toujours pas de symboles pour ces fonctions.

À ce stade, j'ai abandonné et j'ai commencé à chercher sur Github Packages de construction Heroku. Ma théorie était qu'un package de construction Heroku contiendrait les binaires dont j'avais besoin. Finalement, la recherche m'a conduit par ici. J'ai téléchargé et décompressé uml.tar.gz et j'ai trouvé ce qui suit :

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*

C'est un binaire slirp ! Est-ce que ça marche?

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

Il ne tombe pas – donc ça devrait fonctionner ! Plantons ce binaire dans ~/bin/slirp:

cp slirp ~/bin/slirp

Au cas où le créateur du package le supprimerait, je fait un miroir.

Configuration du réseau

Configurons maintenant le réseau sur notre noyau invité. Mettons à jour les paramètres de lancement:

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

Allumons maintenant le réseau :

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 deux premières commandes de configuration /proc и /sys nécessaire au travail ifconfig, qui définit l'interface réseau pour communiquer avec Slirp. Équipe route définit la table de routage du noyau pour forcer tout le trafic à être envoyé via le tunnel Slirp. Vérifions cela avec une requête 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

Cela fonctionne!

Remarque selon . : Apparemment, le message original a été écrit sur un ordinateur de bureau doté d'une carte réseau filaire ou d'une autre configuration ne nécessitant pas de pilotes supplémentaires. Sur un ordinateur portable avec WiFi 8265 d'Intel, une erreur se produit lors de la montée du réseau

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

Apparemment, le noyau ne peut pas communiquer avec le pilote de la carte réseau. Une tentative de compilation du firmware dans le noyau n’a malheureusement pas résolu la situation. Au moment de la publication, il n’était pas possible de trouver une solution dans cette configuration. Sur des configs plus simples (par exemple dans Virtualbox), l'interface monte correctement.

Automatisons la redirection avec le script shell suivant :

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

Et marquez-le comme exécutable :

chmod +x init.sh

Et puis nous apporterons des modifications à la ligne de commande du noyau :

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

Et répétons :

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

Le réseau est stable !

fichier Docker

Pour vous permettre de vérifier plus facilement tout cela, j'ai rassemblé Dockerfile, qui automatise la plupart des étapes décrites et devrait vous donner une configuration fonctionnelle. j'ai aussi noyau préconfiguré, qui contient tout ce qui est décrit dans le message. Mais il est important de comprendre que je n'ai décrit ici que les paramètres minimaux.

J'espère que cet article vous a aidé à comprendre comment afficher un noyau invité. Il s'est avéré être une sorte de monstre, mais la publication a été conçue comme un guide complet sur la création, l'installation et la configuration du mode utilisateur sous Linux sous les versions modernes des systèmes d'exploitation de cette famille. Les prochaines étapes devraient inclure l'installation de services et d'autres logiciels déjà présents dans le système invité. Étant donné que les images du conteneur Docker ne sont que des archives tar publiées, vous devriez pouvoir extraire l'image via docker export, puis déterminez son chemin d'installation à la racine du système de fichiers du noyau invité. Eh bien, exécutez le script shell.

Un merci spécial à Rkeene de #lobsters sur Freenode. Sans son aide pour déboguer Slirp, je ne serais pas arrivé aussi loin. Je n'ai aucune idée de la façon dont son système Slackware fonctionne correctement avec slirp, mais mes systèmes Ubuntu et Alpine n'ont pas accepté slirp et le binaire que Rkeene m'a suggéré. Mais il me suffit qu'au moins quelque chose fonctionne pour moi.

Source: habr.com

Ajouter un commentaire