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

Úvod od překladatele: Na pozadí masivního vstupu různých druhů kontejnerů do našich životů může být docela zajímavé a užitečné zjistit, s jakými technologiemi to všechno kdysi začalo. Některé z nich lze užitečně používat dodnes, ale ne každý si takové metody pamatuje (nebo ví, zda se nechytily při jejich překotném vývoji). Jednou z takových technologií je User Mode Linux. Autor originálu hodně makal, zjišťoval, který ze starých vývojů ještě funguje a který ne, a dal dohromady něco jako návod krok za krokem, jak si pořídit homebrew UML ve 2k19. A ano, pozvali jsme k Habrovi autora původního příspěvku Cadey, takže pokud máte nějaké dotazy - ptejte se v angličtině v komentářích.

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

Uživatelský režim v Linuxu je ve skutečnosti portem linuxového jádra pro sebe. Tento režim vám umožňuje spouštět úplné linuxové jádro jako uživatelský proces a vývojáři jej běžně používají k testování ovladačů. Tento režim je ale také užitečný jako obecný izolační nástroj, jehož princip je podobný provozu virtuálních strojů. Tento režim poskytuje větší izolaci než Docker, ale méně než plnohodnotný virtuální stroj, jako je KVM nebo Virtual Box.

Obecně se Uživatelský režim může zdát jako zvláštní a obtížně použitelný nástroj, ale stále má své využití. Přeci jen se jedná o plnohodnotné linuxové jádro běžící od neprivilegovaného uživatele. Tato funkce umožňuje spustit potenciálně nedůvěryhodný kód bez jakéhokoli ohrožení hostitelského počítače. A protože se jedná o plnohodnotné jádro, jeho procesy jsou izolované od hostitelského stroje, tzn procesy běžící v uživatelském režimu nebudou pro hostitele viditelné. Toto není jako obvyklý kontejner Docker, v takovém případě hostitelský počítač vždy vidí procesy uvnitř úložiště. Podívejte se na tento kousek 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 linuxového jádra v uživatelském režimu:

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

Při práci s kontejnery Docker vidím z hostitele názvy procesů, které v hostu běží. V uživatelském režimu Linux to není možné. Co to znamená? To znamená, že monitorovací nástroje, které běží prostřednictvím auditovacího subsystému Linuxu nevidět procesy běžící v hostujícím systému. Ale v některých situacích se tato vlastnost může stát dvousečným mečem.

Obecně platí, že celý příspěvek níže je sbírkou výzkumů a hrubých pokusů o dosažení požadovaného výsledku. K tomu jsem musel používat různé starodávné nástroje, číst zdrojové kódy jádra, provádět intenzivní ladění kódu napsaného v dobách, kdy jsem byl ještě na základní škole, a také si pohrát s sestaveními Heroku pomocí speciální binárky, abych našel nástroje, které jsem potřeboval. . Všechna tato práce vedla lidi na mém IRC k tomu, aby mi říkali magie. Doufám, že tento příspěvek poslouží jako spolehlivá dokumentace pro někoho, kdo může zkusit to samé s novějšími jádry a verzemi OS.

Nastavení

Nastavení uživatelského režimu Linuxu se provádí v několika krocích:

  • instalace závislostí na hostiteli;
  • stažení linuxového jádra;
  • konfigurace sestavení jádra;
  • sestavení jádra;
  • binární instalace;
  • konfigurace souborového systému hosta;
  • výběr parametrů spouštění jádra;
  • nastavení sítě pro hosty;
  • spuštění hostujícího jádra.

Předpokládám, že pokud se pro to rozhodnete sami, s největší pravděpodobností uděláte vše popsané v nějakém systému Ubuntu nebo Debianu. Zkoušel jsem implementovat vše výše uvedené ve své oblíbené distribuci - Alpine, ale nic z toho nebylo, zřejmě kvůli tomu, že jádro Linuxu má pevně vázané glibc-ismy pro ovladače v uživatelském režimu. Až problém konečně pochopím, plánuji to nahlásit upstreamu.

Instalace závislostí na hostiteli

Ubuntu vyžaduje pro sestavení linuxového jádra alespoň následující balíčky (za 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 (jako root nebo pomocí sudo):

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

Pamatujte, že spuštění instalačního programu nabídky jádra Linuxu bude vyžadovat instalaci libncurses-dev. Ujistěte se prosím, že je nainstalován pomocí následujícího příkazu (jako root nebo pomocí sudo):

apt-get -y install libncurses-dev

Stažení jádra

Rozhodněte se, kde stáhnout a poté sestavit jádro. Pro tuto operaci budete muset přidělit asi 1,3 GB místa na pevném disku, takže se ujistěte, že ho máte.

Poté přejděte na kernel.org a získejte adresu URL ke stažení nejnovějšího stabilního jádra. V době psaní je toto: https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

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

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

A extrahujte to pomocí 'tar':

tar xJf linux-5.1.16.tar.xz

Nyní vstoupíme do adresáře vytvořeného při rozbalování tarballu:

cd linux-5.1.16

Nastavení sestavení jádra

Systém sestavení jádra je sada Makefiles с mnoho vlastní nástroje a skripty pro automatizaci procesu. Nejprve otevřete interaktivní instalační program:

make ARCH=um menuconfig

Částečně vytvoří a zobrazí dialogové okno za vás. Když '[Select]', budete moci konfigurovat pomocí kláves Space nebo Enter. V okně se jako obvykle pohybujte šipkami na klávesnici „nahoru“ a „dolů“ a vyberte prvky – „vlevo“ nebo „vpravo“.

Ukazatel pohledu —> znamená, že se nacházíte v podnabídce, ke které se dostanete klávesou Enter. Cesta z toho je zjevně přes '[Exit]".

Zahrňte následující možnosti do „[Select]“ a ujistěte se, že mají vedle sebe „[*]“:

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

To je vše, toto okno můžete opustit postupným výběrem '[Exit]'. Jen se ujistěte, že jste na konci vyzváni k uložení konfigurace a vyberte '[Yes]".

Doporučuji, abyste si po přečtení tohoto příspěvku pohráli s možnostmi sestavení jádra. Prostřednictvím těchto experimentů se můžete hodně naučit, pokud jde o pochopení práce nízkoúrovňové mechaniky jádra a vlivu různých příznaků na jeho sestavení.

Budování jádra

Linuxové jádro je velký program, který dělá spoustu věcí. I s tak minimální konfigurací na starém hardwaru může trvat poměrně dlouho sestavení. Sestavte jádro pomocí následujícího příkazu:

make ARCH=um -j$(nproc)

Proč? Tento příkaz řekne našemu staviteli, aby v procesu sestavení použil všechna dostupná jádra CPU a vlákna. tým $(nproc) na konci Build nahradí výstup příkazu nproc, která je součástí coreutils ve standardním sestavení Ubuntu.

Po nějaké době bude naše jádro zkompilováno do spustitelného souboru ./linux.

Instalace binárního souboru

Protože uživatelský režim v Linuxu vytváří běžný binární soubor, můžete jej nainstalovat jako jakýkoli jiný nástroj. Udělal jsem to takto:

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

Také stojí za to se o tom přesvědčit ~/bin je ve vašem $PATH:

export PATH=$PATH:$HOME/bin

Nastavení systému souborů hosta

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

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

Otevřete alpinelinux.org a in sekce ke stažení najít skutečný odkaz ke stažení MINI ROOT FILESYSTEM. V době psaní tohoto článku 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 si 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í zadejte adresář souborového systému hosta a rozbalte archiv:

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

Popsané akce vytvoří malou šablonu souborového systému. Vzhledem k povaze systému bude extrémně obtížné instalovat balíčky přes Alpine apk manager. Ale tento FS bude stačit k posouzení obecné myšlenky.

Potřebujeme také nástroj tini ke snížení spotřeby paměti zombie procesy naše hostující jádro.

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

Linuxové jádro, stejně jako většina ostatních programů, má argumenty příkazového řádku, ke kterým lze přistupovat zadáním klíče --help.

Sám — pomoc

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.

Tento panel zvýrazňuje hlavní parametry spouštění. Spusťte jádro s minimální požadovanou sadou 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 následující:

  • Předpokládejme, že kořenový souborový systém je pseudo zařízení /dev/root.
  • Vybrat hostfs jako ovladač kořenového souborového systému.
  • Připojte hostovaný souborový systém, který jsme vytvořili, na kořenové zařízení.
  • A ano, v režimu čtení-zápis.
  • Použijte pouze 64 MB RAM (můžete použít mnohem méně v závislosti na tom, co plánujete dělat, ale 64 MB se zdá jako optimální množství).
  • Automaticky se spustí jádro /bin/sh как init-proces.

Spusťte tento příkaz a měli byste získat něco jako následující:

Ještě jeden list

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

Výše uvedené manipulace nám dají hostující systém minimálně, bez věcí jako /proc nebo přiřazený název hostitele. Zkuste například následující příkazy:

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

Chcete-li se odhlásit z hosta, zadejte exit nebo stiskněte control-d. To zabije shell a následuje panika jádra:

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

Tuto paniku jádra jsme dostali, protože jádro Linuxu si myslí, že proces inicializace vždy běží. Bez něj již systém nemůže fungovat a padá. Ale protože se jedná o proces v uživatelském režimu, výsledný výstup se sám odešle SIGABRT, což má za následek výstup.

Nastavení sítě pro hosty

A tady se to začíná kazit. Síť v uživatelském režimu Linux je místo, kde se celý koncept omezeného „uživatelského režimu“ začíná rozpadat. Koneckonců, obvykle na úrovni systému je síť omezená výsadní z pochopitelných důvodů pro nás všechny.

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

Cesta do Slirp

Existuje však prastarý a téměř nepodporovaný nástroj tzv Slirp, se kterým může Linux v uživatelském režimu komunikovat se sítí. Funguje podobně jako zásobník TCP/IP na uživatelské úrovni a ke spuštění nevyžaduje žádná systémová oprávnění. Tento nástroj byl vydáno v roce 1995a poslední aktualizace je datována 2006 let. Slirp je velmi starý. Za dobu bez podpory a aktualizací zašly kompilátory tak daleko, že nyní lze tento nástroj označit pouze jako kódová hniloba.

Pojďme si tedy stáhnout Slirp z repozitářů Ubuntu a zkusit jej spustit:

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)

Ach bohové. Pojďme nainstalovat Slirpův debugger a uvidíme, jestli dokážeme zjistit, co se zde 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 <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.

Chyba v nás bije tento řádek. Podívejme se na stacktrace, třeba 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 = <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.

Zde vidíme, že k havárii dochází během startu hlavní smyčky, když se slirp pokouší zkontrolovat timeouty. V tuto chvíli jsem musel pokusy o ladění vzdát. Ale uvidíme, jestli Slirp postavený z sort funguje. Archiv jsem znovu stáhl přímo z webu SourceForge, protože přetáhnout něco odtud přes příkazový řádek je bolest:

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

Zde vidíme upozornění na nedefinované vestavěné funkce, tedy na nemožnost propojit výsledný binární soubor. Zdá se, že mezi rokem 2006 a tímto bodem přestalo gcc produkovat symboly používané ve vestavěných funkcích přechodných kompilovaných souborů. Zkusme klíčové slovo nahradit inline na prázdný komentář a podívejte se na výsledek:

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

Ani náhodou. Tohle taky nejde. Stále nemohu najít symboly pro tyto funkce.

V tuto chvíli jsem to vzdal a začal hledat na Github Sestavovací balíčky Heroku. Moje teorie byla, že nějaký balíček sestavení Heroku bude obsahovat binární soubory, které jsem potřeboval. Nakonec mě hledání vedlo právě tady. Stáhl jsem a rozbalil uml.tar.gz a našel 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*

Toto je binární slirp! Pracuje?

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

Nehavaruje - takže by to mělo fungovat! Zasadíme tuto dvojhvězdu ~/bin/slirp:

cp slirp ~/bin/slirp

V případě, že jej tvůrce balíčku odstraní, I udělal zrcadlo.

Nastavení sítě

Nyní nastavíme síť na našem hostujícím jádře. Aktualizujte možnosti spuštění:

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

Nyní zapněte 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 konfigurační příkazy /proc и /sys nutné pro práci ifconfig, který nastavuje síťové rozhraní pro komunikaci se Slirpem. tým route nastaví směrovací tabulku jádra tak, aby vynutila odesílání veškerého provozu tunelem Slirp. Zkontrolujeme to pomocí DNS dotazu:

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

Funguje to!

Poznámka k .: Původní příspěvek byl zjevně napsán na ploše s kabelovou síťovou kartou nebo jinou konfigurací, která nevyžadovala další ovladače. Na notebooku s WiFi 8265 od Intelu dochází k chybě při zvedání sítě

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

Zjevně jádro nemůže komunikovat s ovladačem síťové karty. Pokus o kompilaci firmwaru do jádra bohužel situaci nevyřešil. V době publikace nebylo možné najít řešení v této konfiguraci. Na jednodušších konfiguracích (například ve Virtualboxu) se rozhraní zvedne 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 označte jej jako spustitelný:

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 zopakujme si:

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íť je stabilní!

docker soubor

Abych vám to všechno usnadnil, shromáždil jsem dockerfile, který automatizuje většinu popsaných kroků a měl by vám poskytnout funkční konfiguraci. také mám předkonfigurované jádro, která má vše, co je popsáno v příspěvku. Je ale důležité pochopit, že jsem zde nastínil pouze minimální nastavení.

Doufám, že vám tento příspěvek pomohl pochopit, jak vychovat hostující jádro. Ukázalo se, že je to nějaké monstrum, ale publikace byla koncipována jako komplexní průvodce vytvářením, instalací a konfigurací uživatelského režimu v Linuxu pod moderními verzemi operačních systémů této rodiny. Další kroky by měly zahrnovat instalaci služeb a dalšího softwaru již uvnitř hostujícího systému. Vzhledem k tomu, že obrázky kontejnerů Docker jsou pouze zveřejněné tarbally, měli byste být schopni extrahovat obrázek pomocí docker exporta poté určete jeho instalační cestu v kořenovém adresáři souborového systému hostujícího jádra. No, pak spusťte skript shellu.

Zvláštní poděkování patří Rkeene z #lobsters na Freenode. Bez jeho pomoci při ladění Slirp bych se tak daleko nedostal. Nemám ponětí, jak jeho systém Slackware správně funguje se slirpem, ale moje systémy Ubuntu a Alpine neakceptovaly slirp a navrhla mi binární Rkeene. Ale stačí mi, že mi aspoň něco funguje.

Zdroj: www.habr.com

Přidat komentář