Hoe te beginnen met het gebruik van User Mode in Linux

Introductie van de vertaler: Tegen de achtergrond van de massale komst van verschillende soorten containers in ons leven kan het best interessant en nuttig zijn om te weten met welke technologieën dit allemaal ooit is begonnen. Sommige hiervan kunnen nog steeds nuttig worden toegepast, maar niet iedereen is zich bewust van deze methoden (of weet ze niet, als ze niet hebben meegemaakt tijdens hun bloeiperiode). Een van deze technologieën is User Mode Linux. De auteur van het origineel heeft grondig onderzocht wat van de oude oplossingen nog werkt en wat niet zo goed meer werkt, en heeft iets als een stapsgewijze handleiding verzameld over hoe je zelf een thuismade UML opstelt in 2019. En ja, we hebben de auteur van het originele bericht uitgenodigd op Habr. Cadey, dus als je vragen hebt - stel ze in het Engels in de reacties.

Hoe te beginnen met het gebruik van User Mode in Linux

User Mode in Linux is feitelijk een poort van de Linux-kernel naar zichzelf. Deze modus maakt het mogelijk om een volledige Linux-kernel als een gebruikersproces te draaien en wordt meestal gebruikt door ontwikkelaars om stuurprogramma's te testen. Maar deze modus is ook nuttig als een instrument voor algemene isolatie, waarvan het principe vergelijkbaar is met dat van virtuele machines. Deze modus biedt een grotere isolatie dan Docker, maar minder dan een volledige virtuele machine zoals KVM of Virtual Box.

Over het algemeen kan User Mode als een vreemd en moeilijk te gebruiken hulpmiddel aanvoelen, maar het heeft toch zijn toepassingsgebieden. Het is immers een volledige Linux-kernel die draait vanuit een niet-privilege gebruiker. Dit kenmerk maakt het mogelijk om potentieel onbetrouwbare code uit te voeren zonder enige bedreiging voor de hostmachine. En aangezien dit een volledige kernel is, zijn de processen geïsoleerd van de hostmachine, dat wil zeggen de processen die binnen de User Mode draaien, zijn niet zichtbaar voor de host. Dit is niet vergelijkbaar met een typische Docker-container, waarbij de hostmachine altijd de processen binnen de opslag ziet. Kijk eens naar dit stuk pstree van een van mijn servers:

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

En vergelijk dit met de pstree van de Linux kernel in de gebruikersmodus:

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

Bij het werken met Docker-containers kan ik vanaf de host de namen zien van processen die op het gast systeem draaien. Dit is niet mogelijk met de Linux gebruikersmodus. Wat betekent dit? Dit betekent dat monitoringtools die werken via de audit subsysteem van Linux zien niet de processen die op het gast systeem worden uitgevoerd. Maar in sommige situaties kan deze eigenschap zowel een voordeel als een nadeel zijn.

Over het geheel genomen is de onderstaande post een verzameling onderzoek en ruwe pogingen om het gewenste resultaat te behalen. Hiervoor moest ik verschillende verouderde tools gebruiken, de broncode van de kernel lezen, intensief debuggen met code die geschreven is in de tijd dat ik nog op de basisschool zat, en ook rommelen met Heroku builds met behulp van een speciale binaire op zoek naar de tools die ik nodig had. Al dit werk leidde ertoe dat de jongens in mijn IRC me een heks (magic) begonnen te noemen. Ik hoop dat deze post als een betrouwbare documentatie voor iemand zal dienen om hetzelfde te doen, maar dan met nieuwere kernels en versies van het besturingssysteem.

Instellingen

De configuratie van de Linux gebruikersmodus wordt in verschillende stappen uitgevoerd:

  • installatie van afhankelijkheden op de host;
  • downloaden van de Linux kernel;
  • configureren van de kernel build;
  • bouwen van de kernel;
  • installatie van de binaire;
  • configureren van het gast bestandssysteem;
  • selecteren van kernel opstartsparameters;
  • configureren van het gast netwerk;
  • starten van de gastkernel.

Ik neem aan dat als je dit allemaal zelf gaat doen, je waarschijnlijk alles gaat uitvoeren op een of andere Ubuntu- of Debian-achtige systeem. Ik heb geprobeerd alles hierboven beschreven te implementeren op mijn favoriete distributie — Alpine, maar het is niet gelukt, waarschijnlijk omdat de Linux-kernel een strikte afhankelijkheid heeft van glibc-isms voor stuurprogramma's in User Mode. Ik ben van plan hierover te rapporteren in de upstream nadat ik de problemen volledig heb begrepen.

Installeren van afhankelijkheden op de host

Ubuntu vereist minimaal de volgende pakketten om de Linux-kernel te bouwen (met een schone installatie):

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

Je kunt ze installeren met de volgende opdracht (met root-rechten of met behulp van sudo):

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

Houd er rekening mee dat het starten van de configuratieprogramma voor de Linux-kernel vereist dat je libncurses-dev. Zorg ervoor dat het is geïnstalleerd met de volgende opdracht (met root-rechten of met behulp van sudo):

apt-get -y install libncurses-dev

Downloaden van de kernel

Bepaal een locatie voor het downloaden en de daaropvolgende bouw van de kernel. Voor deze operatie heb je ongeveer 1,3 GB schijfruimte nodig, dus zorg ervoor dat je dat hebt.

Ga vervolgens naar kernel.org en verkrijg de URL om de laatste stabiele versie van de kernel te downloaden. Op het moment van schrijven is dit: https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

Download dit bestand met behulp van 'wget':

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

En pak het uit met 'tar':

tar xJf linux-5.1.16.tar.xz

Ga nu naar de directory die is gemaakt tijdens het uitpakken van de tarball:

cd linux-5.1.16

Configureren van de bouw van de kernel

Het kernelbouwsysteem is een set Make-bestanden met met een scala aan gebruikershulpmiddelen en scripts voor automatisering van het proces. Begin met het openen van het interactieve configuratieprogramma:

make ARCH=um menuconfig

Het zal gedeeltelijk de bouw begeleiden en je een dialoogvenster tonen. Wanneer onderaan het venster ‘[Select]‘ verschijnt, kun je beginnen met configureren met de Spatiebalk of Enter-toets. Navigeren door het venster gebeurt zoals gewoonlijk met de pijltjestoetsen 'omhoog' en 'omlaag', en het selecteren van items met 'links' of 'rechts'.

Een pijl zoals —> betekent dat je in een submenu bent, toegang ertoe verkrijg je met de Enter-toets. Om eruit te gaan, gebruik je duidelijk ‘[Exit]‘.

Schakel de volgende parameters in ‘[Select]‘ in en zorg ervoor dat er een symbool ‘[*]’ naast staat:

UML-specifieke opties:
  - Hostbestandsysteem
Netwerkondersteuning (activeer dit om het submenu te laten zien):
  - Netwerkopties:
    - TCP/IP-netwerken
UML-netwerkapparaten:
  - Virtueel netwerkapparaat
  - SLiRP-transport

U kunt dit venster verlaten door achtereenvolgens ‘[Exit]‘ te kiezen. Zorg ervoor dat u aan het eind de mogelijkheid krijgt om de configuratie op te slaan en kies ‘[Ja]‘.

Ik raad u aan om te experimenteren met de kerncompilatie-instellingen na het lezen van deze post. Door deze experimenten kunt u veel leren over de werking van de laag-niveau mechanieken van de kernel en de invloed van verschillende vlaggen op de compilatie ervan.

Kerncompilatie

De Linuxkernel is een groot programma dat veel verschillende taken uitvoert. Zelfs met een minimale configuratie op oude hardware kan de compilatie enige tijd duren. Compileer de kernel met de volgende opdracht:

make ARCH=um -j$(nproc)

Waarom? Deze opdracht vertelt onze compiler om alle beschikbare kernen en processorthreads te gebruiken tijdens de compilatie. De opdracht $(nproc) geeft aan het einde van de bouw de uitvoer van de opdracht nproc, die deel uitmaakt van coreutils in de standaardinstallatie van Ubuntu.

Na enige tijd zal onze kernel zijn gecompileerd tot een uitvoerbaar bestand ./linux.

Installatie van de binaire uitvoer

Aangezien User Mode in Linux een gewone binaire uitvoer creëert, kunt u deze installeren zoals elke andere utility. Dit is hoe ik het deed:

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

Zorg er ook voor dat ~ /bin in uw $PATH:

export PATH=$PATH:$HOME/bin

Instelling van het gastbestandsysteem

Maak een map voor het gastbestandsysteem:

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

Bezoek alpinelinux.org en zoek in de downloadssectie de actuele downloadlink voor MINI ROOT FILESYSTEM. Op het moment van schrijven was dit:

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

Download deze tarball met 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

Ga nu naar de map van het gastbestandsysteem en pak het archief uit:

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

De beschreven stappen creëren een kleine sjabloon van het bestandsysteem. Vanwege de werking van het systeem zal het zeer moeilijk zijn om pakketten via de apk-beheerder van Alpine te installeren. Maar dit FS is voldoende om een algemeen idee te krijgen.

We hebben ook een hulpmiddel nodig tini om het geheugenverbruik door zombie-processen van onze gastkernel te beheersen.

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

Creëren van de kernelopdrachtregel

In de Linux-kern, net als in de meeste andere programma's, zijn er commandoregelargumenten die kunnen worden geraadpleegd door de sleutel --help.

zelf —help

linux --help
User Mode Linux v5.1.16
        beschikbaar op http://user-mode-linux.sourceforge.net/

--showconfig
    Drukt het configuratiebestand af waaruit deze UML-binary is gegenereerd.

iomem=,
    Configureer  als een IO-geheugenruimte genaamd .

mem=
    Dit controleert hoeveel "fysiek" geheugen de kernel toewijst
    voor het systeem. De grootte wordt opgegeven als een nummer gevolgd door
    een van 'k', 'K', 'm', 'M', die de voor de hand liggende betekenissen hebben.
    Dit is niet gerelateerd aan de hoeveelheid geheugen in de host. Het kan
    meer zijn, en het overschot, als het ooit wordt gebruikt, zal gewoon worden
    weggeswapt.
        Voorbeeld: mem=64M

--help
    Drukt deze boodschap af.

debug
    deze vlag is niet nodig om gdb te draaien op UML in skas-modus

root=
    Dit wordt daadwerkelijk door de generieke kernel op precies dezelfde
    manier gebruikt als in elke andere kernel. Als je een aantal blokapparaten configureert en wilt opstarten vanaf iets anders dan ubd0, zou je iets gebruiken als:
        root=/dev/ubd5

--version
    Drukt het versienummer van de kernel af.

umid=
    Dit wordt gebruikt om een unieke identiteit voor deze UML-machine toe te wijzen en
    wordt gebruikt voor het benoemen van het pid-bestand en de beheersconsole-socket.

con[0-9]*=
    Sluit een console of seriële lijn aan op een hostkanaal. Zie
    http://user-mode-linux.sourceforge.net/old/input.html voor een complete
    beschrijving van deze schakelaar.

eth[0-9]+=,
    Configureer een netwerkapparaat.
    
aio=2.4
    Dit wordt gebruikt om UML te dwingen om 2.4-stijl AIO te gebruiken, zelfs als 2.6 AIO beschikbaar is.
    2.4 AIO is een enkele thread die één verzoek tegelijk afhandelt,
    synchronisch. 2.6 AIO is een thread die de 2.6 AIO-interface gebruikt
    om een willekeurig aantal wachtende verzoeken af te handelen. 2.6 AIO
    is niet beschikbaar in tt-modus, op 2.4 hosts, of wanneer UML is gebouwd met
    /usr/include/linux/aio_abi.h niet beschikbaar. Veel distributies
    bevatten aio_abi.h niet, dus je moet het uit een kernelboom kopiëren naar
    je /usr/include/linux om een AIO-capabele UML te kunnen bouwen.

nosysemu
    Zet de syscall-emulatiepatch voor ptrace (SYSEMU) uit.
    SYSEMU is een prestatiepatch geïntroduceerd door Laurent Vivier. Het verandert
    het gedrag van ptrace() en helpt de contextwisselpercentages van de host te verminderen.
    Om het werkend te krijgen, heb je ook een kernelpatch voor je host nodig.
    Zie http://perso.wanadoo.fr/laurent.vivier/UML/ voor verder
    informatie.

uml_dir=
    De locatie om de pid- en umid-bestanden te plaatsen.

quiet
    Zet informatieberichten tijdens het opstarten uit.

hostfs=,,...
    Dit wordt gebruikt om hostfs-parameters in te stellen. Het argument voor de rootdirectory
    wordt gebruikt om alle hostfs-mounts te beperken tot binnen de opgegeven directory
    boom op de host. Als dit niet is opgegeven, kan een gebruiker binnen UML zomaar
    iets op de host mounten dat toegankelijk is voor de gebruiker die het draait.
    De enige vlag die momenteel wordt ondersteund is 'append', wat aangeeft dat alle
    bestanden die door hostfs worden geopend, in de append-modus zullen worden geopend.

Dit scherm verlicht de essentiële opstartparameters. Laten we de kern opstarten met de minimaal vereiste opties:

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

De bovenstaande regels geven onze kernel het volgende te begrijpen:

  • Stel dat het root-bestandssysteem een pseudotoestel is /dev/root.
  • Selecteer hostfs als de schijf voor het root-bestandssysteem.
  • Koppel het gastbestandssysteem dat we in het root-apparaat hebben gemaakt.
  • En ja, in lees- en schrijfmodes.
  • Gebruik slechts 64 megabyte RAM (je kunt veel minder gebruiken, afhankelijk van wat je van plan bent, maar 64 MB lijkt een optimale hoeveelheid).
  • De kernel start automatisch /bin/sh hoe , wat erg handig is. Bovendien kunnen meerdere configuraties worden geschreven: ontwikkelen op de standaardconfiguratie, en daarna implementeren met het commando-proces.

Voer dit commando uit en je zou iets moeten krijgen als het volgende:

Nog een bladmuziek

Kerndump-beperkingen :
        zacht - 0
        hard - GEEN
Controleren of ptrace systeemaanroepnummers kan wijzigen...OK
Controleren op systeemaanroep-emulatiepatch voor ptrace...OK
Controleren op geavanceerde systeemaanroep-emulatiepatch voor ptrace...OK
Controleren op omgevingsvariabelen voor een tijdelijke directory...geen gevonden
Controleren of \/dev\/shm op tmpfs staat...OK
Controleren op PROT_EXEC mmap in \/dev\/shm...OK
32137216 bytes aan fysiek geheugen toevoegen om de exec-shield-ruimte te compenseren
Linux-versie 5.1.16 (cadey@kahless) (gcc-versie 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #30 Zon Jul 7 18:57:19 UTC 2019
1 zonelijsten gebouwd, mobiliteitsgroepering ingeschakeld. Totaal pagina's: 23898
Kernelopdrachtregel: root=\/dev\/root rootflags=\/home\/cadey\/dl\/uml\/alpine rootfstype=hostfs rw mem=64M init=\/bin\/sh
Dentry-cache hash tabelinvoeren: 16384 (volgorde: 5, 131072 bytes)
Inode-cache hash tabelinvoeren: 8192 (volgorde: 4, 65536 bytes)
Geheugen: 59584K\/96920K beschikbaar (2692K kernelcode, 708K rwdata, 588K rodata, 104K init, 244K bss, 37336K gereserveerd, 0K cma-gereserveerd)
SLUB: HWalign=64, Volgorde=0-3, Minimumobjecten=0, CPU's=1, Knopen=1
NR_IRQS: 15
kloktijdbron: timer: mask: 0xffffffffffffffff max_cycles: 0x1cd42e205, max_idle_ns: 881590404426 ns
Calibreren van vertraginglus... 7479.29 BogoMIPS (lpj=37396480)
pid_max: standaard: 32768 minimum: 301
Montage-cache hash tabelinvoeren: 512 (volgorde: 0, 4096 bytes)
Montagepunt-cache hash tabelinvoeren: 512 (volgorde: 0, 4096 bytes)
Controleren of host ptys output SIGIO ondersteunt...Ja
Controleren of host ptys SIGIO op sluiten ondersteunt...Nee, workaround inschakelen
devtmpfs: geïnitialiseerd
random: get_random_bytes werd opgeroepen vanuit setup_net+0x48\/0x1e0 met crng_init=0
Gebruik 2.6 host AIO
kloktijdbron: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex hash tabelinvoeren: 256 (volgorde: 0, 6144 bytes)
NET: Protocolfamilie 16 geregistreerd
kloktijdbron: Overschakelen naar kloktijdbron timer
NET: Protocolfamilie 2 geregistreerd
tcp_listen_portaddr_hash hash tabelinvoeren: 256 (volgorde: 0, 4096 bytes)
TCP gevestigde hash tabelinvoeren: 1024 (volgorde: 1, 8192 bytes)
TCP bind hash tabelinvoeren: 1024 (volgorde: 1, 8192 bytes)
TCP: Hash-tabellen geconfigureerd (gevestigd 1024 bind 1024)
UDP hash tabelinvoeren: 256 (volgorde: 1, 8192 bytes)
UDP-Lite hash tabelinvoeren: 256 (volgorde: 1, 8192 bytes)
NET: Protocolfamilie 1 geregistreerd
console [stderr0] uitgeschakeld
mconsole (versie 2) geïnitialiseerd op \/home\/cadey\/.uml\/tEwIjm\/mconsole
Controleren op host MADV_REMOVE-ondersteuning...OK
workingset: timestamp_bits=62 max_order=14 bucket_order=0
Bloklaag SCSI algemene (bsg) driver versie 0.4 geladen (major 254)
io-scheduler noop geregistreerd (standaard)
io-scheduler bfq geregistreerd
loop: module geladen
NET: Protocolfamilie 17 geregistreerd
Geïnitieerd stdio console driver
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 1: Configuratie mislukt
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 2: Configuratie mislukt
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 3: Configuratie mislukt
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 4: Configuratie mislukt
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 5: Configuratie mislukt
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 6: Configuratie mislukt
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 7: Configuratie mislukt
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 8: Configuratie mislukt
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 9: Configuratie mislukt
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 10: Configuratie mislukt
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 11: Configuratie mislukt
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 12: Configuratie mislukt
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 13: Configuratie mislukt
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 14: Configuratie mislukt
Een kanaaltype gebruiken dat buiten UML is geconfigureerd
setup_one_line mislukt voor apparaat 15: Configuratie mislukt
Console geïnitialiseerd op \/dev\/tty0
console [tty0] ingeschakeld
console [mc-1] ingeschakeld
Mislukt om ubd-apparaat 0 te initialiseren: Kon de grootte van het apparaatsbestand niet bepalen
VFS: Gehaalde root (hostfs-bestandssysteem) op apparaat 0:11.
devtmpfs: gemonteerd
Deze architectuur heeft geen bescherming van kernelgeheugen.
Voer \/bin\/sh uit als init-proces
\/bin\/sh: kan tty niet bereiken; jobbeheersing is uitgeschakeld
random: snelle init voltooid
\/ # 

De bovenstaande manipulaties zullen ons geven een minimaal gastensysteem, zonder zaken zoals /proc of een toegewezen hostnaam. Probeer de volgende commando's uit:

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

Om de gastensysteem te verlaten, typ in exit of druk op control-d. Dit zal de shell afsluiten met een daaropvolgende kernel panic:

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

We hebben deze kernel panic ontvangen omdat de Linux-kernel denkt dat het initialisatieproces altijd draait. Zonder dit kan het systeem niet functioneren en sluit het af. Maar aangezien dit een gebruikersmodusproces is, stuurt het resultaat zichzelf naar SIGABRT, wat leidt tot beëindiging.

Configuratie van het gastnetwerk

Maar hier begint alles niet volgens plan te gaan. Het netwerk in User Mode Linux is de plek waar het hele idee van een beperkte 'gebruikersmodus' begint te vervallen. Normaal gesproken is het netwerk op systeemniveau beperkt tot bevoorrechte uitvoeringsmodi om voor ons duidelijke redenen.

Opmerking: meer over de verschillende manieren om met netwerken in UML te werken, kan hier worden gelezen. hier.

Een reis in slirp

Er is echter een oud en praktisch niet-ondersteund hulpmiddel genaamd Slirp, waarmee User Mode Linux met netwerken kan communiceren. Het werkt ongeveer als een TCP/IP-stack op gebruikersniveau en vereist geen systeemrechten om te draaien. Dit hulpmiddel werd uitgegeven in 1995, en de laatste update dateert uit 2006.Slirp is erg oud. In de tijd zonder ondersteuning en updates zijn compilers zo ver gevorderd dat dit hulpmiddel alleen nog maar kan worden gekarakteriseerd als ‘code rot’.

Laten we Slirp uit de Ubuntu-repositories halen en kijken of we het kunnen laten draaien:

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

Copyright (c) 1995,1996 Danny Gasparovski en anderen.
Alle rechten voorbehouden.
Dit programma is auteursrechtelijk beschermd, gratis software.
Lees het bestand COPYRIGHT dat bij het Slirp
pakket is geleverd voor de voorwaarden van het auteursrecht.

IP-adres van Slirp-host: 127.0.0.1
IP-adres van uw DNS(s): 1.1.1.1, 10.77.0.7
Uw adres is 10.0.2.15
(of iets anders dat u wilt)

Typ vijf nullen (0) om te verlaten.

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

SLiRP Gereed ...
fish: “/usr/bin/slirp” beëindigd door signaal SIGSEGV (adresgrensfout)

Oh, hemel. Laten we een debugger voor Slirp installeren en zien of we kunnen begrijpen wat er aan de hand is:

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 versie 3 of later 
Dit is gratis software: je mag het vrij wijzigen en herdistribueren.
Er is GEEN GARANTIE, voor zover toegestaan door de wet. Typ "show copying"
en "show warranty" voor details.
Deze GDB is geconfigureerd als "x86_64-linux-gnu".
Typ "show configuration" voor configuratiedetails.
Voor instructies voor het rapporteren van bugs, zie:
.
Vind de GDB-handleiding en andere documentatiebronnen online op:
.
Voor hulp, typ "help".
Typ "apropos word" om te zoeken naar opdrachten die verband houden met "word"...
Symbolen lezen van /usr/bin/slirp...Symbolen lezen van /usr/lib/debug/.build-id/c6/2e75b69581a1ad85f72ac32c0d7af913d4861f.debug...klaar.
klaar.
(gdb) run
Starten van programma: /usr/bin/slirp
Slirp v1.0.17 (BETA)

Copyright (c) 1995,1996 Danny Gasparovski en anderen.
Alle rechten voorbehouden.
Dit programma is auteursrechtelijk beschermd, gratis software.
Lees het bestand COPYRIGHT dat bij het Slirp
pakket is geleverd voor de voorwaarden van de copyright.

IP-adres van Slirp-host: 127.0.0.1
IP-adres van jouw DNS(s): 1.1.1.1, 10.77.0.7
Jouw adres is 10.0.2.15
(of iets anders dat je wilt)

Typ vijf nullen (0) om af te sluiten.

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

SLiRP Gereed ...

Programma ontving signaal SIGSEGV, Segmentatiefout.
                                                    ip_slowtimo () bij ip_input.c:457
457     ip_input.c: dat bestand of directory bestaat niet.

De fout bevindt zich bij ons in deze regel. Laten we naar de stacktrace kijken, misschien helpt dat ons iets:

(gdb) bt full
#0  ip_slowtimo () bij ip_input.c:457
        fp = 0x55784a40
#1  0x000055555556a57c in main_loop () bij ./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) bij ./main.c:95
Geen lokalen.

Hier zien we dat de crash plaatsvindt tijdens het starten van de hoofdloop, wanneer slirp probeert om time-outs te controleren. Op dat moment had ik moeten stoppen met proberen te debuggen. Maar laten we kijken of Slirp werkt, samengesteld vanuit de bron. Ik heb het archief opnieuw gedownload vanaf de website Sourceforge, omdat het een pijn is om iets via de opdrachtregel daarheen te slepen:

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 zien we waarschuwingen over niet-gedefinieerde ingebouwde functies, dat wil zeggen over het niet kunnen linken van het resulterende binaire bestand. Het lijkt erop dat gcc tussen 2006 en dit moment is gestopt met het genereren van symbolen die gebruikt worden in de ingebouwde functies van intermediair gecompileerde bestanden. Laten we proberen het sleutelwoord inline te vervangen door een lege opmerking en het resultaat bekijken:

vi slirp.h
:6
a

#define inline /**/

:wq
make

Nee, dit werkt ook niet. Ik kan de symbolen van deze functies nog steeds niet vinden.

Op dit moment heb ik het opgegeven en begonnen met zoeken op Github. Heroku buildpacks.Mijn theorie was dat in een of ander Heroku buildpack de nodige binaire bestanden zouden zitten. Uiteindelijk leidde mijn zoektocht me hierheen.Ik heb uml.tar.gz gedownload en uitgepakt en vond het volgende:

totaal 6136
-rwxr-xr-x 1 cadey cadey   79744 10 dec 2017 ifconfig*
-rwxr-xr-x 1 cadey cadey     373 13 dec 2017 init*
-rwxr-xr-x 1 cadey cadey  149688 10 dec 2017 insmod*
-rwxr-xr-x 1 cadey cadey   66600 10 dec 2017 route*
-rwxr-xr-x 1 cadey cadey  181056 26 jun 2015 slirp*
-rwxr-xr-x 1 cadey cadey 5786592 15 dec 2017 uml*
-rwxr-xr-x 1 cadey cadey     211 13 dec 2017 uml_run*

Dit is het binaire bestand slirp! Werkt het?

./slirp
Slirp v1.0.17 (BETA) FULL_BOLT

Copyright (c) 1995, 1996 Danny Gasparovski en anderen.
Alle rechten voorbehouden.
Dit programma is auteursrechtelijk beschermd, gratis software.
Lees alstublieft het bestand COPYRIGHT dat bij het Slirp-pakket is meegeleverd voor de voorwaarden.

IP-adres van de Slirp-host: 127.0.0.1
IP-adres van uw DNS(s): 1.1.1.1, 10.77.0.7
Uw adres is 10.0.2.15
(of iets anders dat u wilt)

Typ vijf nullen (0) om te exit.

[auto-detect SLIP/CSLIP, MTU 1500, MRU 1500]

SLiRP Gereed ...

Het crasht niet — dus het zou moeten werken! Laten we deze binaire bestand in ~/bin/slirp:

kopiëren slirp ~/bin/slirp

Voor het geval de maker van het pakket het verwijdert, heb ik een mirror gemaakt..

Netwerkconfiguratie

Laten we nu het netwerk op onze gastkernel instellen. Laten we de opstartparameters bijwerken.:

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

Laten we nu het netwerk inschakelen:

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

De eerste twee configuratieopdrachten /proc en /sys zijn nodig om ifconfigde netwerkinterface voor communicatie met Slirp in te stellen. De opdracht route stelt de routetabel van de kernel in voor de dwangmatige verzending van al het verkeer via de Slirp-tunnel. Laten we dit controleren met een DNS-query:

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

Naam:      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

Werkt!

Opmerking: Het lijkt erop dat de oorspronkelijke post werd geschreven op een desktop met een bedrade netwerkkaart, of een andere configuratie die geen extra stuurprogramma's vereist. Op een laptop met WiFi 8265 van Intel ontstaat er echter een fout bij het opzetten van het netwerk.

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

Het lijkt erop dat de kernel niet kan communiceren met de netwerkdriver. Pogingen om de firmware in de kernel te compileren hebben de situatie helaas niet verbeterd. Op het moment van publicatie is er nog geen oplossing voor deze configuration gevonden. In meer eenvoudige configuraties (bijvoorbeeld in Virtualbox) wordt de interface correct opgezet.

Laten we de omleiding automatiseren met behulp van het volgende shell-script:

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

En laten we het uitvoerbaar maken:

chmod +x init.sh

En laten we de wijzigingen aanbrengen in de kernopdrachtregel:

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

En herhalen:

SLiRP Gereed ...
netwerken ingesteld
\/bin\/sh: kan tty niet benaderen; taakbesturing is uitgeschakeld

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

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

Het netwerk werkt stabiel!

Docker-bestand

Om het u gemakkelijker te maken dit allemaal te verifiëren, heb ik verzameld Dockerfile, dat de meeste beschreven stappen automatiseert en u een werkende configuratie moet bieden. Ook heb ik een kant-en-klare kernconfiguratie, waarin alles is opgenomen dat in de post is beschreven. Maar het is belangrijk te begrijpen dat ik hier alleen de minimale configuratie heb uiteengezet.

Ik hoop dat deze post u heeft geholpen te begrijpen hoe u een gastkern kunt opzetten. Het is een heel monster geworden, maar de publicatie is bedoeld als een allesomvattende gids over het bouwen, installeren en configureren van User Mode in Linux voor de moderne versies van dit besturingssysteem. De volgende stappen moeten de installatie van diensten en andere software binnen het gastensysteem omvatten. Aangezien Docker-container-images gewoon gepackte tar-archieven zijn, zou u in staat moeten zijn het image uit te pakken via docker export, en vervolgens het pad voor de installatie in de root van het bestandssysteem van de gastkern te bepalen. Daarna voert u het shell-script uit.

Speciale dank aan Rkeene van #lobsters op Freenode. Zonder zijn hulp bij het debuggen van Slirp was ik niet zo ver gekomen. Ik heb geen idee hoe zijn Slackware-systeem correct werkt met slirp, maar mijn Ubuntu- en Alpine-systemen accepteerden slirp en de door Rkeene voorgestelde binaire bestanden niet. Maar ik ben tevreden dat ik toch iets werkends heb.

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers 🔥 Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster