Hvordan begynne å bruke brukermodus på Linux

Introduksjon fra oversetteren: På bakgrunn av det massive inntoget av ulike typer containere i livene våre, kan det være ganske interessant og nyttig å finne ut med hvilke teknologier dette begynte en gang i tiden. Noen av dem kan brukes til i dag, men ikke alle husker slike metoder (eller vet om de ikke ble fanget under deres raske utvikling). En slik teknologi er User Mode Linux. Forfatteren av originalen gravde ganske mye, fant ut hvilken av de gamle utviklingene som fortsatt fungerer og hvilke som ikke gjør det, og satte sammen noe som trinnvise instruksjoner for hvordan du lager en hjemmedyrket UML for deg selv i 2k19. Og ja, vi inviterte forfatteren av det originale innlegget til Habr Cadey, så hvis du har spørsmål, spør på engelsk i kommentarfeltet.

Hvordan begynne å bruke brukermodus på Linux

Brukermodus i Linux er faktisk en port av Linux-kjernen til seg selv. Denne modusen lar deg kjøre en full Linux-kjerne som en brukerprosess og brukes ofte av utviklere til å teste drivere. Men denne modusen er også nyttig som et verktøy for generell isolasjon, hvis prinsipp ligner på driften av virtuelle maskiner. Denne modusen gir mer isolasjon enn Docker, men mindre enn en fullverdig virtuell maskin som KVM eller Virtual Box.

Totalt sett kan brukermodus virke som et merkelig og vanskelig verktøy å bruke, men det har sine bruksområder. Tross alt er dette en fullverdig Linux-kjerne som kjører som en uprivilegert bruker. Denne funksjonen lar potensielt uklarert kode kjøre uten noen trussel mot vertsmaskinen. Og siden dette er en fullverdig kjerne, er prosessene isolert fra vertsmaskinen, det vil si prosesser som kjører i brukermodus vil ikke være synlige for verten. Dette er ikke som en tradisjonell Docker-beholder, der vertsmaskinen alltid ser prosessene inne i lagringen. Se på denne delen av pstree fra en av serverne mine:

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 av Linux-kjernen i brukermodus:

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

Når jeg jobber med Docker-containere, kan jeg se fra verten navnene på prosessene som kjører i gjesten. Dette er ikke mulig med Linux User Mode. Hva betyr det? Dette betyr at overvåkingsverktøy som kjører gjennom Linuxs revisjonsundersystem Ikke se prosesser som kjører i gjestesystemet. Men i noen situasjoner kan denne funksjonen være et tveegget sverd.

Generelt sett er hele innlegget nedenfor en samling av forskning og grove forsøk på å oppnå ønsket resultat. For å gjøre dette måtte jeg bruke forskjellige eldgamle verktøy, lese kjernekilder, engasjere meg i intensiv feilsøking av kode skrevet da jeg fortsatt gikk på barneskolen, og også tukle med Heroku-bygg ved å bruke en spesiell binær på leting etter verktøyene jeg trengte. Alt dette arbeidet førte til at gutta på IRC-en min kalte meg en tryllekunstner. Jeg håper at dette innlegget vil tjene som pålitelig dokumentasjon for at noen kan gjøre det samme, men med nyere kjerner og OS-versjoner.

justering

Å sette opp Linux-brukermodus innebærer flere trinn:

  • installere avhengigheter på verten;
  • nedlasting av Linux-kjernen;
  • oppsett av kjernebygging;
  • kjerne forsamlingen;
  • installere binæren;
  • sette opp gjestefilsystemet;
  • utvalg av kjernelanseringsparametere;
  • sette opp et gjestenettverk;
  • starter gjestekjernen.

Jeg antar at hvis du bestemmer deg for å gjøre alt dette selv, vil du mest sannsynlig gjøre alt som er beskrevet på et Ubuntu- eller Debian-lignende system. Jeg prøvde å implementere alt det ovennevnte i min favorittdistribusjon - Alpine, men ingenting fungerte, tilsynelatende fordi Linux-kjernen er tett bundet til glibc-ismer for drivere i brukermodus. Jeg planlegger å rapportere dette til oppstrøms etter at jeg endelig har funnet ut av problemet.

Installere avhengigheter på verten

Ubuntu krever minst følgende pakker for å bygge Linux-kjernen (forutsatt en ren installasjon):

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

Du kan installere dem ved å bruke følgende kommando (som root eller ved å bruke sudo):

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

Vær oppmerksom på at kjøring av menytilpasningsprogrammet for Linux-kjernen vil kreve installasjon libncurses-dev. Sørg for at den er installert ved å bruke følgende kommando (som root eller ved å bruke sudo):

apt-get -y install libncurses-dev

Laster ned kjernen

Bestem hvor du skal laste ned og bygg deretter kjernen. Du må tildele omtrent 1,3 GB harddiskplass for denne operasjonen, så sørg for at du har det.

Gå deretter til kernel.org og få URL-en for å laste ned den siste stabile kjerneversjonen. I skrivende stund dette innlegget: https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

Last ned denne filen ved hjelp av 'wget':

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

Og trekke det ut med 'tar':

tar xJf linux-5.1.16.tar.xz

Nå går vi inn i katalogen som ble opprettet ved utpakking av tarballen:

cd linux-5.1.16

Sette opp en kjernebygging

Kjernebyggesystemet er et sett Lag filer с mange tilpassede verktøy og skript for å automatisere prosessen. For å komme i gang, åpne det elektroniske oppsettprogrammet:

make ARCH=um menuconfig

Det vil delvis fullføre monteringen og vise en dialogboks for deg. Når lyset vises nederst i vinduet[Select]', kan du konfigurere innstillingene ved å bruke mellomromstasten eller Enter-tastene. Navigering rundt i vinduet er som vanlig ved å bruke tastaturpilene "opp" og "ned", og valg av elementer er "venstre" eller "høyre".

Visningsindikatoren -> betyr at du er i en undermeny, som kan nås med Enter-tasten. Veien ut er åpenbart gjennom '[Exit]'.

Ta med følgende alternativer i '[Select]' og sørg for at det er et '[*]'-symbol ved siden av dem:

UML-specific Options:
  - Host filesystem
Networking support (enable this to get the submenu to show up):
  - Networking options:
    - TCP/IP Networking
UML Network devices:
  - Virtual network device
  - SLiRP transport

Det er det, du kan gå ut av dette vinduet ved å velge sekvensielt '[Exit]'. Bare sørg for at du på slutten blir bedt om å lagre konfigurasjonen og velg '[Yes]'.

Jeg anbefaler at du leker med kjernebyggingsalternativene etter å ha lest dette innlegget. Fra disse eksperimentene kan du lære mye om hvordan kjernemekanikk på lavt nivå fungerer og hvordan forskjellige flagg påvirker hvordan kjernen er bygget.

Bygger kjernen

Linux-kjernen er et stort program som gjør mange ting. Selv med denne minimale konfigurasjonen på eldre maskinvare, kan montering ta ganske lang tid. Så bygg kjernen ved å bruke følgende kommando:

make ARCH=um -j$(nproc)

For hva? Denne kommandoen vil fortelle byggeren vår å bruke alle tilgjengelige CPU-kjerner og -tråder under byggeprosessen. Team $(nproc) på slutten av Bygg setter inn utdata fra kommandoen nproc, som er en del coreutils i standard Ubuntu-bygg.

Etter en tid vil kjernen vår bli kompilert til en kjørbar fil ./linux.

Installere binæren

Siden brukermodus i Linux oppretter en vanlig binær, kan du installere den som alle andre verktøy. Slik gjorde jeg det:

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

Det er også verdt å sørge for det ~/bin er i din $PATH:

export PATH=$PATH:$HOME/bin

Konfigurering av gjestefilsystemet

Opprett en katalog for gjestefilsystemet:

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

Åpne alpinelinux.org og inn nedlastingsseksjonen finn gjeldende nedlastingskobling MINI ROOT FILESYSTEM. I skrivende stund var dette:

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

Last ned denne tarballen med 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

Gå nå inn i gjestefilsystemkatalogen og pakk ut arkivet:

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

Trinnene beskrevet vil lage en liten filsystemmal. På grunn av måten systemet fungerer på, vil det være ekstremt vanskelig å installere pakker gjennom Alpine apk manager. Men denne FS vil være nok til å vurdere den generelle ideen.

Vi trenger også et verktøy tini for å stoppe minneforbruket zombie prosesser gjestekjernen vår.

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

Opprette en kjernekommandolinje

Linux-kjernen, som de fleste andre programmer, har kommandolinjeargumenter som kan nås ved å spesifisere nøkkelen --help.

Han selv - hjelp

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

--showconfig
    Prints the config file that this UML binary was generated from.

iomem=<name>,<file>
    Configure <file> as an IO memory region named <name>.

mem=<Amount of desired ram>
    This controls how much "physical" memory the kernel allocates
    for the system. The size is specified as a number followed by
    one of 'k', 'K', 'm', 'M', which have the obvious meanings.
    This is not related to the amount of memory in the host.  It can
    be more, and the excess, if it's ever used, will just be swapped out.
        Example: mem=64M

--help
    Prints this message.

debug
    this flag is not needed to run gdb on UML in skas mode

root=<file containing the root fs>
    This is actually used by the generic kernel in exactly the same
    way as in any other kernel. If you configure a number of block
    devices and want to boot off something other than ubd0, you
    would use something like:
        root=/dev/ubd5

--version
    Prints the version number of the kernel.

umid=<name>
    This is used to assign a unique identity to this UML machine and
    is used for naming the pid file and management console socket.

con[0-9]*=<channel description>
    Attach a console or serial line to a host channel.  See
    http://user-mode-linux.sourceforge.net/old/input.html for a complete
    description of this switch.

eth[0-9]+=<transport>,<options>
    Configure a network device.
    
aio=2.4
    This is used to force UML to use 2.4-style AIO even when 2.6 AIO is
    available.  2.4 AIO is a single thread that handles one request at a
    time, synchronously.  2.6 AIO is a thread which uses the 2.6 AIO
    interface to handle an arbitrary number of pending requests.  2.6 AIO
    is not available in tt mode, on 2.4 hosts, or when UML is built with
    /usr/include/linux/aio_abi.h not available.  Many distributions don't
    include aio_abi.h, so you will need to copy it from a kernel tree to
    your /usr/include/linux in order to build an AIO-capable UML

nosysemu
    Turns off syscall emulation patch for ptrace (SYSEMU).
    SYSEMU is a performance-patch introduced by Laurent Vivier. It changes
    behaviour of ptrace() and helps reduce host context switch rates.
    To make it work, you need a kernel patch for your host, too.
    See http://perso.wanadoo.fr/laurent.vivier/UML/ for further
    information.

uml_dir=<directory>
    The location to place the pid and umid files.

quiet
    Turns off information messages during boot.

hostfs=<root dir>,<flags>,...
    This is used to set hostfs parameters.  The root directory argument
    is used to confine all hostfs mounts to within the specified directory
    tree on the host.  If this isn't specified, then a user inside UML can
    mount anything on the host that's accessible to the user that's running
    it.
    The only flag currently supported is 'append', which specifies that all
    files opened by hostfs will be opened in append mode.

Dette panelet fremhever hovedstartparameterne. La oss kjøre kjernen med det minste nødvendige settet med alternativer:

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

Linjene ovenfor forteller kjernen vår følgende:

  • La oss anta at rotfilsystemet er en pseudoenhet /dev/root.
  • Velge hostfs som en rotfilsystemdriver.
  • Monter gjestefilsystemet vi opprettet på rotenheten.
  • Og ja, i lese-skrivemodus.
  • Bruk bare 64 megabyte RAM (du kan bruke mye mindre avhengig av hva du planlegger å gjøre, men 64 MB ser ut til å være den optimale mengden).
  • Kjernen starter automatisk /bin/sh som init-prosess.

Kjør denne kommandoen og du bør få noe sånt som følgende:

Et annet ark

Core dump limits :
        soft - 0
        hard - NONE
Checking that ptrace can change system call numbers...OK
Checking syscall emulation patch for ptrace...OK
Checking advanced syscall emulation patch for ptrace...OK
Checking environment variables for a tempdir...none found
Checking if /dev/shm is on tmpfs...OK
Checking PROT_EXEC mmap in /dev/shm...OK
Adding 32137216 bytes to physical memory to account for exec-shield gap
Linux version 5.1.16 (cadey@kahless) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #30 Sun Jul 7 18:57:19 UTC 2019
Built 1 zonelists, mobility grouping on.  Total pages: 23898
Kernel command line: root=/dev/root rootflags=/home/cadey/dl/uml/alpine rootfstype=hostfs rw mem=64M init=/bin/sh
Dentry cache hash table entries: 16384 (order: 5, 131072 bytes)
Inode-cache hash table entries: 8192 (order: 4, 65536 bytes)
Memory: 59584K/96920K available (2692K kernel code, 708K rwdata, 588K rodata, 104K init, 244K bss, 37336K reserved, 0K cma-reserved)
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
NR_IRQS: 15
clocksource: timer: mask: 0xffffffffffffffff max_cycles: 0x1cd42e205, max_idle_ns: 881590404426 ns
Calibrating delay loop... 7479.29 BogoMIPS (lpj=37396480)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
Mountpoint-cache hash table entries: 512 (order: 0, 4096 bytes)
Checking that host ptys support output SIGIO...Yes
Checking that host ptys support SIGIO on close...No, enabling workaround
devtmpfs: initialized
random: get_random_bytes called from setup_net+0x48/0x1e0 with crng_init=0
Using 2.6 host AIO
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex hash table entries: 256 (order: 0, 6144 bytes)
NET: Registered protocol family 16
clocksource: Switched to clocksource timer
NET: Registered protocol family 2
tcp_listen_portaddr_hash hash table entries: 256 (order: 0, 4096 bytes)
TCP established hash table entries: 1024 (order: 1, 8192 bytes)
TCP bind hash table entries: 1024 (order: 1, 8192 bytes)
TCP: Hash tables configured (established 1024 bind 1024)
UDP hash table entries: 256 (order: 1, 8192 bytes)
UDP-Lite hash table entries: 256 (order: 1, 8192 bytes)
NET: Registered protocol family 1
console [stderr0] disabled
mconsole (version 2) initialized on /home/cadey/.uml/tEwIjm/mconsole
Checking host MADV_REMOVE support...OK
workingset: timestamp_bits=62 max_order=14 bucket_order=0
Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
io scheduler noop registered (default)
io scheduler bfq registered
loop: module loaded
NET: Registered protocol family 17
Initialized stdio console driver
Using a channel type which is configured out of UML
setup_one_line failed for device 1 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 2 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 3 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 4 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 5 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 6 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 7 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 8 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 9 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 10 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 11 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 12 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 13 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 14 : Configuration failed
Using a channel type which is configured out of UML
setup_one_line failed for device 15 : Configuration failed
Console initialized on /dev/tty0
console [tty0] enabled
console [mc-1] enabled
Failed to initialize ubd device 0 :Couldn't determine size of device's file
VFS: Mounted root (hostfs filesystem) on device 0:11.
devtmpfs: mounted
This architecture does not have kernel memory protection.
Run /bin/sh as init process
/bin/sh: can't access tty; job control turned off
random: fast init done
/ # 

Manipulasjonene ovenfor vil gi oss minimalt gjestesystem, uten ting som /proc eller tildelt vertsnavn. Prøv for eksempel følgende kommandoer:

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

For å logge ut av gjestesystemet, skriv inn exit eller trykk på kontroll-d. Dette vil avfyre ​​skallet etterfulgt av en kjernepanikk:

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

Vi fikk denne kjernepanikken fordi Linux-kjernen tror at initialiseringsprosessen alltid kjører. Uten den kan systemet ikke lenger fungere og slås av. Men siden dette er en brukermodusprosess, sender det resulterende resultatet seg selv til SIGABRT, som fører til utgangen.

Sette opp et gjestenettverk

Men det er her ting begynner å gå galt for oss. Nettverk i brukermodus Linux er der hele konseptet med en begrenset "brukermodus" begynner å falle fra hverandre. Tross alt er nettverket vanligvis begrenset på systemnivå privilegert utførelsesmåter av åpenbare grunner for oss alle.

Merk pr.: Du kan lese mer om ulike muligheter for å jobbe med nettverk i UML her.

Reise til slirp

Imidlertid er det et eldgammelt og praktisk talt ikke-støttet verktøy kalt Slurp, som brukermodus Linux kan samhandle med nettverket med. Den fungerer omtrent som en TCP/IP-stakk på brukernivå og krever ingen systemtillatelser for å kjøre. Dette verktøyet var utgitt i 1995, og siste oppdatering er datert 2006 år. Slirp er veldig gammel. I løpet av tiden uten støtte og oppdateringer har kompilatorer kommet så langt at dette verktøyet nå kun kan beskrives som "kode råte".

Så la oss laste ned Slirp fra Ubuntu-lagrene og prøve å kjøre det:

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

Copyright (c) 1995,1996 Danny Gasparovski and others.
All rights reserved.
This program is copyrighted, free software.
Please read the file COPYRIGHT that came with the Slirp
package for the terms and conditions of the copyright.

IP address of Slirp host: 127.0.0.1
IP address of your DNS(s): 1.1.1.1, 10.77.0.7
Your address is 10.0.2.15
(or anything else you want)

Type five zeroes (0) to exit.

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

SLiRP Ready ...
fish: “/usr/bin/slirp” terminated by signal SIGSEGV (Address boundary error)

Herregud. La oss installere Slirp debugger og se om vi kan finne ut hva som skjer her:

sudo apt-get install gdb slirp-dbgsym
gdb /usr/bin/slirp
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/bin/slirp...Reading symbols from /usr/lib/debug/.build-id/c6/2e75b69581a1ad85f72ac32c0d7af913d4861f.debug...done.
done.
(gdb) run
Starting program: /usr/bin/slirp
Slirp v1.0.17 (BETA)

Copyright (c) 1995,1996 Danny Gasparovski and others.
All rights reserved.
This program is copyrighted, free software.
Please read the file COPYRIGHT that came with the Slirp
package for the terms and conditions of the copyright.

IP address of Slirp host: 127.0.0.1
IP address of your DNS(s): 1.1.1.1, 10.77.0.7
Your address is 10.0.2.15
(or anything else you want)

Type five zeroes (0) to exit.

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

SLiRP Ready ...

Program received signal SIGSEGV, Segmentation fault.
                                                    ip_slowtimo () at ip_input.c:457
457     ip_input.c: No such file or directory.

Feilen rammer oss denne linjen. La oss se på stacktrace, kanskje noe vil hjelpe oss der:

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

Her ser vi at krasjen skjer under oppstart av hovedsløyfen, når slirp prøver å sjekke timeoutene. Det var i dette øyeblikket jeg måtte gi opp å prøve å feilsøke. Men la oss se om Slirp, bygget fra sorter, fungerer. Jeg lastet ned arkivet på nytt direkte fra nettstedet sourceforge, fordi det er vanskelig å dra noe 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 varsler om udefinerte innebygde funksjoner, det vil si om umuligheten av å koble den resulterende binære filen. Det ser ut til at gcc mellom 2006 og nå sluttet å lage symboler brukt i innebygde mellomfunksjoner. La oss prøve å erstatte søkeordet inline til en tom kommentar og se på resultatet:

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

Nei. Dette går heller ikke. Kan fortsatt ikke finne symboler for disse funksjonene.

På dette tidspunktet ga jeg opp og begynte å søke på Github Heroku byggepakker. Min teori var at en eller annen Heroku byggepakke ville inneholde binærfilene jeg trengte. Til slutt førte søket meg akkurat her. Jeg lastet ned og pakket ut uml.tar.gz og fant 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*

Dette er en slirp binær! Virker det?

./slirp
Slirp v1.0.17 (BETA) FULL_BOLT

Copyright (c) 1995,1996 Danny Gasparovski and others.
All rights reserved.
This program is copyrighted, free software.
Please read the file COPYRIGHT that came with the Slirp
package for the terms and conditions of the copyright.

IP address of Slirp host: 127.0.0.1
IP address of your DNS(s): 1.1.1.1, 10.77.0.7
Your address is 10.0.2.15
(or anything else you want)

Type five zeroes (0) to exit.

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

SLiRP Ready ...

Det faller ikke - så det burde fungere! La oss plante denne binæren inn ~/bin/slirp:

cp slirp ~/bin/slirp

I tilfelle skaperen av pakken fjerner den, kan jeg laget et speil.

Nettverkskonfigurasjon

La oss nå konfigurere nettverket på gjestekjernen vår. La oss oppdatere lanseringsparametrene:

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

La oss nå aktivere nettverket:

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 to første konfigurasjonskommandoene /proc и /sys nødvendig for arbeid ifconfig, som setter opp et nettverksgrensesnitt for å kommunisere med Slirp. Team route setter kjernerutingstabellen til å tvinge all trafikk til å sendes gjennom Slirp-tunnelen. La oss sjekke dette med en DNS-spørring:

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

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

Det fungerer!

Merknad per.: Tilsynelatende ble det originale innlegget skrevet på et skrivebord med et kablet nettverkskort, eller en annen konfigurasjon som ikke krever ekstra drivere. På en bærbar PC med WiFi 8265 fra Intel oppstår det en feil ved heving av nettverket

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

Tilsynelatende kan ikke kjernen kommunisere med driveren for nettverksstasjonen. Et forsøk på å kompilere fastvaren inn i kjernen, korrigerte dessverre ikke situasjonen. På publiseringstidspunktet kunne det ennå ikke finnes noen løsning i denne spesielle konfigurasjonen. På enklere konfigurasjoner (for eksempel i Virtualbox) er grensesnittet riktig hevet.

La oss automatisere omdirigeringen ved å bruke følgende shell-skript:

#!/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 merk den som kjørbar:

chmod +x init.sh

Og la oss så gjøre endringer i kjernekommandolinjen:

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

Og la oss gjenta:

SLiRP Ready ...
networking set up
/bin/sh: can't access tty; job control turned off

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

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

Nettverket er stabilt!

docker-fil

For å gjøre det lettere for deg å sjekke alt dette har jeg samlet Dockerfile, som automatiserer de fleste trinnene som er beskrevet og bør gi deg en fungerende konfigurasjon. jeg har også klar kjernekonfigurasjon, som inneholder alt som er beskrevet i innlegget. Men det er viktig å forstå at her har jeg kun skissert minimumsinnstillingene.

Jeg håper dette innlegget hjalp deg med å forstå hvordan du henter frem en gjestekjerne. Det viste seg å være et slags monster, men publikasjonen var ment å være en omfattende guide om emnet montering, installasjon og konfigurering av brukermodus i Linux under moderne versjoner av operativsystemer i denne familien. Påfølgende trinn bør inkludere installasjon av tjenester og annen programvare som allerede er inne i gjestesystemet. Siden Docker-beholderbilder bare er promoterte tarballs, bør du kunne trekke ut bildet via docker export, og bestemmer deretter banen for å installere den i roten til gjestekjernens filsystem. Vel, så kjør shell-skriptet.

Spesiell takk til Rkeene fra #lobsters på Freenode. Uten hans hjelp til å feilsøke Slirp, hadde jeg ikke kommet så langt. Jeg aner ikke hvordan Slackware-systemet hans fungerer riktig med slirp, men Ubuntu- og Alpine-systemene mine godtok ikke slirp og den binære Rkeene foreslo meg. Men det er nok for meg at i det minste noe fungerer for meg.

Kilde: www.habr.com

Legg til en kommentar