Cara mulai menggunakan Mode Pengguna di Linux

Pengantar dari penerjemah: Dengan latar belakang masuknya berbagai jenis kontainer ke dalam kehidupan kita secara besar-besaran, akan sangat menarik dan berguna untuk mengetahui teknologi apa yang memulai semuanya. Beberapa di antaranya dapat digunakan secara berguna hingga saat ini, namun tidak semua orang mengingat metode tersebut (atau mengetahui jika metode tersebut tidak tertangkap selama perkembangan pesatnya). Salah satu teknologi tersebut adalah Mode Pengguna Linux. Penulis versi asli melakukan banyak penggalian, mencari tahu pengembangan lama mana yang masih berfungsi dan mana yang tidak, dan menyusun sesuatu seperti petunjuk langkah demi langkah tentang cara mendapatkan UML buatan sendiri di 2k19. Dan ya, kami mengundang penulis postingan asli ke Habr Cadey, jadi jika ada pertanyaan, tanyakan dalam bahasa Inggris di komentar.

Cara mulai menggunakan Mode Pengguna di Linux

Mode Pengguna di Linux sebenarnya adalah port dari kernel Linux itu sendiri. Mode ini memungkinkan Anda menjalankan kernel Linux lengkap sebagai proses pengguna dan biasanya digunakan oleh pengembang untuk menguji driver. Namun mode ini juga berguna sebagai alat isolasi umum, yang prinsipnya mirip dengan pengoperasian mesin virtual. Mode ini memberikan lebih banyak isolasi daripada Docker, tetapi kurang dari mesin virtual lengkap seperti KVM atau Virtual Box.

Secara keseluruhan, Mode Pengguna mungkin tampak seperti alat yang aneh dan sulit untuk digunakan, namun ada kegunaannya. Bagaimanapun, ini adalah kernel Linux lengkap yang berjalan sebagai pengguna yang tidak memiliki hak istimewa. Fitur ini memungkinkan kode yang berpotensi tidak dipercaya untuk dijalankan tanpa ancaman apa pun terhadap mesin host. Dan karena ini adalah kernel yang lengkap, prosesnya diisolasi dari mesin host proses yang berjalan di dalam Mode Pengguna tidak akan terlihat oleh host. Ini tidak seperti container Docker biasa, dalam hal ini mesin host selalu melihat proses di dalam repositori. Lihatlah pstree ini dari salah satu server 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 Mode Pengguna:

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

Saat bekerja dengan container Docker, saya dapat melihat dari host nama-nama proses yang berjalan di guest. Dengan Mode Pengguna Linux, hal ini tidak mungkin dilakukan. Apa artinya? Ini berarti alat pemantauan yang dijalankan melalui subsistem audit Linux tidak melihat proses yang berjalan di sistem tamu. Namun dalam beberapa situasi, fitur ini bisa menjadi pedang bermata dua.

Secara umum, keseluruhan postingan di bawah ini merupakan kumpulan penelitian dan upaya kasar untuk mencapai hasil yang diinginkan. Untuk melakukan ini, saya harus menggunakan berbagai alat kuno, membaca sumber kernel, melakukan debug intensif terhadap kode yang ditulis ketika saya masih di sekolah dasar, dan juga mengutak-atik build Heroku menggunakan biner khusus untuk menemukan alat yang saya butuhkan. . Semua pekerjaan ini membuat orang-orang di IRC saya menyebut saya ajaib. Saya harap postingan ini berfungsi sebagai dokumentasi yang dapat dipercaya bagi seseorang untuk mencoba hal yang sama dengan kernel dan versi OS yang lebih baru.

pengaturan

Menyiapkan Mode Pengguna Linux melibatkan beberapa langkah:

  • menginstal dependensi pada host;
  • mengunduh kernel Linux;
  • konfigurasi pembuatan kernel;
  • perakitan kernel;
  • instalasi biner;
  • mengkonfigurasi sistem file tamu;
  • pemilihan parameter peluncuran kernel;
  • menyiapkan jaringan tamu;
  • memulai kernel tamu.

Saya berasumsi bahwa jika Anda memutuskan untuk melakukannya sendiri, kemungkinan besar Anda akan melakukan semua yang dijelaskan di sistem mirip Ubuntu atau Debian. Saya mencoba menerapkan semua hal di atas dalam distribusi favorit saya - Alpine, tetapi tidak ada hasil, tampaknya karena fakta bahwa kernel Linux memiliki glibc-isms yang mengikat keras untuk driver dalam Mode Pengguna. Saya berencana melaporkan hal ini ke hulu setelah saya akhirnya memahami masalahnya.

Menginstal dependensi pada host

Ubuntu memerlukan setidaknya paket-paket berikut untuk membangun kernel Linux (dengan asumsi instalasi bersih):

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

Anda dapat menginstalnya dengan perintah berikut (sebagai root atau dengan sudo):

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

Perhatikan bahwa menjalankan program pengaturan menu kernel Linux memerlukan instalasi libncurses-dev. Pastikan itu diinstal dengan perintah berikut (sebagai root atau dengan sudo):

apt-get -y install libncurses-dev

Unduhan kernel

Tentukan tempat untuk mengunduh dan kemudian membangun kernel. Untuk operasi ini, Anda perlu mengalokasikan sekitar 1,3 GB ruang hard disk, jadi pastikan Anda memilikinya.

Setelah pergi ke kernel.org dan dapatkan URL untuk mengunduh versi kernel stabil terbaru. Pada saat menulis posting ini: https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

Unduh file 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 masuk ke direktori yang dibuat saat membongkar tarball:

cd linux-5.1.16

Pengaturan pembuatan kernel

Sistem pembangunan kernel adalah satu set file make с banyak alat dan skrip khusus untuk mengotomatiskan proses. Pertama, buka program pengaturan interaktif:

make ARCH=um menuconfig

Ini sebagian akan membangun dan menampilkan kotak dialog untuk Anda. Kapan '[Select]', Anda dapat mengonfigurasinya menggunakan tombol Spasi atau Enter. Navigasikan jendela, seperti biasa, dengan panah keyboard "atas" dan "bawah", dan pilih elemen - "kiri" atau "kanan".

Penunjuk tampilan —> berarti Anda berada dalam submenu, diakses dengan tombol Enter. Jalan keluarnya jelas melalui '[Exit]'.

Sertakan opsi berikut di '[Select]' dan pastikan ada simbol '[*]' 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 saja, Anda dapat keluar dari jendela ini dengan memilih '[Exit]'. Pastikan pada akhirnya Anda diminta untuk menyimpan konfigurasi dan pilih '[Yes]'.

Saya sarankan Anda bermain-main dengan opsi build kernel setelah membaca posting ini. Dari eksperimen ini Anda dapat belajar banyak tentang cara kerja mekanisme kernel tingkat rendah dan bagaimana flag yang berbeda memengaruhi cara kernel dibangun.

Membangun kernel

Kernel Linux adalah program besar yang melakukan banyak hal. Bahkan dengan konfigurasi minimal pada perangkat keras lama, proses pembuatannya bisa memakan waktu cukup lama. Jadi buatlah kernel dengan perintah berikut:

make ARCH=um -j$(nproc)

Untuk apa? Perintah ini akan memberitahu pembuat kami untuk menggunakan semua inti dan thread CPU yang tersedia dalam proses pembuatan. Tim $(nproc) di akhir Build menggantikan output dari perintah nproc, yang merupakan bagian dari coreutils dalam build standar Ubuntu.

Setelah beberapa waktu, kernel kita akan dikompilasi menjadi file yang dapat dieksekusi ./linux.

Menginstal biner

Karena Mode Pengguna di Linux membuat biner biasa, Anda dapat menginstalnya seperti utilitas lainnya. Inilah cara saya melakukannya:

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

Penting juga untuk memastikan hal itu ~/bin ada di dalam kamu $PATH:

export PATH=$PATH:$HOME/bin

Menyiapkan sistem file tamu

Buat direktori untuk sistem file tamu:

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

Buka alpinelinux.org dan masuk bagian unduhan temukan tautan unduhan yang sebenarnya MINI ROOT FILESYSTEM. Pada saat penulisan ini adalah:

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

Unduh 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 masuk ke direktori sistem file tamu dan ekstrak arsipnya:

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

Tindakan yang dijelaskan akan membuat templat sistem file kecil. Karena cara kerja sistem, menginstal paket melalui pengelola apk Alpine akan sangat sulit. Tapi FS ini akan cukup untuk mengevaluasi gambaran umum.

Kami juga membutuhkan alat kecil untuk menghentikan konsumsi memori proses zombie kernel tamu kami.

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

Membuat baris perintah kernel

Kernel Linux, seperti kebanyakan program lainnya, memiliki argumen baris perintah yang dapat diakses dengan menentukan kuncinya --help.

Dirinya sendiri—tolong

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 menyoroti parameter peluncuran utama. Mari kita jalankan kernel dengan serangkaian opsi minimum yang diperlukan:

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

Baris di atas memberi tahu kernel kita hal berikut:

  • Anggaplah sistem file root adalah perangkat semu /dev/root.
  • Memilih hostfs sebagai driver sistem file root.
  • Pasang sistem file tamu yang kami buat di perangkat root.
  • Dan ya, dalam mode baca-tulis.
  • Gunakan hanya 64 megabyte RAM (Anda dapat menggunakan lebih sedikit tergantung pada apa yang Anda rencanakan, tetapi 64 MB tampaknya merupakan jumlah optimal).
  • Kernel secara otomatis dimulai /bin/sh sebagai init-proses.

Jalankan perintah ini dan Anda akan mendapatkan sesuatu seperti berikut:

Lembar lain

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 tamu minimal, tanpa hal-hal seperti /proc atau nama host yang ditetapkan. Misalnya, coba perintah berikut:

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

Untuk keluar dari tamu, ketik exit atau tekan kontrol-d. Ini akan mematikan shell yang diikuti dengan kepanikan kernel:

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

Kami mengalami kepanikan kernel ini karena kernel Linux menganggap proses inisialisasi selalu berjalan. Tanpanya, sistem tidak dapat berfungsi lagi dan crash. Namun karena ini adalah proses mode pengguna, keluaran yang dihasilkan akan dikirimkan sendiri ke SIGABRT, yang menghasilkan output.

Pengaturan jaringan tamu

Dan di sinilah segalanya mulai salah. Jaringan dalam Mode Pengguna Linux adalah tempat seluruh konsep "mode pengguna" terbatas mulai berantakan. Lagi pula, biasanya pada tingkat sistem, jaringannya terbatas istimewa mode eksekusi untuk alasan yang dapat dimengerti oleh kita semua.

Catatan. per.: Anda dapat membaca lebih lanjut tentang berbagai opsi untuk bekerja dengan jaringan di UML di sini.

Perjalanan ke Slirp

Namun, ada alat kuno dan hampir tidak didukung yang disebut selip, yang dengannya Mode Pengguna Linux dapat berinteraksi dengan jaringan. Ia bekerja seperti tumpukan TCP/IP tingkat pengguna dan tidak memerlukan izin sistem apa pun untuk dijalankan. Alat ini adalah dirilis pada tahun 1995, dan pembaruan terkini bertanggal 2006 tahun. Slirp sudah sangat tua. Selama ini tanpa dukungan dan pembaruan, kompiler telah melangkah sejauh ini sehingga sekarang alat ini hanya dapat digambarkan sebagai pembusukan kode.

Jadi mari unduh Slirp dari repositori Ubuntu dan coba jalankan:

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 tuhanku. Mari kita instal debugger Slirp dan lihat apakah kita dapat mengetahui apa yang terjadi 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.

Kesalahan terjadi pada diri kita garis ini. Mari kita lihat stacktrace, mungkin ada yang bisa 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 bahwa crash terjadi selama permulaan loop utama ketika slirp mencoba memeriksa batas waktu. Pada titik ini, saya harus berhenti mencoba melakukan debug. Tapi mari kita lihat apakah Slirp yang dibuat berhasil. Saya mengunduh ulang arsip langsung dari situsnya Sourceforge, karena menyeret sesuatu dari sana melalui baris perintah itu merepotkan:

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 peringatan tentang fungsi bawaan yang tidak terdefinisi, yaitu ketidakmampuan untuk menghubungkan file biner yang dihasilkan. Tampaknya antara tahun 2006 dan saat ini, gcc berhenti memproduksi simbol yang digunakan dalam fungsi bawaan file kompilasi perantara. Mari kita coba mengganti kata kuncinya inline pada komentar kosong dan lihat hasilnya:

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

Tidak. Ini juga tidak berhasil. Masih tidak dapat menemukan simbol untuk fungsi-fungsi ini.

Pada titik ini, saya menyerah dan mulai mencari di Github Paket pembuatan Heroku. Teori saya adalah bahwa beberapa paket build Heroku akan berisi biner yang saya butuhkan. Pada akhirnya, pencarian itu membawa saya di sini. Saya mengunduh dan membongkar uml.tar.gz dan menemukan yang berikut ini:

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 biner slirp! Apakah 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 mogok - jadi seharusnya berhasil! Mari kita tanam biner ini ~/bin/slirp:

cp slirp ~/bin/slirp

Jika pembuat paket menghapusnya, I membuat cermin.

Pengaturan jaringan

Sekarang mari kita konfigurasikan jaringan pada inti tamu kita. Perbarui opsi peluncuran:

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

Sekarang mari kita nyalakan jaringan:

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 perintah konfigurasi pertama /proc и /sys diperlukan untuk bekerja ifconfig, yang mengatur antarmuka jaringan untuk berkomunikasi dengan Slirp. Tim route mengatur tabel perutean kernel untuk memaksa semua lalu lintas dikirim melalui terowongan Slirp. Mari kita periksa ini dengan permintaan 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

Itu berhasil!

Catatan per.: Rupanya, postingan asli ditulis di desktop dengan kartu jaringan berkabel, atau konfigurasi lain yang tidak memerlukan driver tambahan. Pada laptop dengan WiFi 8265 dari Intel, terjadi kesalahan saat menaikkan jaringan

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

Rupanya, kernel tidak dapat berkomunikasi dengan driver kartu jaringan. Sayangnya, upaya untuk mengkompilasi firmware ke dalam kernel tidak memperbaiki situasi. Pada saat publikasi, solusi dalam konfigurasi ini tidak dapat ditemukan. Pada konfigurasi yang lebih sederhana (misalnya, di Virtualbox), antarmuka muncul dengan benar.

Mari kita otomatisasi pengalihan 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 tandai sebagai dapat dieksekusi:

chmod +x init.sh

Dan kemudian kita akan membuat perubahan pada baris perintah 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

Jaringannya stabil!

file buruh pelabuhan

Untuk memudahkan Anda memeriksa semua ini, saya telah mengumpulkannya Dockerfile, yang mengotomatiskan sebagian besar langkah yang dijelaskan dan akan memberi Anda konfigurasi yang berfungsi. saya juga punya kernel yang telah dikonfigurasi sebelumnya, yang memiliki semua yang dijelaskan di postingan. Namun penting untuk dipahami bahwa di sini saya hanya menguraikan pengaturan minimum.

Saya harap postingan ini membantu Anda memahami cara meningkatkan kernel tamu. Ternyata itu semacam monster, tetapi publikasi ini dimaksudkan sebagai panduan komprehensif tentang membangun, menginstal, dan mengonfigurasi Mode Pengguna di Linux pada versi modern sistem operasi keluarga ini. Langkah selanjutnya harus mencakup instalasi layanan dan perangkat lunak lain yang sudah ada di dalam sistem tamu. Karena image container Docker hanyalah tarball yang dipublikasikan, Anda seharusnya dapat mengekstrak image tersebut melalui docker export, lalu tentukan jalur instalasinya di root sistem file kernel tamu. Baiklah, jalankan skrip shell.

Terima kasih khusus kepada Rkeene dari #lobsters di Freenode. Tanpa bantuannya untuk men-debug Slirp, saya tidak akan sampai sejauh ini. Saya tidak tahu bagaimana sistem Slackware-nya bekerja dengan benar dengan slirp, tetapi sistem Ubuntu dan Alpine saya tidak menerima slirp dan biner yang disarankan Rkeene kepada saya. Tapi itu cukup bagi saya bahwa setidaknya ada sesuatu yang berhasil untuk saya.

Sumber: www.habr.com

Tambah komentar