Bagaimana untuk mula menggunakan Mod Pengguna di Linux

Pengenalan daripada penterjemah: Berlatarbelakangkan kemasukan besar-besaran ke dalam kehidupan kita pelbagai jenis bekas, ia boleh menjadi agak menarik dan berguna untuk mengetahui dengan teknologi apa yang semuanya bermula sekali. Sesetengah daripada mereka boleh digunakan dengan berguna hingga ke hari ini, tetapi tidak semua orang mengingati kaedah sedemikian (atau tahu jika mereka tidak ditangkap semasa perkembangan pesat mereka). Satu teknologi sedemikian ialah Mod Pengguna Linux. Pengarang asal melakukan banyak penggalian, memikirkan perkembangan lama mana yang masih berfungsi dan yang tidak, dan menyusun sesuatu seperti arahan langkah demi langkah tentang cara untuk mendapatkan UML buatan sendiri dalam 2k19. Dan ya, kami menjemput pengarang jawatan asal kepada Habr Cadey, jadi jika anda mempunyai sebarang soalan - tanya dalam bahasa Inggeris dalam ulasan.

Bagaimana untuk mula menggunakan Mod Pengguna di Linux

Mod Pengguna dalam Linux, sebenarnya, pelabuhan kernel Linux kepada dirinya sendiri. Mod ini membolehkan anda menjalankan kernel Linux penuh sebagai proses pengguna dan biasanya digunakan oleh pembangun untuk menguji pemacu. Tetapi mod ini juga berguna sebagai alat pengasingan umum, yang prinsipnya serupa dengan pengendalian mesin maya. Mod ini menyediakan lebih banyak pengasingan daripada Docker, tetapi kurang daripada mesin maya yang lengkap seperti KVM atau Virtual Box.

Secara umum, Mod Pengguna mungkin kelihatan seperti alat yang pelik dan sukar untuk digunakan, tetapi ia masih mempunyai kegunaannya. Lagipun, ini adalah kernel Linux sepenuhnya yang dijalankan daripada pengguna yang tidak mempunyai hak istimewa. Ciri ini membolehkan kod yang mungkin tidak dipercayai dijalankan tanpa sebarang ancaman kepada mesin hos. Dan kerana ini adalah kernel sepenuhnya, prosesnya diasingkan daripada mesin hos, iaitu proses yang berjalan di dalam Mod Pengguna tidak akan kelihatan kepada hos. Ini tidak seperti bekas Docker biasa, dalam hal ini mesin hos sentiasa melihat proses di dalam repositori. Lihat sekeping pstree ini dari salah satu pelayan saya:

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

Dan bandingkan ini dengan pstree kernel Linux dalam Mod Pengguna:

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

Apabila bekerja dengan bekas Docker, saya dapat melihat dari hos nama-nama proses yang sedang berjalan dalam tetamu. Dengan Mod Pengguna Linux, ini tidak boleh dilakukan. Apakah maksudnya? Ini bermakna alat pemantauan yang dijalankan melalui subsistem pengauditan Linux jangan tengok proses berjalan dalam sistem tetamu. Tetapi dalam beberapa situasi, ciri ini boleh menjadi pedang bermata dua.

Secara umum, keseluruhan siaran di bawah adalah koleksi penyelidikan dan percubaan kasar untuk mencapai hasil yang diinginkan. Untuk melakukan ini, saya perlu menggunakan pelbagai alat kuno, membaca sumber kernel, melakukan penyahpepijatan intensif kod yang ditulis pada zaman saya masih di sekolah rendah, dan juga bermain-main dengan binaan Heroku menggunakan binari khas untuk mencari alat yang saya perlukan. . Semua kerja ini menyebabkan lelaki di IRC saya memanggil saya sihir. Saya harap siaran ini berfungsi sebagai dokumentasi yang boleh dipercayai untuk seseorang mencuba perkara yang sama dengan kernel dan versi OS yang lebih baharu.

pelarasan

Menyediakan Mod Pengguna Linux dilakukan dalam beberapa langkah:

  • memasang kebergantungan pada hos;
  • memuat turun kernel Linux;
  • konfigurasi binaan kernel;
  • pemasangan inti;
  • pemasangan binari;
  • mengkonfigurasi sistem fail tetamu;
  • pemilihan parameter pelancaran kernel;
  • menyediakan rangkaian tetamu;
  • memulakan kernel tetamu.

Saya menganggap bahawa jika anda memutuskan untuk melakukannya sendiri, anda kemungkinan besar akan melakukan semua yang diterangkan dalam beberapa sistem seperti Ubuntu atau Debian. Saya cuba melaksanakan semua perkara di atas dalam pengedaran kegemaran saya - Alpine, tetapi tiada apa yang berlaku, nampaknya disebabkan oleh fakta bahawa kernel Linux mempunyai glibc-ism yang mengikat untuk pemandu dalam Mod Pengguna. Saya bercadang untuk melaporkan perkara ini kepada huluan selepas saya akhirnya memahami masalahnya.

Memasang kebergantungan pada hos

Ubuntu memerlukan sekurang-kurangnya pakej berikut untuk membina kernel Linux (dengan mengandaikan pemasangan bersih):

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

Anda boleh memasangnya dengan arahan berikut (sebagai root atau dengan sudo):

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

Ambil perhatian bahawa menjalankan program persediaan menu kernel Linux memerlukan pemasangan libncurses-dev. Sila pastikan ia dipasang dengan arahan berikut (sebagai root atau dengan sudo):

apt-get -y install libncurses-dev

Muat turun kernel

Tentukan tempat untuk memuat turun dan kemudian bina kernel. Untuk operasi ini, anda perlu memperuntukkan kira-kira 1,3 GB ruang cakera keras, jadi pastikan anda memilikinya.

Selepas pergi ke kernel.org dan dapatkan URL untuk memuat turun kernel stabil terkini. Pada masa penulisan ini ialah: https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

Muat turun fail ini menggunakan 'wget':

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

Dan ekstrak dengan 'tar':

tar xJf linux-5.1.16.tar.xz

Sekarang kita memasuki direktori yang dibuat semasa membongkar tarball:

cd linux-5.1.16

Persediaan binaan kernel

Sistem binaan kernel adalah satu set Makefiles с ramai alatan dan skrip tersuai untuk mengautomasikan proses. Mula-mula, buka program persediaan interaktif:

make ARCH=um menuconfig

Ia sebahagiannya akan membina dan memaparkan kotak dialog untuk anda. Bila '[Select]', anda akan dapat mengkonfigurasi menggunakan kekunci Space atau Enter. Navigasi tetingkap, seperti biasa, dengan anak panah papan kekunci "atas" dan "bawah", dan pilih elemen - "kiri" atau "kanan".

Penunjuk pandangan —> bermakna anda berada dalam submenu, diakses oleh kekunci Enter. Jalan keluar daripadanya jelas melalui '[Exit]'.

Sertakan pilihan berikut dalam '[Select]' dan pastikan mereka mempunyai '[*]' di sebelahnya:

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

Itu sahaja, anda boleh keluar dari tetingkap ini dengan memilih '[Exit]'. Hanya pastikan anda digesa untuk menyimpan konfigurasi pada penghujung dan pilih '[Yes]'.

Saya mengesyorkan anda bermain-main dengan pilihan binaan kernel selepas membaca siaran ini. Melalui eksperimen ini, anda boleh belajar banyak dari segi memahami kerja mekanik kernel peringkat rendah dan kesan pelbagai bendera pada pemasangannya.

Membina inti

Kernel Linux ialah program besar yang melakukan banyak perkara. Walaupun dengan konfigurasi minimum pada perkakasan lama, ia boleh mengambil masa yang agak lama untuk dibina. Jadi bina kernel dengan arahan berikut:

make ARCH=um -j$(nproc)

Untuk apa? Perintah ini akan memberitahu pembina kami untuk menggunakan semua teras dan utas CPU yang tersedia dalam proses binaan. Pasukan $(nproc) pada akhir Build menggantikan output arahan nproc, yang merupakan sebahagian daripada coreutils dalam binaan Ubuntu standard.

Selepas beberapa lama, kernel kami akan disusun menjadi fail boleh laku ./linux.

Memasang binari

Memandangkan Mod Pengguna dalam Linux mencipta binari biasa, anda boleh memasangnya seperti mana-mana utiliti lain. Begini cara saya melakukannya:

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

Ia juga berbaloi untuk memastikannya ~/bin ada dalam awak $PATH:

export PATH=$PATH:$HOME/bin

Menyediakan sistem fail tetamu

Buat direktori untuk sistem fail tetamu:

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

Buka alpinelinux.org dan masuk bahagian muat turun cari pautan muat turun sebenar MINI ROOT FILESYSTEM. Pada masa penulisan ini adalah:

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

Muat turun tarball ini menggunakan 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

Sekarang masukkan direktori sistem fail tetamu dan ekstrak arkib:

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

Tindakan yang diterangkan akan mencipta templat sistem fail kecil. Oleh kerana sifat sistem, ia akan menjadi sangat sukar untuk memasang pakej melalui pengurus apk Alpine. Tetapi FS ini akan cukup untuk menilai idea umum.

Kami juga memerlukan alat tini untuk mengekang penggunaan memori proses zombi kernel tetamu kami.

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

Mencipta baris arahan kernel

Kernel Linux, seperti kebanyakan program lain, mempunyai argumen baris perintah yang boleh diakses dengan menentukan kunci --help.

Dirinya sendiri —membantu

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.

Panel ini menyerlahkan parameter utama pelancaran. Mari jalankan kernel dengan set pilihan minimum yang diperlukan:

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

Baris di atas memberitahu kernel kami yang berikut:

  • Andaikan sistem fail akar ialah peranti pseudo /dev/root.
  • Pilih hostfs sebagai pemacu sistem fail akar.
  • Lekapkan sistem fail tetamu yang kami buat pada peranti root.
  • Dan ya, dalam mod baca-tulis.
  • Gunakan hanya 64 MB RAM (anda boleh menggunakan lebih sedikit bergantung pada apa yang anda bercadang untuk lakukan, tetapi 64 MB kelihatan seperti jumlah yang optimum).
  • Kernel bermula secara automatik /bin/sh sebagai init-proses.

Jalankan arahan ini dan anda sepatutnya mendapat sesuatu seperti berikut:

Satu helaian lagi

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

Manipulasi di atas akan memberi kita sistem tetamu sekurang-kurangnya, tanpa perkara seperti /proc atau nama hos yang diberikan. Sebagai contoh, cuba arahan berikut:

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

Untuk log keluar daripada tetamu, taip exit atau tekan control-d. Ini akan membunuh shell diikuti oleh panik kernel:

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

Kami mendapat panik kernel ini kerana kernel Linux berpendapat proses pemulaan sentiasa berjalan. Tanpanya, sistem tidak lagi boleh berfungsi dan ranap. Tetapi kerana ini adalah proses mod pengguna, output yang terhasil dihantar sendiri ke SIGABRT, yang menghasilkan output.

Persediaan rangkaian tetamu

Dan di sinilah perkara mula menjadi salah. Rangkaian dalam Mod Pengguna Linux ialah tempat keseluruhan konsep "mod pengguna" terhad mula berantakan. Lagipun, biasanya pada peringkat sistem, rangkaian adalah terhad diberi keistimewaan mod pelaksanaan untuk kita semua sebab yang boleh difahami.

Catatan. per .: anda boleh membaca lebih lanjut tentang pilihan yang berbeza untuk bekerja dengan rangkaian dalam UML di sini.

Perjalanan ke Slirp

Walau bagaimanapun, terdapat alat kuno dan hampir tidak disokong dipanggil Slirp, yang mana Mod Pengguna Linux boleh berinteraksi dengan rangkaian. Ia berfungsi seperti tindanan TCP/IP peringkat pengguna dan tidak memerlukan sebarang kebenaran sistem untuk dijalankan. Alat ini adalah dikeluarkan pada tahun 1995, dan kemas kini terkini adalah bertarikh Tahun 2006. Slirp sangat tua. Sepanjang masa tanpa sokongan dan kemas kini, penyusun telah pergi begitu jauh sehingga kini alat ini hanya boleh digambarkan sebagai reput kod.

Jadi mari muat turun Slirp dari repositori Ubuntu dan cuba jalankannya:

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)

Oh tuhan. Mari pasang penyahpepijat Slirp dan lihat sama ada kita boleh mengetahui perkara yang berlaku di sini:

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.

Kesilapan berdegup dalam diri kita baris ini. Mari kita lihat stacktrace, mungkin sesuatu akan membantu kita di sana:

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

Di sini kita melihat bahawa ranap sistem berlaku semasa gelung utama bermula apabila slirp cuba menyemak tamat masa. Pada ketika ini, saya terpaksa berhenti mencuba untuk menyahpepijat. Tetapi mari kita lihat sama ada Slirp dibina daripada jenis berfungsi. Saya memuat turun semula arkib terus dari tapak Sourceforge, kerana menyeret sesuatu dari sana melalui baris arahan adalah sakit:

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

Di sini kita melihat makluman tentang fungsi terbina dalam yang tidak ditentukan, iaitu, tentang ketidakupayaan untuk memautkan fail binari yang terhasil. Nampaknya antara tahun 2006 dan ketika ini, gcc berhenti menghasilkan simbol yang digunakan dalam fungsi terbina dalam fail tersusun perantaraan. Mari cuba menggantikan kata kunci inline pada komen kosong dan lihat hasilnya:

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

Tidak. Ini juga tidak berfungsi. Masih tidak dapat mencari simbol untuk fungsi ini.

Pada ketika ini, saya menyerah dan mula melihat Github Pakej binaan Heroku. Teori saya ialah beberapa pakej binaan Heroku akan mengandungi binari yang saya perlukan. Akhirnya, pencarian membawa saya dekat sini. Saya memuat turun dan membongkar uml.tar.gz dan mendapati perkara berikut:

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*

Ini adalah binari slirp! Adakah dia bekerja?

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

Tidak ranap - jadi ia sepatutnya berfungsi! Mari kita tanam binari ini dalam ~/bin/slirp:

cp slirp ~/bin/slirp

Sekiranya pencipta pakej mengeluarkannya, I membuat cermin.

Konfigurasi rangkaian

Sekarang mari kita sediakan rangkaian pada kernel tetamu kita. Kemas kini pilihan pelancaran:

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

Sekarang mari hidupkan rangkaian:

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

Dua arahan konfigurasi pertama /proc и /sys perlu untuk kerja ifconfig, yang menetapkan antara muka rangkaian untuk berkomunikasi dengan Slirp. Pasukan route menetapkan jadual penghalaan kernel untuk memaksa semua trafik dihantar melalui terowong Slirp. Mari semak ini dengan pertanyaan DNS:

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

Ia berfungsi!

Nota per .: Nampaknya, siaran asal ditulis pada desktop dengan kad rangkaian berwayar, atau beberapa konfigurasi lain yang tidak memerlukan pemacu tambahan. Pada komputer riba dengan WiFi 8265 daripada Intel, ralat berlaku semasa menaikkan rangkaian

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

Nampaknya, kernel tidak dapat berkomunikasi dengan pemacu kad rangkaian. Percubaan untuk menyusun perisian tegar ke dalam kernel, malangnya, tidak membetulkan keadaan. Pada masa penerbitan, tidak mungkin untuk mencari penyelesaian dalam konfigurasi ini. Pada konfigurasi yang lebih mudah (contohnya, dalam Virtualbox), antara muka meningkat dengan betul.

Mari kita mengautomasikan ubah hala dengan skrip shell berikut:

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

Dan tandakan ia boleh laku:

chmod +x init.sh

Dan kemudian kami akan membuat perubahan pada baris arahan kernel:

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

Dan mari kita ulangi:

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

Rangkaian adalah stabil!

fail docker

Untuk memudahkan anda menyemak semua ini, saya telah mengumpulkan Dockerfile, yang mengautomasikan kebanyakan langkah yang diterangkan dan sepatutnya memberi anda konfigurasi yang berfungsi. saya juga ada kernel prakonfigurasi, yang mempunyai semua yang diterangkan dalam siaran. Tetapi adalah penting untuk memahami bahawa di sini saya telah menggariskan hanya tetapan minimum.

Saya harap siaran ini telah membantu anda memahami cara menaikkan kernel tetamu. Ia ternyata sejenis raksasa, tetapi penerbitan itu difikirkan sebagai panduan komprehensif untuk membina, memasang dan mengkonfigurasi Mod Pengguna dalam Linux di bawah versi moden sistem pengendalian keluarga ini. Langkah seterusnya harus termasuk memasang perkhidmatan dan perisian lain yang sudah ada di dalam sistem tetamu. Memandangkan imej kontena Docker hanyalah tarball yang dipublikasikan, anda sepatutnya dapat mengekstrak imej itu melalui docker export, dan kemudian tentukan laluan pemasangannya dalam akar sistem fail kernel tetamu. Nah, kemudian laksanakan skrip shell.

Terima kasih khas kepada Rkeene daripada #lobsters di Freenode. Tanpa bantuannya menyahpepijat Slirp, saya tidak akan sampai sejauh ini. Saya tidak tahu bagaimana sistem Slackwarenya berfungsi dengan betul dengan slirp, tetapi sistem Ubuntu dan Alpine saya tidak menerima slirp dan Rkeene binari mencadangkan kepada saya. Tetapi ia cukup untuk saya bahawa sekurang-kurangnya sesuatu bekerja untuk saya.

Sumber: www.habr.com

Tambah komen