So starten Sie mit dem Benutzer-Modus in Linux.

EinfĂŒhrung vom Übersetzer: Vor dem Hintergrund des massiven Einzugs verschiedener Container-Technologien in unser Leben kann es Ă€ußerst interessant und nĂŒtzlich sein, herauszufinden, mit welchen Technologien das alles begann. Einige davon lassen sich bis heute sinnvoll anwenden, aber nicht alle erinnern sich an diese AnsĂ€tze (oder wissen es, wenn sie deren turbulente Entwicklung nicht miterlebt haben). Eine dieser Technologien ist User Mode Linux. Der Autor des Originals hat sich grĂŒndlich mit den Ă€lteren Entwicklungen beschĂ€ftigt, um herauszufinden, was noch funktioniert und was nicht mehr, und hat eine Art Schritt-fĂŒr-Schritt-Anleitung zusammengestellt, wie man sich selbst ein hausgemachtes UML im Jahr 2019 einrichten kann. Und ja, wir haben den Autor des Originalbeitrags zu Habr eingeladen. Cadey, also wenn es Fragen gibt – stellen Sie diese bitte auf Englisch in den Kommentaren.

So starten Sie mit dem Benutzer-Modus in Linux.

Der User Mode in Linux ist praktisch der Port des Linux-Kernels auf sich selbst. Dieser Modus ermöglicht es, einen vollstĂ€ndigen Linux-Kernel als Benutzerprozess auszufĂŒhren und wird in der Regel von Entwicklern zum Testen von Treibern verwendet. Gleichzeitig ist dieser Modus auch ein nĂŒtzliches Werkzeug zur allgemeinen Isolierung, dessen Prinzipien einem virtuellen Maschinen Ă€hneln. Er bietet eine grĂ¶ĂŸere Isolation als Docker, jedoch weniger als eine vollstĂ€ndige virtuelle Maschine wie KVM oder VirtualBox.

Insgesamt mag der User Mode wie ein seltsames und kompliziertes Werkzeug erscheinen, aber er hat dennoch seine Anwendungsbereiche. Schließlich handelt es sich um einen vollwertigen Linux-Kernel, der von einem nicht privilegierten Benutzer betrieben wird. Diese Besonderheit erlaubt es, potenziell unsicheren Code auszufĂŒhren, ohne dass eine Bedrohung fĂŒr die Host-Maschine besteht. Da es sich um einen vollstĂ€ndigen Kernel handelt, sind seine Prozesse von der Host-Maschine isoliert, das heißt, Prozesse, die im User Mode laufen, sind fĂŒr den Host nicht sichtbar. Dies unterscheidet sich von einem herkömmlichen Docker-Container, bei dem die Host-Maschine immer die Prozesse innerhalb des Containers sehen kann. Hier ein Ausschnitt von pstree von einem meiner Server:

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

Vergleichen Sie dies mit dem pstree des Linux-Kernels im Benutzerbereich:

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

Wenn ich mit Docker-Containern arbeite, kann ich vom Host aus die Prozessnamen sehen, die im Gastbetriebssystem ausgefĂŒhrt werden. Mit dem Linux-Benutzermodus ist dies nicht möglich. Was bedeutet das? Es bedeutet, dass Überwachungswerkzeuge, die ĂŒber das Auditsystem von Linux arbeiten, sehen nicht die Prozesse, die im Gastbetriebssystem ausgefĂŒhrt werden. In manchen Situationen kann dieses Merkmal jedoch zu einem zweischneidigen Schwert werden.

Im Grunde genommen ist der gesamte nachfolgende Beitrag eine Sammlung von Untersuchungen und groben Versuchen, das gewĂŒnschte Ergebnis zu erzielen. Dazu musste ich verschiedene alte Werkzeuge verwenden, den Quellcode des Kernels studieren, intensives Debugging von Code durchfĂŒhren, der in einer Zeit geschrieben wurde, als ich noch zur Grundschule ging, und auch in Heroku-Builds mit einem speziellen Binary nach den benötigten Werkzeugen suchen. All diese Arbeit fĂŒhrte dazu, dass mich die Jungs in meinem IRC eine Hexe (magic) nannten. Ich hoffe, dass dieser Beitrag fĂŒr jemanden als zuverlĂ€ssige Dokumentation dient, um das Gleiche zu erreichen, aber mit neueren Kernen und Betriebssystemversionen.

Konfiguration

Die Einrichtung des Linux User Mode erfolgt in mehreren Schritten:

  • Installation der AbhĂ€ngigkeiten auf dem Host;
  • Herunterladen des Linux-Kernels;
  • Konfiguration des Kernel-Builds;
  • Build des Kernels;
  • Installation des Binaries;
  • Einrichtung des Gast-Dateisystems;
  • Festlegung der Kernel-Startparameter;
  • Einrichtung des Gastnetzwerks;
  • Start des Gastkernels.

Ich gehe davon aus, dass Sie, wenn Sie versuchen, das selbst zu erledigen, wahrscheinlich alles in einem Ubuntu- oder Debian-Ă€hnlichen System durchfĂŒhren werden. Ich habe versucht, alles oben Beschriebene in meiner bevorzugten Distribution – Alpine – umzusetzen, aber es hat nicht geklappt, offenbar wegen des engen Zusammenhangs des Linux-Kernels mit glibc-isms fĂŒr Treiber im User Mode. Ich plane, dies upstream zu melden, sobald ich das Problem vollstĂ€ndig verstanden habe.

Installation der AbhÀngigkeiten auf dem Host

Ubuntu benötigt mindestens die folgenden Pakete zum Kompilieren des Linux-Kernels (bei einer sauberen Installation):

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

Sie können sie mit dem folgenden Befehl installieren (mit Root-Rechten oder mit sudo):

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

Bitte beachten Sie, dass das AusfĂŒhren des KonfigurationsmenĂŒprogramms fĂŒr den Linux-Kernel die Installation von libncurses-devbenötigt. Bitte stellen Sie sicher, dass es mit dem folgenden Befehl installiert ist (mit Root-Rechten oder mit sudo):

apt-get -y install libncurses-dev

Herunterladen des Kernels

Legen Sie einen Ort fĂŒr den Download und die anschließende Kompilierung des Kernels fest. FĂŒr diesen Vorgang benötigen Sie etwa 1,3 GB Speicherplatz auf der Festplatte, stellen Sie also sicher, dass dieser verfĂŒgbar ist.

Gehen Sie anschließend zu kernel.org und holen Sie sich die URL fĂŒr den Download der neuesten stabilen Version des Kernels. Zum Zeitpunkt des Schreibens ist das: https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

Laden Sie diese Datei mit 'wget':

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

Und entpacken Sie sie mit 'tar':

tar xJf linux-5.1.16.tar.xz

Wechseln Sie nun in das Verzeichnis, das wÀhrend des Entpackens des Tarballs erstellt wurde:

cd linux-5.1.16

Kernel-Bau konfigurieren

Das System zur Kernkompilierung besteht aus einer Reihe von Make-Dateien mit und einer Vielzahl von benutzerdefinierten Werkzeugen und Skripts zur Automatisierung des Prozesses. Beginnen Sie, indem Sie das interaktive Konfigurationsprogramm öffnen:

make ARCH=um menuconfig

Es wird teilweise die Kompilierung durchfĂŒhren und Ihnen ein Dialogfenster anzeigen. Wenn am unteren Rand des Fensters '[Select]' angezeigt wird, können Sie mit der Leertaste oder Enter mit der Konfiguration beginnen. Die Navigation im Fenster erfolgt wie gewohnt mit den Pfeiltasten 'nach oben' und 'nach unten', und das AuswĂ€hlen von Elementen erfolgt mit 'nach links' oder 'nach rechts'.

Der Hinweis —> bedeutet, dass Sie sich im UntermenĂŒ befinden, dessen Zugang ĂŒber die Eingabetaste erfolgt. Der Ausgang erfolgt offensichtlich durch ‘[Exit]‘.

Aktivieren Sie die folgenden Optionen in ‘[Select]‘ und stellen Sie sicher, dass neben ihnen das Zeichen ‘[*]’ vorhanden ist:

UML-spezifische Optionen:
  - Host-Dateisystem
Netzwerksupport (aktivieren Sie dies, um das UntermenĂŒ anzuzeigen):
  - Netzwerkoptionen:
    - TCP/IP-Netzwerk
UML-NetzwerkgerÀte:
  - Virtuelles NetzwerkgerÀt
  - SLiRP-Transport

Sie können dieses Fenster verlassen, indem Sie nacheinander ‘[Exit]‘ auswĂ€hlen. Stellen Sie nur sicher, dass Sie am Ende dazu aufgefordert werden, die Konfiguration zu speichern, und wĂ€hlen Sie ‘[Yes]‘.

Ich empfehle Ihnen, mit den Kernel-Bauparametern zu experimentieren, nachdem Sie diesen Beitrag gelesen haben. Durch diese Experimente können Sie viel ĂŒber das VerstĂ€ndnis der Funktionsweise der Low-Level-Kernel-Mechanismen und den Einfluss verschiedener Flags auf den Build gewinnen.

Kernel-Bau

Der Linux-Kernel ist ein umfangreiches Programm, das sich mit vielen Dingen beschÀftigt. Selbst mit einer so minimalen Konfiguration auf alter Hardware kann der Build viel Zeit in Anspruch nehmen. Daher bauen Sie den Kernel mit dem folgenden Befehl:

make ARCH=um -j$(nproc)

Warum? Dieser Befehl weist unseren Builder an, alle verfĂŒgbaren Kerne und Threads des Prozessors beim Build-Prozess zu nutzen. Der Befehl $(nproc) setzt am Ende des Builds die Ausgabe des Befehls nproc, der Teil von coreutils in der Standardinstallation von Ubuntu ist.

Nach einiger Zeit wird unser Kern in eine ausfĂŒhrbare Datei ./linux.

installiert.

Da der User Mode in Linux eine regulÀre BinÀrdatei erzeugt, können Sie ihn wie jede andere Utility installieren. So habe ich es gemacht:

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

Es ist auch wichtig, sicherzustellen, dass ~/bin in Ihrem $PATH:

export PATH=$PATH:$HOME/bin

Einrichtung des Gastspeichersystems

Erstellen Sie ein Verzeichnis fĂŒr das Gastspeichersystem:

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

Besuchen Sie alpinelinux.org und finden Sie im Downloadbereich den aktuellen Link zum Herunterladen MINI ROOT DATEISYSTEM. Zum Zeitpunkt der Veröffentlichung war dies:

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

Laden Sie dieses Tarball mit wget herunter:

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

Gehen Sie jetzt in das Verzeichnis des Gastspeichersystems und entpacken Sie das Archiv:

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

Die beschriebenen Schritte erstellen ein kleines Dateisystem-Template. Aufgrund der Eigenheiten des Systems wird es sehr schwierig sein, Pakete ĂŒber den Alpine apk-Manager zu installieren. Aber dieses FS wird ausreichen, um die allgemeine Idee zu bewerten.

Wir benötigen auch ein Werkzeug tini um den Speicherverbrauch von Zombie-Prozessen in unserem Gastkern zu reduzieren.

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

Erstellung der Kernel-Befehlszeile

Im Linux-Kernel, wie in den meisten anderen Programmen, gibt es Befehlszeilenargumente, die mit dem SchlĂŒssel --help.

abgerufen werden können.

linux --help
User Mode Linux v5.1.16
        verfĂŒgbar unter http://user-mode-linux.sourceforge.net/

--showconfig
    Gibt die Konfigurationsdatei aus, aus der dieses UML-BinÀrdatei erstellt wurde.

iomem=,
    Konfiguriert  als IO-Speicherbereich mit dem Namen .

mem=
    Dies steuert, wie viel "physikalischer" Speicher der Kernel fĂŒr das System zuweist. Die GrĂ¶ĂŸe wird als Zahl gefolgt von einem der Zeichen 'k', 'K', 'm', 'M' angegeben, die allgemein bekannt sind. Dies steht nicht im Zusammenhang mit der Menge an Speicher im Host. Es kann mehr sein, und der Überschuss, falls ĂŒberhaupt verwendet, wird einfach ausgelagert.
        Beispiel: mem=64M

--help
    Gibt diese Nachricht aus.

debug
    dieses Flag ist nicht erforderlich, um gdb im UML im skas-Modus auszufĂŒhren

root=
    Dies wird tatsĂ€chlich vom generischen Kernel genau auf die gleiche Weise verwendet wie in jedem anderen Kernel. Wenn Sie eine Anzahl von BlockgerĂ€ten konfigurieren und von etwas anderem als ubd0 booten möchten, wĂŒrden Sie etwas verwenden wie:
        root=/dev/ubd5

--version
    Gibt die Versionsnummer des Kernels aus.

umid=
    Dies wird verwendet, um dieser UML-Maschine eine eindeutige IdentitÀt zuzuweisen und wird zur Benennung der PID-Datei und des Verwaltungskonsole-Sockets verwendet.

con[0-9]*=
    Schließt eine Konsole oder serielle Linie an einen Host-Kanal an. Siehe http://user-mode-linux.sourceforge.net/old/input.html fĂŒr eine vollstĂ€ndige Beschreibung dieses Schalters.

eth[0-9]+=,
    Konfiguriert ein NetzwerkgerÀt.
    
aio=2.4
    Dies wird verwendet, um UML dazu zu zwingen, den AIO-Stil von 2.4 zu verwenden, auch wenn 2.6 AIO verfĂŒgbar ist.  2.4 AIO ist ein einzelner Thread, der eine Anfrage zur Zeit synchron verarbeitet. 2.6 AIO ist ein Thread, der die 2.6 AIO-Schnittstelle verwendet, um eine beliebige Anzahl von ausstehenden Anfragen zu bearbeiten.  2.6 AIO ist im tt-Modus, auf 2.4-Hosts oder wenn UML mit /usr/include/linux/aio_abi.h nicht verfĂŒgbar erstellt wird, nicht verfĂŒgbar. Viele Distributionen enthalten aio_abi.h nicht, also mĂŒssen Sie es aus einem Kernel-Verzeichnis nach /usr/include/linux kopieren, um ein AIO-fĂ€higes UML zu erstellen.

nosysemu
    Deaktiviert den Syscall-Emulationspatch fĂŒr ptrace (SYSEMU).
    SYSEMU ist ein Leistungspatch, der von Laurent Vivier eingefĂŒhrt wurde. Er Ă€ndert das Verhalten von ptrace() und hilft, die Host-Kontextwechselraten zu reduzieren. Um es zum Laufen zu bringen, benötigen Sie auch einen Kernel-Patch fĂŒr Ihren Host. Siehe http://perso.wanadoo.fr/laurent.vivier/UML/ fĂŒr weitere Informationen.

uml_dir=
    Der Speicherort fĂŒr die PID- und UMID-Dateien.

quiet
    Deaktiviert Informationsnachrichten wÀhrend des Bootvorgangs.

hostfs=,,...
    Dies wird verwendet, um die Hostfs-Parameter festzulegen. Das Argument fĂŒr das Stammverzeichnis wird verwendet, um alle Hostfs-Mounts innerhalb des angegebenen Verzeichnisbaums auf dem Host zu beschrĂ€nken. Wenn dies nicht angegeben ist, kann ein Benutzer innerhalb von UML alles auf dem Host einhĂ€ngen, das fĂŒr den Benutzer zugĂ€nglich ist, der es ausfĂŒhrt.
    Das einzige derzeit unterstĂŒtzte Flag ist 'append', das angibt, dass alle von Hostfs geöffneten Dateien im AnhĂ€ngemodus geöffnet werden.

Dieses Dokument beleuchtet die grundlegenden Startparameter. Lassen Sie uns den Kernel mit dem minimal notwendigen Satz von Optionen starten:

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

Die obigen Zeilen informieren unseren Kernel Folgendes:

  • Angenommen, das Wurzel-Dateisystem ist ein Pseudo-GerĂ€t. /dev/root.
  • WĂ€hlen Sie hostfs als Treiber fĂŒr das Wurzel-Dateisystem.
  • Montieren Sie das Gast-Dateisystem, das wir im root-GerĂ€t erstellt haben.
  • Und ja, im Lese-Schreib-Modus.
  • Verwenden Sie nur 64 Megabyte RAM (Sie können viel weniger verwenden, je nachdem, was Sie vorhaben, aber 64 MB scheinen optimal zu sein).
  • Der Kernel startet automatisch /bin/sh als init-Prozess.

FĂŒhren Sie diesen Befehl aus, und Sie sollten etwas Ähnliches wie das Folgende erhalten:

Noch ein Dokument

Kern-Dump-Limits :
        weich - 0
        hart - KEINE
ÜberprĂŒfung, ob ptrace Systemaufrufnummern Ă€ndern kann...OK
ÜberprĂŒfung des syscall Emulations-Patches fĂŒr ptrace...OK
ÜberprĂŒfung des erweiterten syscall Emulations-Patches fĂŒr ptrace...OK
ÜberprĂŒfung der Umgebungsvariablen fĂŒr ein tempdir...keine gefunden
ÜberprĂŒfung, ob /dev/shm auf tmpfs ist...OK
ÜberprĂŒfung von PROT_EXEC mmap in /dev/shm...OK
32137216 Bytes zu physikalischem Speicher hinzugefĂŒgt, um die exec-shield-LĂŒcke auszugleichen
Linux-Version 5.1.16 (cadey@kahless) (gcc-Version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #30 So Jul 7 18:57:19 UTC 2019
1 Zonelisten erstellt, MobilitÀtsgruppierung aktiv. Gesamtseiten: 23898
Kommandozeilenparameter des Kernels: root=/dev/root rootflags=/home/cadey/dl/uml/alpine rootfstype=hostfs rw mem=64M init=/bin/sh
Dentry-Cache-Hash-TabelleneintrÀge: 16384 (Ordnung: 5, 131072 Bytes)
Inode-Cache-Hash-TabelleneintrÀge: 8192 (Ordnung: 4, 65536 Bytes)
Speicher: 59584K/96920K verfĂŒgbar (2692K Kernelcode, 708K rwdata, 588K rodata, 104K init, 244K bss, 37336K reserviert, 0K cma-reserviert)
SLUB: HWalign=64, Ordre=0-3, MinObjects=0, CPUs=1, Nodes=1
NR_IRQS: 15
ZeitzÀhler: timer: maske: 0xffffffffffffffff max_cycles: 0x1cd42e205, max_idle_ns: 881590404426 ns
Kalibrierung der Verzögerungsschleife... 7479.29 BogoMIPS (lpj=37396480)
pid_max: Standard: 32768 Minimum: 301
Mount-Cache-Hash-TabelleneintrÀge: 512 (Ordnung: 0, 4096 Bytes)
Mountpoint-Cache-Hash-TabelleneintrÀge: 512 (Ordnung: 0, 4096 Bytes)
ÜberprĂŒfung, ob die Host-PTYs SIGIO-Output unterstĂŒtzen...Ja
ÜberprĂŒfung, ob die Host-PTYs SIGIO bei Schließung unterstĂŒtzen...Nein, workaround aktivieren
devtmpfs: initialisiert
random: get_random_bytes aufgerufen von setup_net+0x48/0x1e0 mit crng_init=0
Verwendung von 2.6 Host AIO
ZeitzÀhler: jiffies: maske: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex-Hash-TabelleneintrÀge: 256 (Ordnung: 0, 6144 Bytes)
NET: Registriert Protokollfamilie 16
ZeitzÀhler: Auf ZeitzÀhler umgeschaltet
NET: Registriert Protokollfamilie 2
tcp_listen_portaddr_hash Hash-TabelleneintrÀge: 256 (Ordnung: 0, 4096 Bytes)
TCP etablierte Hash-TabelleneintrÀge: 1024 (Ordnung: 1, 8192 Bytes)
TCP Bind-Hash-TabelleneintrÀge: 1024 (Ordnung: 1, 8192 Bytes)
TCP: Hash-Tabellen konfiguriert (etabliert 1024 bind 1024)
UDP Hash-TabelleneintrÀge: 256 (Ordnung: 1, 8192 Bytes)
UDP-Lite Hash-TabelleneintrÀge: 256 (Ordnung: 1, 8192 Bytes)
NET: Registriert Protokollfamilie 1
Konsole [stderr0] deaktiviert
mconsole (Version 2) auf /home/cadey/.uml/tEwIjm/mconsole initialisiert
ÜberprĂŒfung der UnterstĂŒtzung von MADV_REMOVE durch den Host...OK
workingset: timestamp_bits=62 max_order=14 bucket_order=0
Blockschicht SCSI generisch (bsg) Treiberversion 0.4 geladen (major 254)
io-Scheduler noop registriert (Standard)
io-Scheduler bfq registriert
loop: Modul geladen
NET: Registriert Protokollfamilie 17
Standard Console Driver initialisiert
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 1 fehlgeschlagen: Konfiguration fehlgeschlagen
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 2 fehlgeschlagen: Konfiguration fehlgeschlagen
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 3 fehlgeschlagen: Konfiguration fehlgeschlagen
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 4 fehlgeschlagen: Konfiguration fehlgeschlagen
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 5 fehlgeschlagen: Konfiguration fehlgeschlagen
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 6 fehlgeschlagen: Konfiguration fehlgeschlagen
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 7 fehlgeschlagen: Konfiguration fehlgeschlagen
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 8 fehlgeschlagen: Konfiguration fehlgeschlagen
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 9 fehlgeschlagen: Konfiguration fehlgeschlagen
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 10 fehlgeschlagen: Konfiguration fehlgeschlagen
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 11 fehlgeschlagen: Konfiguration fehlgeschlagen
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 12 fehlgeschlagen: Konfiguration fehlgeschlagen
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 13 fehlgeschlagen: Konfiguration fehlgeschlagen
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 14 fehlgeschlagen: Konfiguration fehlgeschlagen
Verwendung eines Kanaltyps, der außerhalb von UML konfiguriert ist
setup_one_line fĂŒr GerĂ€t 15 fehlgeschlagen: Konfiguration fehlgeschlagen
Konsole auf /dev/tty0 initialisiert
Konsole [tty0] aktiviert
Konsole [mc-1] aktiviert
Fehler bei der Initialisierung des ubd-GerĂ€ts 0: GrĂ¶ĂŸe der GerĂ€tedatei konnte nicht bestimmt werden
VFS: Root (hostfs-Dateisystem) auf GerÀt 0:11 eingehÀngt.
devtmpfs: eingehÀngt
Diese Architektur hat keinen Schutz des Kernelspeichers.
FĂŒhren Sie /bin/sh als Init-Prozess aus
/bin/sh: kann tty nicht zugreifen; Jobkontrolle deaktiviert
random: schnelle Initialisierung abgeschlossen
/ # 

Die oben genannten Manipulationen fĂŒhren uns zu einem minimalen Gast-System, ohne solche Dinge wie /proc oder einen zugewiesenen Hostnamen. Versuchen Sie als Beispiel, die folgenden Befehle auszufĂŒhren:

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

Um das Gast-System zu verlassen, geben Sie exit oder drĂŒcken Sie Steuerung-d. Dies wird die Shell mit einem anschließenden Kernel-Panik beenden:

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

Wir haben diesen Kernel-Panik erhalten, weil der Linux-Kernel denkt, dass der Initialisierungsprozess immer lĂ€uft. Ohne ihn kann das System nicht mehr arbeiten und beendet sich. Da es sich jedoch um einen Benutzermodus-Prozess handelt, sendet das erhaltene Ergebnis sich selbst an SIGABRT, was zu einem Ausstieg fĂŒhrt.

Einrichten des Gast-Netzwerks

Hier beginnt es jedoch, vom Plan abzuweichen. Das Netzwerk in User Mode Linux ist der Bereich, in dem das gesamte Konzept des eingeschrĂ€nkten 'Benutzermodus' auseinanderfĂ€llt. Denn normalerweise ist das Netzwerk auf Systemebene eingeschrĂ€nkt durch privilegierte AusfĂŒhrungsmodi aus uns allen verstĂ€ndlichen GrĂŒnden.

Hinweis: Mehr ĂŒber verschiedene Netzwerk-Operationen in UML können Sie lesen hier.

Reise nach slirp

Es gibt jedoch ein altes und nahezu nicht unterstĂŒtztes Werkzeug namens Slirp, mit dem User Mode Linux mit dem Netzwerk interagieren kann. Er funktioniert Ă€hnlich wie ein TCP/IP-Stack auf Benutzerebene und benötigt keine Systemberechtigungen zum AusfĂŒhren. Dieses Werkzeug wurde 1995 veröffentlicht, und das letzte Update stammt aus dem Jahr 2006. Slirp ist sehr alt. Über die Zeit ohne UnterstĂŒtzung und Updates sind die Compiler so weit gegangen, dass dieses Werkzeug nur noch als «Code-Rot».

bezeichnet werden kann. Lassen Sie uns Slirp aus den Ubuntu-Repositorys installieren und versuchen, es zu starten:

sudo apt-get install slirp
/usr/bin/slirp
Slirp v1.0.17 (BETA)

Copyright (c) 1995,1996 Danny Gasparovski und andere.
Alle Rechte vorbehalten.
Dieses Programm ist urheberrechtlich geschĂŒtzt, freie Software.
Bitte lesen Sie die Datei COPYRIGHT, die mit dem Slirp-Paket geliefert wurde, fĂŒr die Nutzungsbedingungen.

IP-Adresse des Slirp-Hosts: 127.0.0.1
IP-Adressen Ihrer DNS(s): 1.1.1.1, 10.77.0.7
Ihre Adresse ist 10.0.2.15
(oder alles andere, was Sie möchten)

Tippen Sie fĂŒnf Nullen (0), um zu beenden.

[automatische Erkennung SLIP/CSLIP, MTU 1500, MRU 1500, 115200 baud]

SLiRP bereit ...
fisch: “/usr/bin/slirp” beendet durch Signal SIGSEGV (Adressgrenzfehler)

Oh, je. Lassen Sie uns einen Debugger fĂŒr Slirp installieren und sehen, ob wir herausfinden können, was hier vor sich geht:

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.
Lizenz GPLv3+: GNU GPL-Version 3 oder höher 
Dies ist freie Software: Sie sind frei, sie zu Àndern und weiterzugeben.
Es gibt KEINE GARANTIE, soweit es das Gesetz erlaubt. Geben Sie "show copying" ein
und "show warranty" fĂŒr Details.
Dieses GDB wurde als "x86_64-linux-gnu" konfiguriert.
Geben Sie "show configuration" fĂŒr Konfigurationsdetails ein.
FĂŒr Anweisungen zur Fehlerberichterstattung siehe:
.
Finden Sie das GDB-Handbuch und andere Dokumentationsressourcen online unter:
.
FĂŒr Hilfe geben Sie "help" ein.
Geben Sie "apropos word" ein, um nach Befehlen zu suchen, die mit "word" zu tun haben...
Symbole lesen von /usr/bin/slirp...Symbole lesen von /usr/lib/debug/.build-id/c6/2e75b69581a1ad85f72ac32c0d7af913d4861f.debug...fertig.
fertig.
(gdb) run
Starte Programm: /usr/bin/slirp
Slirp v1.0.17 (BETA)

Copyright (c) 1995,1996 Danny Gasparovski und andere.
Alle Rechte vorbehalten.
Dieses Programm ist urheberrechtlich geschĂŒtzt, freie Software.
Bitte lesen Sie die Datei COPYRIGHT, die mit dem Slirp
Paket geliefert wurde, fĂŒr die Bedingungen des Urheberrechts.

IP-Adresse des Slirp-Hosts: 127.0.0.1
IP-Adresse Ihrer DNS(s): 1.1.1.1, 10.77.0.7
Ihre Adresse ist 10.0.2.15
(oder etwas anderes, das Sie möchten)

Geben Sie fĂŒnf Nullstellen (0) ein, um zu beenden.

[autodetect SLIP/CSLIP, MTU 1500, MRU 1500, 115200 baud]

SLiRP Bereit ...

Programm erhielt Signal SIGSEGV, Segmentierungsfehler.
                                                    ip_slowtimo () in ip_input.c:457
457     ip_input.c: Datei oder Verzeichnis nicht gefunden.

Der Fehler tritt bei uns in der dieser Zeile. Lassen Sie uns den Stacktrace ansehen, vielleicht hilft uns das weiter:

(gdb) bt full
#0  ip_slowtimo () at ip_input.c:457
        fp = 0x55784a40
#1  0x000055555556a57c in main_loop () at ./main.c:980
        so = 
        so_next = 
        timeout = {tv_sec = 0, tv_usec = 0}
        ret = 0
        nfds = 0
        ttyp = 
        ttyp2 = 
        best_time = 
        tmp_time = 
#2  0x000055555555b116 in main (argc=1, argv=0x7fffffffdc58) at ./main.c:95
No locals.

Hier sehen wir, dass der Fehler wĂ€hrend des Starts der Hauptschleife auftritt, wenn Slirp versucht, die ZeitĂŒberschreitungen zu ĂŒberprĂŒfen. An diesem Punkt hĂ€tte ich aufhören sollen, mit dem Debugging fortzufahren. Aber schauen wir mal, ob Slirp, der aus den Quellcodes gebaut wurde, funktioniert. Ich habe das Archiv direkt von der Website heruntergeladen. Sourceforge, denn etwas von dort ĂŒber die Kommandozeile herunterzuladen, ist mĂŒhsam:

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

Hier sehen wir Warnungen zu undefinierten eingebetteten Funktionen, also dass es unmöglich ist, die resultierende BinĂ€rdatei zu verlinken. Es scheint, dass GCC zwischen 2006 und diesem Zeitpunkt aufgehört hat, die Symbole zu erstellen, die in den eingebetteten Funktionen von zwischenkompilierten Dateien verwendet werden. Lassen Sie uns versuchen, das SchlĂŒsselwort inline Auf den leeren Kommentar und sehen wir mal, was das Ergebnis ist:

vi slirp.h
:6
a

#define inline /**/

:wq
make

Nein. Das funktioniert auch nicht. Ich kann die Symbole dieser Funktionen weiterhin nicht finden.

An diesem Punkt habe ich aufgegeben und angefangen, auf Github zu suchen. Heroku-Build-Pakete. Meine Theorie basierte darauf, dass in irgendeinem Build-Paket von Heroku die benötigten BinĂ€rdateien enthalten sein wĂŒrden. Letztendlich fĂŒhrte mich die Suche hierhin. Ich habe heruntergeladen und entpackt uml.tar.gz und fand Folgendes:

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*

Das ist die BinÀrdatei slirp! Funktioniert die auch?

./slirp
Slirp v1.0.17 (BETA) FULL_BOLT

Copyright (c) 1995,1996 Danny Gasparovski und andere.
Alle Rechte vorbehalten.
Dieses Programm ist urheberrechtlich geschĂŒtzt, freie Software.
Bitte lesen Sie die Datei COPYRIGHT, die mit dem Slirp-Paket geliefert wurde, fĂŒr die Bedingungen und Konditionen des Urheberrechts.

IP-Adresse des Slirp-Hosts: 127.0.0.1
IP-Adresse Ihres DNS/DNS: 1.1.1.1, 10.77.0.7
Ihre Adresse ist 10.0.2.15
(oder alles andere, was Sie möchten)

Geben Sie fĂŒnf Nullen (0) ein, um zu beenden.

[Autodetect SLIP/CSLIP, MTU 1500, MRU 1500]

SLiRP bereit ...

Es stĂŒrzt nicht ab – also sollte es funktionieren! Lasst uns diese BinĂ€rdatei in ~/bin/slirp:

cp slirp ~/bin/slirp

Falls der Paket-Ersteller es löscht, habe ich ein Spiegelbild erstellt.

Netzwerkkonfiguration

Lassen Sie uns jetzt das Netzwerk auf unserem Gast-Kernel konfigurieren. Aktualisieren wir die Boot-Parameter:

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

Jetzt aktivieren wir das Netzwerk:

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

Die ersten beiden Konfigurationsbefehle /proc und /sys sind erforderlich, um ifconfig, das das Netzwerk-Interface zur Kommunikation mit Slirp einrichtet. Der Befehl route stellt die Kernel-Routing-Tabelle ein, um den gesamten Verkehr ĂŒber den Slirp-Tunnel zu leiten. Lassen Sie uns das mit einer DNS-Abfrage ĂŒberprĂŒfen:

nslookup google.com 8.8.8.8
Server:    8.8.8.8
Adresse 1: 8.8.8.8 dns.google

Name:      google.com
Adresse 1: 172.217.12.206 lga25s63-in-f14.1e100.net
Adresse 2: 2607:f8b0:4006:81b::200e lga25s63-in-x0e.1e100.net

Es funktioniert!

Hinweis: Anscheinend wurde der ursprĂŒngliche Beitrag auf einem Desktop mit einer kabelgebundenen Netzwerkkarte oder einer anderen Konfiguration ohne zusĂ€tzliche Treiber verfasst. Bei einem Laptop mit Intel WiFi 8265 tritt jedoch bei der Aktivierung des Netzwerks ein Fehler auf.

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

Offensichtlich kann der Kernel nicht mit dem Treiber der Netzwerkkarte kommunizieren. Der Versuch, die Firmware in den Kernel zu kompilieren, hat die Situation leider nicht verbessert. Zum Zeitpunkt der Veröffentlichung war es nicht möglich, eine Lösung in dieser Konfiguration zu finden. Bei einfacheren Konfigurationen (zum Beispiel in VirtualBox) wird das Interface korrekt hochgefahren.

Lassen Sie uns die Weiterleitung mit dem folgenden Shell-Skript automatisieren:

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

Und markieren wir es als ausfĂŒhrbar:

chmod +x init.sh

Und dann nehmen wir Änderungen an der Kernel-Befehlszeile vor:

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

Und wiederholen wir:

SLiRP Bereit ...
Netzwerk konfiguriert
/bin/sh: kann tty nicht erreichen; Jobkontrolle ausgeschaltet

nslookup google.com 8.8.8.8
Server:    8.8.8.8
Adresse 1: 8.8.8.8 dns.google

Name:      google.com
Adresse 1: 172.217.12.206 lga25s63-in-f14.1e100.net
Adresse 2: 2607:f8b0:4004:800::200e iad30s09-in-x0e.1e100.net

Das Netzwerk funktioniert stabil!

Docker-Datei

Um es Ihnen leichter zu machen, habe ich Dockerfile, das die meisten beschriebenen Schritte automatisiert und Ihnen eine funktionierende Konfiguration bereitstellen sollte. Außerdem habe ich eine fertige Kernel-Konfiguration, die alles enthĂ€lt, was im Beitrag beschrieben ist. Es ist jedoch wichtig zu verstehen, dass ich hier nur die minimale Konfiguration dargelegt habe.

Ich hoffe, dieser Beitrag hat Ihnen geholfen zu verstehen, wie man einen Gastkern aufsetzt. Es ist ein ziemlich komplexes Thema, aber der Artikel soll als umfassende Anleitung zur Erstellung, Installation und Konfiguration des User Mode in Linux unter aktuellen Betriebssystemversionen dienen. Die nĂ€chsten Schritte sollten die Installation von Diensten und anderer Software innerhalb des Gast-Systems umfassen. Da Docker-Images einfach nur umbreitete tar-Archive sind, sollten Sie in der Lage sein, das Image ĂŒber docker export, zu extrahieren und dann den Installationspfad im Stammverzeichnis des Gastkerns zu bestimmen. Danach fĂŒhren Sie das Shell-Skript aus.

Ein besonderer Dank geht an Rkeene von #lobsters auf Freenode. Ohne seine Hilfe bei der Fehlersuche mit Slirp wĂ€re ich nicht so weit gekommen. Ich habe keine Ahnung, wie sein Slackware-System korrekt mit Slirp funktioniert, aber meine Ubuntu- und Alpine-Systeme haben Slirp und die mir vorgeschlagene Rkeene-BinĂ€rdatei nicht angenommen. Aber ich bin schon zufrieden, dass ĂŒberhaupt etwas funktioniert.

Quelle: habr.com

Kaufen Sie zuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz, VPS VDS-Server đŸ”„ Kaufen Sie zuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster