Jak začít používat uživatelský režim v Linuxu

Úvod od překladatele: Vzhledem k masovému vstupu různých typů kontejnerů do našeho života může být poměrně zajímavé a užitečné zjistit, z jakých technologií to všechno kdysi začalo. Některé z nich lze stále užitečně využít, ale ne každý na tyto způsoby pamätá (nebo je nezná, pokud nezažil jejich bouřlivý rozvoj). Jednou z takových technologií je User Mode Linux. Autor originálu se podrobně zabýval tím, co ze starých vývojů ještě funguje a co už ne, a sestavil něco jako krok za krokem návod, jak si v roce 2019 založit domácí UML. A ano, pozvali jsme na Habr autora originálního příspěvku. Cadey, takže pokud máte otázky - ptejte se anglicky v komentářích.

Jak začít používat uživatelský režim v Linuxu

User Mode v Linuxu je v zásadě přenos jádra Linuxu na sebe samého. Tento režim umožňuje spustit plnohodnotné jádro Linuxu jako uživatelský proces a obvykle ho používají vývojáři k testování ovladačů. Ale také je tento režim užitečný jako nástroj pro obecnou izolaci, jejíž princip je podobný fungování virtuálních strojů. Tento režim poskytuje větší izolaci než Docker, ale menší než plnohodnotný virtuální stroj jako KVM nebo Virtual Box.

Celkově může User Mode vypadat jako podivný a složitý nástroj, ale i přesto má své oblasti použití. Je to přece plnohodnotné Linuxové jádro, které běží pod neoprávněným uživatelským účtem. Tato vlastnost umožňuje spouštět potenciálně nespolehlivý kód bez jakýchkoliv hrozeb pro hostitelský stroj. A protože je to plnohodnotné jádro, jeho procesy jsou izolovány od hostitelské mašiny, což znamená že procesy běžící uvnitř User Mode nebudou viditelné pro hostitele. To není podobné běžnému Docker kontejneru, kde hostitelský systém vždy vidí procesy uvnitř úložiště. Podívejte se na tento kus pstree z jednoho z mých 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}]

A porovnejte to s pstree jádra Linux v uživatelském režimu:

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

Při práci s kontejnery Docker mohu na hostiteli vidět názvy procesů, které běží v hostitelském systému. S uživatelským režimem Linuxu to možné není. Co to znamená? To znamená, že monitoringové nástroje, které pracují přes podsystem auditu Linuxu (Linux’s auditing subsystem) nevidí procesy prováděné v hostitelském systému. Ale v některých situacích může být tato vlastnost oboustranným mečem.

Celý následující příspěvek je soubor výzkumů a hrubých pokusů dosáhnout požadovaného výsledku. K tomu jsem musel používat různé staré nástroje, číst zdrojové kódy jádra, intenzivně ladit kód z doby, kdy jsem ještě chodil na základní školu, a také pátrat ve buildy Heroku pomocí speciálního binárního souboru při hledání potřebných nástrojů. Tato veškerá práce vedla k tomu, že mě kluci v mém IRC začali nazývat kouzelníkem (magic). Doufám, že tento příspěvek poslouží někomu jako spolehlivá dokumentace pro provedení toho samého, ale již s novějšími jádry a verzemi OS.

Nastavení

Nastavení uživatelského režimu Linuxu probíhá ve několika fázích:

  • instalace závislostí na hostiteli;
  • stažení jádra Linux;
  • nastavení buildu jádra;
  • build jádra;
  • instalace binárního souboru;
  • nastavení hostitelského souborového systému;
  • výběr parametrů spuštění jádra;
  • nastavení hostitelské sítě;
  • spuštění hostitelského jádra.

Předpokládám, že pokud se rozhodnete to provést sami, pravděpodobně budete vše dělat v nějakém systému podobném Ubuntu nebo Debianu. Snažila jsem se implementovat všechno výše uvedené ve své oblíbené distribuci – Alpine, ale nic se nepodařilo, zřejmě kvůli tomu, že jádro Linuxu má striktní vazbu na glibc-isms pro ovladače v uživatelském režimu. Plánuji to oznámit upstream, jakmile se s problémem konečně poprvé seznámím.

Instalace závislostí na hostiteli

Ubuntu vyžaduje alespoň následující balíčky pro sestavení jádra Linux (při předpokladu čisté instalace):

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

Můžete je nainstalovat pomocí následujícího příkazu (s právy root nebo pomocí sudo):

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

Všimněte si, že spuštění programu pro konfiguraci menu jádra Linux vyžaduje instalaci libncurses-dev. Prosím ujistěte se, že je nainstalován pomocí následujícího příkazu (s právy root nebo pomocí sudo):

apt-get -y install libncurses-dev

Stahování jádra

Určete místo pro stažení a následnou kompilaci jádra. Pro tuto operaci budete potřebovat přidělit přibližně 1,3 GB místa na pevném disku, proto se ujistěte, že ho máte k dispozici.

Poté přejděte na kernel.org a získejte URL na stažení poslední stabilní verze jádra. K datu napsání příspěvku je to: https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

Stáhněte tento soubor pomocí 'wget':

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

A rozbalte ho pomocí 'tar':

tar xJf linux-5.1.16.tar.xz

Nyní přejděte do adresáře, který byl vytvořen při rozbalení tarballu:

cd linux-5.1.16

Nastavení kompilace jádra

Systém kompilace jádra je soubor Make souborů s s množstvím uživatelských nástrojů a skriptů pro automatizaci procesu. Pro začátek otevřete interaktivní program pro konfiguraci:

make ARCH=um menuconfig

Částečně provede kompilaci a zobrazí vám dialogové okno. Když se na spodní části okna objeví ‚[Select]‘, můžete se věnovat konfiguraci pomocí kláves mezerník nebo Enter. Navigace oknem se provádí běžně šipkami na klávesnici ‚nahoru‘ a ‚dolů‘, zatímco zvýraznění prvků se provádí ‚vlevo‘ nebo ‚vpravo‘.

Ukazatel ve tvaru –> znamená, že se nacházíte v podmenu, do kterého vstoupíte stisknutím klávesy Enter. Výstup je, jak jinak, přes ‚[Exit]‘.

Zahrňte následující parametry v ‘[Select]‘ a ujistěte se, že vedle nich je symbol ‘[*]’:

Možnosti specifické pro UML:
  - Hostitelský souborový systém
Podpora sítě (aktivujte toto, abyste zobrazili submenu):
  - Možnosti sítě:
    - TCP/IP síťové připojení
Zařízení UML Network:
  - Virtuální síťové zařízení
  - SLiRP transport

Z tohoto okna můžete postupně vycházet výběrem ‘[Exit]‘. Jen se ujistěte, že se na konci nabídne možnost uložit konfiguraci a vyberete ‘[Ano]‘.

Doporučuji si po přečtení tohoto příspěvku pohrát s nastavením jádra. Díky těmto experimentům se můžete mnoho naučit o fungování nízkoúrovňových mechanik jádra a vlivu různých příznaků na jeho sestavení.

Sestavení jádra

Jádro Linuxu je velký program, který se zabývá mnoha věcmi. I při tak minimální konfiguraci na starém zařízení může trvat docela dlouho, než jej sestavíte. Proto sestavte jádro pomocí následujícího příkazu:

make ARCH=um -j$(nproc)

Proč? Tento příkaz řekne našemu sestavovači, aby použil všechna dostupná jádra a vlákna procesoru během procesu sestavování. Příkaz $(nproc) na konci Build nahrazuje výstup příkazu nproc, který je součástí coreutils ve standardní instalaci Ubuntu.

Po nějakém čase bude naše jádro sestaveno do spustitelného souboru ./linux.

Instalace binárního souboru

Protože User Mode v Linuxu vytváří běžný binárník, můžete jej nainstalovat jako jakoukoli jinou utilitu. Zde je, jak jsem to udělala já:

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

Také se ujistěte, že ~/bin je ve vašem $PATH:

export PATH=$PATH:$HOME/bin

Nastavení hostitelského souborového systému

Vytvořte adresář pro hostitelský souborový systém:

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

Otevřete alpinelinux.org a v sekci stažení najděte aktuální odkaz na stažení MINI ROOT FILESYSTEM. V době psaní tohoto příspěvku to bylo:

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

Stáhněte tento tarball pomocí 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

Nyní přejděte do adresáře hostitelského souborového systému a rozbalte archiv:

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

Popisovaná opatření vytvoří malou šablonu souborového systému. Z důvodu specifiků systému bude extrémně obtížné instalovat balíčky prostřednictvím správce apk Alpine. Ale tento FS bude stačit pro celkové posouzení myšlenky.

Také budeme potřebovat nástroj tini pro zastavení spotřeby paměti zombie procesy našem hostitelském jádře.

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

Vytvoření příkazového řádku jádra

V jádře Linuxu, stejně jako v mnoha dalších programech, existují argumenty příkazového řádku, se kterými se můžete seznámit zadáním klíče --help.

sám --help

linux --help
User Mode Linux v5.1.16
        k dispozici na http://user-mode-linux.sourceforge.net/

--showconfig
    Vytiskne konfigurační soubor, ze kterého byl tento UML binární soubor vygenerován.

iomem=,
    Nakonfigurujte  jako region IO paměti pojmenovaný .

mem=
    To řídí, kolik "fyzické" paměti jádro přiděluje
    systému. Velikost je určena jako číslo následované
    jedním z 'k', 'K', 'm', 'M', což má očividný význam.
    To není spojeno s množstvím paměti na hostiteli. Může
    být více, a přebytek, pokud je někdy použit, bude jednoduše vyžádán na výměnu.
        Příklad: mem=64M

--help
    Vytiskne tuto zprávu.

debug
    tato příznak není potřeba pro spuštění gdb na UML v režimu skas

root=
    To se skutečně používá generickým jádrem přesně stejným
    způsobem jako v jakémkoli jiném jádru. Pokud nakonfigurujete řadu blokových
    zařízení a chcete bootovat z něčeho jiného než ubd0, použijete něco jako:
        root=/dev/ubd5

--version
    Vytiskne číslo verze jádra.

umid=
    To se používá k přiřazení jedinečné identity této UML stroji a
    je použito k pojmenování PID souboru a správcovské konzole.

con[0-9]*=
    Připojte konzoli nebo sériovou linku k hostitelskému kanálu. Viz
    http://user-mode-linux.sourceforge.net/old/input.html pro úplný
    popis tohoto přepínače.

eth[0-9]+=

, Nakonfigurujte síťové zařízení. aio=2.4 Toto se používá k nucení UML používat 2.4 styl AIO i když 2.6 AIO je k dispozici. 2.4 AIO je jediný vlákno, které zpracovává jeden požadavek jednou synchronně. 2.6 AIO je vlákno, které používá rozhraní 2.6 AIO k zpracování libovolného počtu čekajících požadavků. 2.6 AIO není k dispozici v režimu tt, na 2.4 hostitelích, nebo když je UML postaven s /usr/include/linux/aio_abi.h není k dispozici. Mnoho distribucí neobsahuje aio_abi.h, takže jej budete muset zkopírovat z jádrového stromu do svého /usr/include/linux, abyste mohli postavit AIO schopný UML nosysemu Vypne emulaci systémových volání pro ptrace (SYSEMU). SYSEMU je výkonová záplata, kterou zavedl Laurent Vivier. Změní chování ptrace() a pomáhá snižovat míru pompování kontextu hostitele. Aby to fungovalo, potřebujete také záplatu jádra pro svůj hostitel. Viz http://perso.wanadoo.fr/laurent.vivier/UML/ pro další informace. uml_dir= Umístění, kam umístit PID a umid soubory. quiet Vypne informační zprávy během bootování. hostfs=,

,... Toto se používá k nastavení hostfs parametrů. Argument kořenového adresáře se používá k omezení všech hostfs připojení na určený adresářový strom na hostiteli. Pokud to není specifikováno, pak uživatel uvnitř UML může připojit cokoliv na hostitele, co je přístupné uživateli, který jej spouští. Jediný příznak, který je v současnosti podporován, je 'append', který určuje, že všechny soubory otevřené hostfs budou otevřeny v režimu připojení.

Tento přehled osvětluje hlavní parametry spuštění. Pojďme spustit jádro s minimálním nezbytným souborem možností:

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

Výše uvedené řádky říkají našemu jádru toto:

  • Předpokládejme, že kořenový souborový systém je pseudo-zařízení /dev/root.
  • Vyberte hostfs jako ovladač kořenového souborového systému.
  • Připojte hostitelský souborový systém, který jsme vytvořili v kořenovém zařízení.
  • A ano, v režimu pro čtení a zápis.
  • Použijte pouze 64 megabajtů paměti RAM (můžete použít mnohem méně, v závislosti na tom, co plánujete dělat, ale 64 MB se zdají být optimální množství).
  • Jádro se automaticky spouští /bin/sh jak init-proces.

Spusťte tento příkaz a měli byste dostat něco podobného následujícímu:

Ještě jedna stránka

Limitace core dump:
        měkké - 0
        tvrdé - ŽÁDNÉ
Kontrola, zda ptrace může měnit čísla systémových volání...OK
Kontrola patchování emulace systémových volání pro ptrace...OK
Kontrola pokročilého patchování emulace systémových volání pro ptrace...OK
Kontrola proměnných prostředí pro dočasný adresář...nenalezeno
Kontrola, zda je /dev/shm na tmpfs...OK
Kontrola PROT_EXEC mmap v /dev/shm...OK
Přidávání 32137216 bytů do fyzické paměti pro pokrytí mezery exec-shield
Verze Linuxu 5.1.16 (cadey@kahless) (gcc verze 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #30 Ne 7. července 2019 18:57:19 UTC
Postaveno 1 zonelists, mobilita ve skupinách. Celkem stránek: 23898
Příkazový řádek jádra: root=/dev/root rootflags=/home/cadey/dl/uml/alpine rootfstype=hostfs rw mem=64M init=/bin/sh
Dentry cache hash table entries: 16384 (řád: 5, 131072 bytů)
Inode-cache hash table entries: 8192 (řád: 4, 65536 bytů)
Paměť: 59584K/96920K k dispozici (2692K kód jádra, 708K rwdata, 588K rodata, 104K init, 244K bss, 37336K rezervováno, 0K cma-rezervováno)
SLUB: HWalign=64, Řád=0-3, MinObjects=0, CPU=1, Uzly=1
NR_IRQS: 15
clocksource: timer: mask: 0xffffffffffffffff max_cycles: 0x1cd42e205, max_idle_ns: 881590404426 ns
Kalibrace zpoždění... 7479.29 BogoMIPS (lpj=37396480)
pid_max: výchozí: 32768 minimum: 301
Mount-cache hash table entries: 512 (řád: 0, 4096 bytů)
Mountpoint-cache hash table entries: 512 (řád: 0, 4096 bytů)
Kontrola, zda host ptys podporují výstup SIGIO...Ano
Kontrola, zda host ptys podporují SIGIO při uzavření...Ne, povolujeme workaround
devtmpfs: inicializováno
random: get_random_bytes byl volán z setup_net+0x48/0x1e0 s crng_init=0
Použití 2.6 host AIO
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex hash table entries: 256 (řád: 0, 6144 bytů)
NET: Registrována protokolová rodina 16
clocksource: Přepnuto na clocksource timer
NET: Registrována protokolová rodina 2
tcp_listen_portaddr_hash hash table entries: 256 (řád: 0, 4096 bytů)
TCP establishment hash table entries: 1024 (řád: 1, 8192 bytů)
TCP bind hash table entries: 1024 (řád: 1, 8192 bytů)
TCP: Hash tabulky nakonfigurovány (established 1024 bind 1024)
UDP hash table entries: 256 (řád: 1, 8192 bytů)
UDP-Lite hash table entries: 256 (řád: 1, 8192 bytů)
NET: Registrována protokolová rodina 1
konzole [stderr0] zakázána
mconsole (verze 2) inicializována na /home/cadey/.uml/tEwIjm/mconsole
Kontrola podpory host MADV_REMOVE...OK
workingset: timestamp_bits=62 max_order=14 bucket_order=0
Block layer SCSI generic (bsg) ovladač verze 0.4 načten (major 254)
io plánovač noop registrován (výchozí)
io plánovač bfq registrován
loop: modul načten
NET: Registrována protokolová rodina 17
Inicializován stdio konzolní ovladač
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 1: Konfigurace selhala
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 2: Konfigurace selhala
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 3: Konfigurace selhala
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 4: Konfigurace selhala
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 5: Konfigurace selhala
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 6: Konfigurace selhala
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 7: Konfigurace selhala
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 8: Konfigurace selhala
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 9: Konfigurace selhala
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 10: Konfigurace selhala
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 11: Konfigurace selhala
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 12: Konfigurace selhala
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 13: Konfigurace selhala
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 14: Konfigurace selhala
Použití typu kanálu, který je nakonfigurován mimo UML
setup_one_line nezdar pro zařízení 15: Konfigurace selhala
Konzole inicializována na /dev/tty0
konzole [tty0] povolena
konzole [mc-1] povolena
Nepodařilo se inicializovat ubd zařízení 0: Nelze určit velikost souboru zařízení
VFS: Připojený root (hostfs souborový systém) na zařízení 0:11.
devtmpfs: připojeno
Tato architektura nemá ochranu paměti jádra.
Spusťte /bin/sh jako init proces
/bin/sh: nemohu přistupovat k tty; ovládání úloh bylo vypnuto
random: rychlý init dokončen
/ # 

Manipulace výše nám dají hostitelský systém na minimální úrovni, bez takových věcí, jako je /proc nebo přidělené hostitelské jméno. Jako příklad zkuste provést následující příkazy:

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

Chcete-li opustit hostitelský systém, zadejte exit nebo stiskněte control-d. To zabije shell a vyvolá následný kernel panic:

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

K tomuto kernel panic došlo, protože jádro Linuxu považuje inicializační proces za vždy spuštěný. Bez něj již systém nemůže fungovat a ukončí činnost. Ale jelikož se jedná o proces uživatelského režimu, získaný výstup se posílá sám do SIGABRT, což vede k výstupu.

Nastavení hostitelské sítě

A tady se nám všechno začíná rozpadat. Síť v User Mode Linux je to místo, kde se celá koncepce omezeného 'uživatelského režimu' začíná rozpadat. Obvykle je síť na systémové úrovni omezena privilegovanými režimy vykonávání z nám všem jasných důvodů.

Pozn. překladatele: více o různých variantách práce se sítí v UML si můžete přečíst zde.

Cesta do slirp

Existuje však starý a prakticky nepodporovaný nástroj zvaný Slirp, pomocí něhož může User Mode Linux komunikovat se sítí. Funguje přibližně jako TCP/IP zásobník na úrovni uživatele a nevyžaduje žádná systémová oprávnění k spuštění. Tento nástroj byl vydán v roce 1995, a poslední aktualizace pochází z roku 2006. Slirp je opravdu starý. Během doby bez podpory a aktualizací se kompilátory posunuly tak daleko, že nyní lze tento nástroj charakterizovat pouze jako "code rot".

Takže pojďme nainstalovat Slirp z repozitářů Ubuntu a zkusit ho spustit:

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

Copyright (c) 1995,1996 Danny Gasparovski a ostatní.
Všechna práva vyhrazena.
Tento program je chráněn autorským právem, je to freeware.
Přečtěte si prosím soubor COPYRIGHT, který přišel s balíčkem Slirp
pro podmínky copyrightu.

IP adresa hostitele Slirp: 127.0.0.1
IP adresa vaší DNS(y): 1.1.1.1, 10.77.0.7
Vaše adresa je 10.0.2.15
(nebo cokoliv jiného, co chcete)

Zadejte pět nul (0) k ukončení.

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

SLiRP Připraveno ...
fishing: “/usr/bin/slirp” byl přerušen signálem SIGSEGV (Chyba hranice adresy)

Ach, bože. Nainstalujme debugger pro Slirp a podívejme se, jestli se nám podaří zjistit, co se děje:

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.

Chyba se nám vyskytuje v této řádce. Podívejme se na stacktrace, možná nám tam něco pomůže:

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

Tady vidíme, že k chybě dochází během spuštění hlavního cyklu, když se slirp snaží zkontrolovat časové limity. V tu dobu jsem měla vzdát pokusy o ladění. Ale pojďme se podívat, zda funguje Slirp, sestavený ze zdrojů. Znovu jsem stáhla archiv přímo z webové stránky Sourceforge, protože tahání něčeho z příkazového řádku - to je mučení:

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

Tady vidíme upozornění na nedefinované vestavěné funkce, tedy na nemožnost slinkovat výsledný binární soubor. Zdá se, že mezi rokem 2006 a tímto okamžikem gcc přestalo generovat symboly používané ve vestavěných funkcích mezikompilovaných souborů. Zkusme nahradit klíčové slovo inline prázdným komentářem a podívejme se na výsledek:

vi slirp.h
:6
a

#define inline /**/

:wq
make

Ne, to také nefunguje. Stále se nedaří najít znaky těchto funkcí.

V této fázi jsem to vzdala a začala hledat na Githubu balíčky pro sestavení Heroku. Moje teorie se zakládala na tom, že nějaký balíček pro sestavení Heroku bude obsahovat potřebné binární soubory. Nakonec mě hledání dovedlo až sem. Stáhla jsem a rozbalila uml.tar.gz a našla následující:

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*

To je binární soubor slirp! Funguje?

./slirp
Slirp v1.0.17 (BETA) FULL_BOLT

Copyright (c) 1995,1996 Danny Gasparovski a další.
Všechna práva vyhrazena.
Tento program je chráněn autorským právem, je to svobodný software.
Přečtěte si prosím soubor COPYRIGHT, který byl dodán s balíčkem Slirp
pro podmínky a podmínky copyrightu.

IP adresa hostitele Slirp: 127.0.0.1
IP adresa vaší DNS(s): 1.1.1.1, 10.77.0.7
Vaše adresa je 10.0.2.15
(a nebo cokoliv jiného, co chcete)

Zadejte pět nul (0), abyste ukončili.

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

SLiRP Ready ...

Nepadá — takže by to mělo fungovat! Pojďme vložit tento binární soubor do ~\/bin\/slirp:

cp slirp ~\/bin\/slirp

Pro případ, že by tvůrce balíčku jeho odstranil, jsem vytvořila zrcadlo.

Nastavení sítě

Teď pojďme nastavit síť na našem hostujícím jádře. Aktualizujeme spouštěcí parametry:

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

Teď zapneme síť:

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

První dva příkazy pro nastavení /proc a /sys jsou nezbytné pro funkci ifconfig, která nastavuje síťové rozhraní pro komunikaci se Slirp. Příkaz route nastavuje směrovací tabulku jádra na nucení obousměrného provozu tunelovat přes Slirp. Pojďme to zkontrolovat pomocí DNS dotazu:

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

Název:      google.com
Adresa 1: 172.217.12.206 lga25s63-in-f14.1e100.net
Adresa 2: 2607:f8b0:4006:81b::200e lga25s63-in-x0e.1e100.net

Funguje!

Pozn.: Zřejmě byl původní příspěvek napsán na desktopu s drátovou síťovou kartou, nebo jinou konfigurací, která nevyžaduje další ovladače. Na notebooku s WiFi 8265 od Intelu však při zprovozňování sítě nastává chyba

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

Zdá se, že jádro se nemůže spojit s ovladačem síťovky. Pokus o zkompilování firmwaru do jádra situaci, bohužel, neopravil. V době publikace zatím nebylo možné najít řešení pro tuto konfiguraci. V jednodušších konfiguracích (např. ve Virtualboxu) se rozhraní zprovozňuje správně.

Pojďme automatizovat přesměrování pomocí následujícího shell skriptu:

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

A uděláme ho spustitelným:

chmod +x init.sh

A pak provedeme změny v příkazovém řádku jádra:

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

A opakujeme:

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

Síť funguje stabilně!

Docker soubor

Abych vám to vše usnadnila, připravila jsem Dockerfile, který automatizuje většinu popsaných kroků a měl by vám poskytnout funkční konfiguraci. Mám také hotovou konfiguraci jádra, která obsahuje vše, co je popsáno v příspěvku. Je však důležité pochopit, že jsem zde uvedla pouze minimální nastavení.

Doufám, že vám tento příspěvek pomohl pochopit, jak spustit hostitelské jádro. Vyšlo z toho nějaké monstrum, ale zamýšlela jsem publikaci jako komplexní průvodce na téma sestavování, instalace a nastavení User Mode v Linuxu pro moderní verze operačních systémů tohoto rodiny. Následující kroky by měly zahrnovat instalaci služeb a dalšího softwaru již uvnitř hostitelského systému. Protože obrazy kontejnerů Docker jsou prostě rozbalené tar archivy, měli byste být schopni extrahovat obraz pomocí docker export, a pak určit cestu jeho instalace v kořenovém adresáři souborového systému hostitelského jádra. Poté už jen spusťte shell skript.

Zvláštní poděkování Rkeene z #lobsters na Freenode. Bez jeho pomoci při debugování Slirp bych se nedostala tak daleko. Nemám ponětí, jak jeho systém Slackware správně funguje se slirp, ale moje systémy Ubuntu a Alpine přijaly slirp a nabízený Rkeene binární soubor. Ale jsem ráda, že mi funguje alespoň něco.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster