Hvordan man begynder at bruge User Mode i Linux

Indledning fra oversætteren: I takt med den massive indtræden af forskellige containere i vores liv kan det være interessant og nyttigt at kende de teknologier, som dette hele engang startede med. Nogle af dem kan stadig med fordel anvendes den dag i dag, men ikke alle husker (eller ved, hvis de ikke oplevede dem under deres hastige udvikling) sådanne metoder. En af disse teknologier er User Mode Linux. Forfatteren af originalen har gravet dybt for at finde ud af, hvilke af de gamle idéer der stadig fungerer, og hvad der ikke gør, og har samlet noget, der ligner en trin-for-trin guide til, hvordan man selv kan få en hjemmelavet UML i 2k19. Og ja, vi har inviteret forfatteren af det originale indlæg til Habr. Cadey, så hvis der er spørgsmål - så spørg på engelsk i kommentarerne.

Hvordan man begynder at bruge User Mode i Linux

User Mode i Linux er i virkeligheden en port af Linux-kernen til sig selv. Denne tilstand gør det muligt at køre en fuld fungerende Linux-kerne som en brugerproces og bruges normalt af udviklere til at teste drivere. Men denne tilstand er også nyttig som et generelt isoleringsværktøj, hvis princip er sammenligneligt med, hvordan virtuelle maskiner fungerer. Denne tilstand giver større isolation end Docker, men mindre end en fuld virtuel maskine såsom KVM eller Virtual Box.

Generelt kan User Mode virke som et mærkeligt og komplekst værktøj at bruge, men det har alligevel sine anvendelsesområder. For det er en fuld Linux-kerne, der kører under en ikke-privilegeret bruger. Denne funktion giver mulighed for at køre potentielt usikre koder uden nogen trussel mod værtmaskinen. Og da det er en fuld kerne, er dens processer isoleret fra værtmaskinen, det vil sige processerne, der kører inden for User Mode, vil ikke være synlige for værten. Det ligner ikke den velkendte Docker-container, hvor værtmaskinen altid kan se processerne inden for containeren. Se på dette stykke pstree fra en af mine servere:

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

Og sammenlign dette med pstree i Linux-kernen i brugerens tilstand:

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

Når jeg arbejder med Docker-containere, kan jeg se procesnavnene, der kører i gæstesystemet fra værten. Dette er ikke muligt med Linux User Mode. Hvad betyder det? Det betyder, at overvågningsværktøjer, der arbejder gennem Linux’s auditing subsystem, ikke ser de processer, der udføres i gæstesystemet. Men i nogle situationer kan denne egenskab blive en tosidet sværd.

Hele indlægget herunder er en samling af undersøgelser og grove forsøg på at opnå det ønskede resultat. Til dette har jeg været nødt til at bruge forskellige gamle værktøjer, læse kildekoden til kernen, foretage intensiv debugging af kode skrevet i en tid, hvor jeg stadig gik i folkeskole, samt nørde rundt i Heroku-builds med et specielt binær i jagten på de værktøjer, jeg havde brug for. Alt dette arbejde har fået drengene i min IRC til at kalde mig en troldkvinde (magic). Jeg håber, at dette indlæg kan tjene som pålidelig dokumentation for nogen, der ønsker at gøre det samme, men allerede med nyere kerner og OS-versioner.

Indstillinger

Opsætning af Linux User Mode sker i flere trin:

  • installation af afhængigheder på værten;
  • download af Linux-kernen;
  • opsætning af kernebuild;
  • kompilering af kernen;
  • installation af binærfilen;
  • opsætning af gæstefilssystemet;
  • justering af kernelstartparametre;
  • opsætning af gæstenetværket;
  • start af gæstekernen.

Jeg antager, at hvis du vælger at klare dette selv, vil du sandsynligvis gøre alt det beskrevne i et eller andet Ubuntu- eller Debian-lignende system. Jeg har forsøgt at implementere alt det ovenfor beskrevne i min yndlingsdistribution — Alpine, men det gik ikke, angiveligt fordi kernel Linux har en rigid binding til glibc-ism'er for drivere i brugerklassen. Jeg planlægger at rapportere dette til upstream, når jeg har helt forstået problemet.

Installation af afhængigheder på værten

Ubuntu kræver mindst følgende pakker for at kompilere kernen i Linux (under forudsætning af en ren installation):

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

Du kan installere dem med følgende kommando (som root eller ved hjælp af sudo):

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

Bemærk, at kørsel af konfigurationsprogrammet til Linux-kernen kræver installation af libncurses-dev. Venligst sikr dig, at det er installeret med følgende kommando (som root eller ved hjælp af sudo):

apt-get -y install libncurses-dev

Download af kernen

Bestem, hvor du vil downloade og senere kompilere kernen. Du skal afsætte omkring 1,3 GB plads på harddisken til denne operation, så sørg for, at du har det.

Derefter skal du gå til kernel.org og få URL'en til at downloade den seneste stabile version af kernen. På tidspunktet for denne skrivning er det: https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

Download denne fil ved hjælp af 'wget':

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

Og udpak den med 'tar':

tar xJf linux-5.1.16.tar.xz

Nu går vi ind i den mappe, der blev oprettet ved udpakkingen af tarballen:

cd linux-5.1.16

Konfiguration af kernen

Kernens bygge-system er et sæt Make-filer med mange brugerdefinerede værktøjer og scripts til at automatisere processen. For at starte skal du åbne det interaktive konfigurationsprogram:

make ARCH=um menuconfig

Det vil delvist gennemføre kompileringen og vise dig et dialogvindue. Når '[Select]' vises nederst i vinduet, kan du begynde at konfigurere med tasterne mellemrum eller Enter. Navigering i vinduet gøres som sædvanlig med pilene 'op' og 'ned', og markeringen af elementer med 'venstre' eller 'højre'.

En indikator som —> betyder, at du er i en undermenu, som du går ind i ved at trykke på Enter. Udad fra den går du tydeligvis ved at vælge '[Exit]'Aktivér følgende indstillinger i '[Select]' og sørg for, at der er et symbol '[*]' ved siden af dem:‘.

Aktivér følgende indstillinger i ‘[Select]‘ og sørg for, at der er et symbol ‘[*]’ ved siden af dem:

UML-specifikke indstillinger:
  - Værtsfilsystem
Netværksunderstøttelse (aktiver dette for at få under-menuen til at vises):
  - Netværksindstillinger:
    - TCP/IP-netværk
UML-netværksenheder:
  - Virtuel netværksenhed
  - SLiRP-transport

Du kan forlade dette vindue ved at vælge ‘Aktivér følgende indstillinger i '[Select]' og sørg for, at der er et symbol '[*]' ved siden af dem:‘. Bare sørg for, at du til sidst bliver tilbudt at gemme konfigurationen og vælg ‘[Ja]‘.

Jeg anbefaler, at du eksperimenterer med kernelbyggeindstillingerne efter at have læst dette indlæg. Gennem disse eksperimenter kan du lære meget om, hvordan lavniveau mekanismer fungerer i kernen og hvordan forskellige flag påvirker dens bygning.

Kernelbygning

Linux-kernen er et stort program, der håndterer mange ting. Selv med en minimal konfiguration på gammelt hardware kan opbygningen tage betydelig tid. Derfor kan du bygge kernen ved hjælp af følgende kommando:

make ARCH=um -j$(nproc)

Hvorfor? Denne kommando fortæller vores byggeprogram at bruge alle tilgængelige kerner og tråde under byggingen. Kommandoen $(nproc) indsætter output fra kommandoen nproc, som er en del af coreutils i den standardinstallation af Ubuntu.

Efter noget tid vil vores kernel blive bygget til en eksekverbar fil ./linux.

Installation af binæren

Da User Mode i Linux opretter en almindelig binær, kan du installere den som enhver anden tjeneste. Her er, hvad jeg gjorde:

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

Du bør også sikre dig, at ~\/bin er i din $PATH:

export PATH=$PATH:$HOME/bin

Opsætning af gæste-filsystemet

Opret en mappe til gæste-filsystemet:

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

Gå til alpinelinux.org og i download-sektionen find den aktuelle downloadlink til MINI ROOT FILESYSTEM. På tidspunktet for publiceringen var dette:

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

Download denne tarball ved hjælp af 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

Nu skal du gå ind i mappen for gæste-filsystemet og udpakke arkivet:

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

De beskrevne skridt vil oprette et lille skabelon-filsystem. På grund af systemets karakter vil det være ret vanskeligt at installere pakker via apk-pakkestyringssystemet fra Alpine. Men dette filsystem vil være tilstrækkeligt til at vurdere den overordnede idé.

Vi vil også få brug for værktøjet tini for at stoppe hukommelsesforbruget af zombie-processerne i vores gæstekernel.

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

Oprettelse af kernelens kommandolinje

I Linux-kernen, ligesom i de fleste andre programmer, er der kommandolinjeargumenter, som kan fås ved at angive nøglen --help.

Selv —help

linux --help
User Mode Linux v5.1.16
        tilgængelig på http://user-mode-linux.sourceforge.net/

--showconfig
    Udskriver konfigurationsfilen, som denne UML-binærfil blev genereret fra.

iomem=,
    Konfigurer  som et IO-hukommelsesområde navngivet .

mem=
    Dette styrer, hvor meget "fysisk" hukommelse kerne allokerer til systemet. Størrelsen angives som et tal efterfulgt af en af 'k', 'K', 'm', 'M', som har de indlysende betydninger. Dette er ikke relateret til mængden af hukommelse i værten.  Det kan være mere, og overskuddet, hvis det nogensinde bruges, vil blot blive byttet ud.
        Eksempel: mem=64M

--help
    Udskriver denne meddelelse.

debug
    dette flag er ikke nødvendigt for at køre gdb på UML i skas-tilstand

root=
    Dette bruges faktisk af den generiske kerne på præcis samme måde, som i enhver anden kerne. Hvis du konfigurerer et antal blok-enheder og ønsker at boote fra noget andet end ubd0, ville du bruge noget som:
        root=/dev/ubd5

--version
    Udskriver versionnummeret på kernen.

umid=
    Dette bruges til at tildele en unik identitet til denne UML-maskine og bruges til at navngive pid-filen og administrationskonsolens socket.

con[0-9]*=
    Tilslut en konsol eller seriel linje til en værtkanal. Se
    http://user-mode-linux.sourceforge.net/old/input.html for en komplet beskrivelse af denne switch.

eth[0-9]+=,
    Konfigurer en netværksenhed.
    
aio=2.4
    Dette bruges til at tvinge UML til at bruge 2.4-stil AIO, selv når 2.6 AIO er tilgængelig.  2.4 AIO er en enkelt tråd, der håndterer en anmodning ad gangen, synkront.  2.6 AIO er en tråd, der bruger 2.6 AIO-grænsefladen til at håndtere et vilkårligt antal ventende anmodninger.  2.6 AIO er ikke tilgængelig i tt-tilstand, på 2.4 værter eller når UML er bygget med /usr/include/linux/aio_abi.h ikke tilgængelig.  Mange distributioner inkluderer ikke aio_abi.h, så du bliver nødt til at kopiere det fra et kerne-træ til din /usr/include/linux for at bygge en AIO-kapabel UML

nosysemu
    Slår syscall-emuleringspatch for ptrace (SYSEMU) fra. SYSEMU er en ydelsespatch, der blev introduceret af Laurent Vivier. Den ændrer adfærden af ptrace() og hjælper med at reducere værts kontekstskiftfrekvens. For at få det til at fungere skal du også have en kerne-patch til din vært. Se http://perso.wanadoo.fr/laurent.vivier/UML/ for yderligere information.

uml_dir=
    Placeringen af pid- og umid-filerne.

quiet
    Slår informationsmeddelelser fra under boot.

hostfs=,,...
    Dette bruges til at sætte hostfs-parametre.  Argumentet for rodmappen bruges til at begrænse alle hostfs-mounts til inden for det angivne mappetræ på værten.  Hvis dette ikke er angivet, kan en bruger inde i UML montere alt på værten, der er tilgængeligt for den bruger, der kører det.
    Den eneste flag, der i øjeblikket understøttes, er 'append', som angiver, at alle filer åbnet af hostfs vil blive åbnet i append-tilstand.

Dette dokument belyser de grundlæggende opstartsparametre. Lad os starte kernen med det mindste nødvendige sæt af indstillinger:

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

Linjerne ovenfor siger til vores kerne:

  • Lad os antage, at rodfilsystemet er en pseudo-enhed /dev/root.
  • Vælg hostfs som en driver for rodfilsystemet.
  • Monter gæstefilsystemet, som vi har oprettet, i root-enheden.
  • Og ja, i læsning-skrivning-tilstand.
  • Brug kun 64 megabyte RAM (du kan bruge meget mindre, afhængigt af hvad du planlægger at gøre, men 64 MB virker optimalt).
  • Kernen starter automatisk /bin/sh hvordan init-processen.

Kør denne kommando, og du skal få noget som følgende:

En anden blok

Kernekdump begrænsninger :
        blød - 0
        hård - INGEN
Tjekker om ptrace kan ændre systemopkaldsnumre...OK
Tjekker syscall-emulation patch til ptrace...OK
Tjekker avanceret syscall-emulation patch til ptrace...OK
Tjekker miljøvariabler for en tempdir...ingen fundet
Tjekker om /dev/shm er på tmpfs...OK
Tjekker PROT_EXEC mmap i /dev/shm...OK
Tilføjer 32137216 bytes til fysisk hukommelse for at dække exec-shield gap
Linux version 5.1.16 (cadey@kahless) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #30 Søndag den 7. jul 2019 18:57:19 UTC
Bygget 1 zonelister, mobilitetsgruppering aktiveret.  Samlet antal sider: 23898
Kernel kommando linje: root=/dev/root rootflags=/home/cadey/dl/uml/alpine rootfstype=hostfs rw mem=64M init=/bin/sh
Dentry cache hash tabel posteringer: 16384 (orden: 5, 131072 bytes)
Inode-cache hash tabel posteringer: 8192 (orden: 4, 65536 bytes)
Hukommelse: 59584K/96920K tilgængelig (2692K kernel kode, 708K rwdata, 588K rodata, 104K init, 244K bss, 37336K reserveret, 0K cma-reserveret)
SLUB: HWalign=64, Orden=0-3, MinObjects=0, CPUs=1, Noder=1
NR_IRQS: 15
clocksource: timer: mask: 0xffffffffffffffff max_cycles: 0x1cd42e205, max_idle_ns: 881590404426 ns
Kalibrering af forsinkelse loop... 7479.29 BogoMIPS (lpj=37396480)
pid_max: standard: 32768 minimum: 301
Mount-cache hash tabel posteringer: 512 (orden: 0, 4096 bytes)
Mountpoint-cache hash tabel posteringer: 512 (orden: 0, 4096 bytes)
Tjekker at host ptys understøtter output SIGIO...Ja
Tjekker at host ptys understøtter SIGIO ved lukning...Nej, aktiverer workaround
devtmpfs: initialiseret
random: get_random_bytes kaldt fra setup_net+0x48/0x1e0 med crng_init=0
Brug af 2.6 host AIO
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex hash tabel posteringer: 256 (orden: 0, 6144 bytes)
NET: Registreret protokol familie 16
clocksource: Skiftet til clocksource timer
NET: Registreret protokol familie 2
tcp_listen_portaddr_hash hash tabel posteringer: 256 (orden: 0, 4096 bytes)
TCP etablerede hash tabel posteringer: 1024 (orden: 1, 8192 bytes)
TCP bind hash tabel posteringer: 1024 (orden: 1, 8192 bytes)
TCP: Hash tabeller konfigureret (etablerede 1024 bind 1024)
UDP hash tabel posteringer: 256 (orden: 1, 8192 bytes)
UDP-Lite hash tabel posteringer: 256 (orden: 1, 8192 bytes)
NET: Registreret protokol familie 1
console [stderr0] deaktiveret
mconsole (version 2) initialiseret på /home/cadey/.uml/tEwIjm/mconsole
Tjekker host MADV_REMOVE support...OK
workingset: timestamp_bits=62 max_order=14 bucket_order=0
Block layer SCSI generisk (bsg) driver version 0.4 indlæst (major 254)
io scheduler noop registreret (standard)
io scheduler bfq registreret
loop: modul indlæst
NET: Registreret protokol familie 17
Initialiseret stdio console driver
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 1 : Konfiguration mislykkedes
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 2 : Konfiguration mislykkedes
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 3 : Konfiguration mislykkedes
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 4 : Konfiguration mislykkedes
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 5 : Konfiguration mislykkedes
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 6 : Konfiguration mislykkedes
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 7 : Konfiguration mislykkedes
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 8 : Konfiguration mislykkedes
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 9 : Konfiguration mislykkedes
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 10 : Konfiguration mislykkedes
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 11 : Konfiguration mislykkedes
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 12 : Konfiguration mislykkedes
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 13 : Konfiguration mislykkedes
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 14 : Konfiguration mislykkedes
Bruger en kanaltype, der er konfigureret uden for UML
setup_one_line mislykkedes for enhed 15 : Konfiguration mislykkedes
Console initialiseret på /dev/tty0
console [tty0] aktiveret
console [mc-1] aktiveret
Kunne ikke initialisere ubd enhed 0 :Kunne ikke bestemme størrelse af enhedens fil
VFS: Monteret rod (hostfs filsystem) på enhed 0:11.
devtmpfs: monteret
Denne arkitektur har ikke beskyttelse af kernens hukommelse.
Kør /bin/sh som init proces
/bin/sh: kan ikke få adgang til tty; jobkontrol er slået fra
random: hurtig init udført
/ # 

Manipulationerne ovenfor vil give os et gæstesystem med minimal funktionalitet, uden sådanne ting som /proc eller tildelt værtsnavn. For eksempel, prøv at køre følgende kommandoer:

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

For at afslutte gæstesystemet, indtast sigreturn eller tryk på control-d. Dette vil afslutte shell'en med efterfølgende kernel panic:

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

Vi fik denne kernel panic, fordi Linux-kernen mener, at initialiseringsprocessen altid er aktiv. Uden den kan systemet ikke længere fungere og afslutter driften. Men da dette er en brugergrænseflade-proces, sender det resulterende output sig selv til SIGABRT, hvilket fører til afslutningen.

Konfiguration af gæstenetværk

Men her begynder tingene at gå galt. Netværket i User Mode Linux er det sted, hvor hele konceptet om begrænset 'brugermode' begynder at bryde sammen. Normalt er netværket på systemniveau begrænset af privilegerede kørselsmode af åbenlyse grunde.

Bemærk: mere om forskellige måder at arbejde med netværk i UML kan findes her.

Rejsen til slirp

Der findes dog et gammelt og stort set ikke-understøttet værktøj kaldet Slirp, ved hjælp af hvilket User Mode Linux kan interagere med netværket. Det fungerer omtrent som et TCP/IP-stak på brugerniveau og kræver ikke nogen systemtilladelser for at køre. Dette værktøj blev udgivet i 1995, og den seneste opdatering var i 2006.Slirp er meget gammelt. I en periode uden understøttelse og opdateringer er compilere gået så langt, at dette værktøj nu kun kan beskrives som "code rot".

Så lad os installere Slirp fra Ubuntu-repositories og forsøge at køre det:

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

Copyright (c) 1995,1996 Danny Gasparovski med flere.
Alle rettigheder forbeholdes.
Dette program er ophavsretligt beskyttet, gratis software.
Læs venligst filen COPYRIGHT, der følger med Slirp
pakken for betingelserne for ophavsretten.

IP-adresse for Slirp-værten: 127.0.0.1
IP-adresse for dine DNS(e): 1.1.1.1, 10.77.0.7
Din adresse er 10.0.2.15
(eller hvad som helst andet, du ønsker)

Skriv fem nuller (0) for at afslutte.

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

SLiRP Klar ...
fisk: "/usr/bin/slirp" afsluttet af signal SIGSEGV (Adressegrænsefejl)

Åh, hvad siger du. Lad os installere en debugger til Slirp og se, om vi kan finde ud af, hvad der sker:

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 
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:
.
Find the GDB manual and other documentation resources online at:
.
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.

Fejlen opstår i denne linje. Lad os se på stacktrace, måske kan det hjælpe os:

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

Her ser vi, at fejlen opstår i starten af hovedløkken, når slirp prøver at kontrollere tidsudløb. Det var i dette øjeblik, jeg burde have opgivet at debugge. Men lad os se, om Slirp, bygget fra kilden, fungerer. Jeg har genaflæst arkivet direkte fra hjemmesiden Sourceforge, fordi det er besværligt at hente noget derfra via kommandolinjen:

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

Her ser vi advarsler om ubekræftede indbyggede funktioner, hvilket betyder, at det resulterende binære fil ikke kan linker. Det ser ud til, at mellem 2006 og nu har gcc holdt op med at oprette symboler, der bruges i indbyggede funktioner for mellemkompilerede filer. Lad os prøve at erstatte nøgleordet inline med en tom kommentar og se hvad resultatet bliver:

vi slirp.h
:6
a

#define inline /**/

:wq
make

Nej, det virker stadig ikke. Jeg kan stadig ikke finde tegn på disse funktioner.

På dette tidspunkt gav jeg op og begyndte at lede efter det på Github Heroku build packs. Min teori var, at der i et eller andet Heroku build pack ville være de nødvendige binære filer. Til sidst førte mine søgninger mig herhen. Jeg downloadede og udpakkede uml.tar.gz og fandt følgende:

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*

Det er den binære fil slirp! Men fungerer den?

./slirp
Slirp v1.0.17 (BETA) FULL_BOLT

Copyright (c) 1995,1996 Danny Gasparovski og andre.
Alle rettigheder forbeholdes.
Dette program er copyrightbeskyttet, gratis software.
Læs venligst filen COPYRIGHT, der følger med Slirp
pakken for vilkårene og betingelserne for copyright.

IP-adresse på Slirp-værten: 127.0.0.1
IP-adresse på din(e) DNS: 1.1.1.1, 10.77.0.7
Din adresse er 10.0.2.15
(eller hvad som helst andet, du ønsker)

Indtast fem nuller (0) for at exit.

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

SLiRP Klar ...

Den crasher ikke — så det bør virke! Lad os flytte denne binærfil til ~/bin/slirp:

cp slirp ~/bin/slirp

I tilfælde af at skaberen af pakken fjerner den, har jeg lavet et spejl.

Netværksopsætning

Lad os nu konfigurere netværket på vores gæste-kerne. Vi opdaterer startparametrene:

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

Lad os nu aktivere netværket:

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 første to konfigurationskommandoer /proc og /sys er nødvendige for at etablere ifconfignetværksgrænsefladen til kommunikation med Slirp. Kommandoen rute opsætter kernerutingen til at tvinge al trafik gennem Slirp-tunnelen. Lad os teste dette med en DNS-forespørgsel:

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

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

Det virker!

Obs: Det ser ud til, at det oprindelige indlæg blev skrevet på en desktop med et kablet netværkskort, eller en anden konfiguration, der ikke kræver ekstra drivere. På en bærbar computer med WiFi 8265 fra Intel opstår der dog en fejl ved netværksoprettelsen.

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

Det ser ud til, at kernen ikke kan oprette forbindelse til netværksdriveren. Desværre løste forsøget på at kompilere firmwaren ind i kernen ikke situationen. På tidspunktet for offentliggørelsen har der endnu ikke været fundet en løsning i denne konfiguration. I mere enkle konfigurationer (f.eks. i VirtualBox) aktiveres grænsefladen korrekt.

Lad os automatisere omdirigeringen ved hjælp af følgende 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

Og lad os gøre det eksekverbart:

chmod +x init.sh

Og så vil vi foretage ændringer i kernekommandolinjen:

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

Og vi gentager:

SLiRP Klar ...
netværk opsat
\/bin\/sh: kan ikke få adgang til tty; jobkontrol slået fra

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

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

Netværket fungerer stabilt!

Docker-fil

For at gøre det lettere for dig at tjekke det hele, har jeg samlet Dockerfile, som automatiserer de fleste af de beskrevne trin og bør give dig en fungerende konfiguration. Jeg har også en klar kerne-konfiguration, som indeholder alt, hvad der er beskrevet i indlægget. Men det er vigtigt at forstå, at jeg kun har præsenteret den minimale opsætning her.

Jeg håber, at dette indlæg har hjulpet dig med at forstå, hvordan man opsætter et gæste-kern. Det blev en slags monster, men publikationen var tænkt som en omfattende guide til emnet samling, installation og opsætning af User Mode i Linux under moderne versioner af dette families operativsystemer. De efterfølgende trin bør omfatte installation af tjenester og anden software inden i gæstesystemet. Da Docker-containerbilleder blot er pakket tar-arkiver, skal du være i stand til at udtrække billedet via docker export, og derefter bestemme banen for dens installation i rodmappen for gæstebitkernel. Og derefter køre shell-scriptet.

En særlig tak til Rkeene fra #lobsters på Freenode. Uden hans hjælp til fejlfinding af Slirp ville jeg ikke være kommet så langt. Jeg har ingen idé om, hvordan hans Slackware-system fungerer korrekt med slirp, men mine Ubuntu- og Alpine-systemer accepterede ikke slirp og den Rkeene-binærfil, jeg blev tilbudt. Men jeg er tilfreds med, at jeg har noget, der fungerer.

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster