如何在 Linux 中开始使用用户模式

译者介绍:在各种容器大量进入我们的生活的背景下,了解这些容器曾经是由哪些技术开始的,是非常有趣和有用的。 其中一些方法至今仍然有用,但并不是每个人都记得这些方法(或者知道它们在快速发展过程中是否未被捕获)。 用户模式 ​​Linux 就是其中一项技术。 原作者做了很多挖掘工作,弄清楚哪些旧的开发仍然有效,哪些无效,并整理出一些类似于如何在 2k19 中为自己提供自制 UML 的分步说明。 是的,我们邀请了原帖的作者到 Habr 凯迪,所以如果您有任何疑问 - 请在评论中用英语提问。

如何在 Linux 中开始使用用户模式

Linux 中的用户模式实际上是 Linux 内核对其自身的移植。 此模式允许您作为用户进程运行完整的 Linux 内核,并且通常被开发人员用来测试驱动程序。 但这种模式作为通用隔离工具也很有用,其原理与虚拟机的操作类似。 此模式提供了比 Docker 更多的隔离,但不如 KVM 或 Virtual Box 等成熟的虚拟机。

一般来说,用户模式似乎是一个奇怪且难以使用的工具,但它仍然有其用途。 毕竟,这是一个由非特权用户运行的成熟的 Linux 内核。 此功能允许潜在不受信任的代码运行,而不会对主机造成任何威胁。 由于这是一个成熟的内核,因此它的进程与主机隔离,即 在用户模式中运行的进程对主机不可见。 这与通常的 Docker 容器不同,在这种情况下,主机总是可以看到存储库内的进程。 从我的一台服务器上查看这段 pstree:

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

并将其与用户模式下 Linux 内核的 pstree 进行比较:

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

使用 Docker 容器时,我可以从主机看到来宾中运行的进程的名称。 对于 Linux 用户模式,这是不可能的。 这是什么意思? 这意味着通过 Linux 审计子系统运行的监控工具 别看 来宾系统中运行的进程。 但在某些情况下,此功能可能成为一把双刃剑。

总的来说,下面的整篇文章是为了达到预期结果而进行的研究和粗略尝试的集合。 为此,我必须使用各种古老的工具,阅读内核源代码,对我还在小学时编写的代码进行深入调试,并使用特殊的二进制文件修补 Heroku 构建以找到我需要的工具。 所有这些工作让我的 IRC 上的人称我为魔法。 我希望这篇文章可以作为可靠的文档,供人们尝试使用较新的内核和操作系统版本进行相同的操作。

调整

设置 Linux 用户模式需要几个步骤:

  • 在主机上安装依赖项;
  • 下载Linux内核;
  • 内核构建配置;
  • 内核汇编;
  • 二进制安装;
  • 配置来宾文件系统;
  • 选择内核启动参数;
  • 设置访客网络;
  • 启动来宾内核。

我认为如果您决定自己做,您很可能会执行某些 Ubuntu 或类似 Debian 的系统中描述的所有操作。 我尝试在我最喜欢的发行版 Alpine 中实现上述所有内容,但没有任何结果,显然是因为 Linux 内核在用户模式下对驱动程序有一个硬绑定的 glibc-isms。 我打算在最终了解问题后向上游报告此情况。

在主机上安装依赖项

Ubuntu 至少需要以下软件包来构建 Linux 内核(假设全新安装):

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

您可以使用以下命令(以 root 身份或使用 sudo)安装它们:

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

请注意,运行 Linux 内核菜单设置程序需要安装 libncurses-dev。 请确保使用以下命令安装它(以 root 身份或使用 sudo):

apt-get -y install libncurses-dev

内核下载

决定在哪里下载然后构建内核。 对于此操作,您将需要分配大约 1,3 GB 的硬盘空间,因此请确保您有它。

之后去 kernel.org 并获取下载最新稳定内核的 URL。 在撰写本文时,这是: https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz

使用下载此文件 'wget':

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

并提取它 'tar':

tar xJf linux-5.1.16.tar.xz

现在我们进入解压 tarball 时创建的目录:

cd linux-5.1.16

内核构建设置

内核构建系统是一套 生成文件 с 许多 自定义工具和脚本来自动化该过程。 首先,打开交互式安装程序:

make ARCH=um menuconfig

它将部分地为您构建并显示一个对话框。 什么时候 '[Select]',您将能够使用空格键或 Enter 键进行配置。 像往常一样,使用键盘箭头“向上”和“向下”导航窗口,然后选择元素 - “左”或“右”。

视图指针 —> 表示您位于子菜单中,可通过 Enter 键访问。 摆脱困境的出路显然是通过'[Exit]“。

在 ' 中包含以下选项[Select]'并确保它们旁边有一个'[*]':

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

就是这样,您可以通过连续选择'来退出该窗口[Exit]'。 只需确保最后提示您保存配置并选择“[Yes]“。

我建议您在阅读本文后尝试一下内核构建选项。 通过这些实验,您可以在了解低级内核机制的工作以及各种标志对其汇编的影响方面学到很多东西。

构建内核

Linux 内核是一个可以做很多事情的大程序。 即使在旧硬件上使用如此最小的配置,也可能需要相当长的时间来构建。 因此,使用以下命令构建内核:

make ARCH=um -j$(nproc)

为了什么? 该命令将告诉我们的构建器在构建过程中使用所有可用的 CPU 核心和线程。 团队 $(nproc) 在 Build 的末尾替换命令的输出 nproc, 这是的一部分 coreutils 在标准 Ubuntu 构建中。

一段时间后,我们的内核将被编译成可执行文件 ./linux.

安装二进制文件

由于 Linux 中的用户模式创建了常规二进制文件,因此您可以像任何其他实用程序一样安装它。 我是这样做的:

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

还值得确保的是 ~/bin 在你的 $PATH:

export PATH=$PATH:$HOME/bin

设置来宾文件系统

为来宾文件系统创建目录:

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

打开 alpinelinux.org 并进入 下载部分 找到实际的下载链接 MINI ROOT FILESYSTEM。 在撰写本文时,情况是:

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

使用 wget 下载此 tarball:

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

现在进入来宾文件系统的目录并提取存档:

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

所描述的操作将创建一个小型文件系统模板。 由于系统的性质,通过 Alpine apk 管理器安装软件包将非常困难。 但这个FS足以评估总体思路。

我们还需要一个工具 TINI 抑制内存消耗 僵尸进程 我们的来宾内核。

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

创建内核命令行

Linux 内核与大多数其他程序一样,具有可以通过指定键来访问的命令行参数 --help.

他自己——帮助

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.

该面板重点介绍了此次发布的主要参数。 让我们使用所需的最少选项集来运行内核:

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

上面的几行告诉我们的内核以下内容:

  • 假设根文件系统是一个伪设备 /dev/root.
  • 选择 主机文件系统 作为根文件系统驱动程序。
  • 挂载我们在根设备上创建的来宾文件系统。
  • 是的,在读写模式下。
  • 仅使用 64 MB RAM(根据您的计划,您可以使用更少的 RAM,但 64 MB 似乎是最佳数量)。
  • 内核自动启动 /bin/shinit-过程。

运行此命令,您应该得到类似以下内容:

再来一张

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

上面的操作将为我们提供 至少有访客系统,没有类似的东西 /proc 或分配的主机名。 例如,尝试以下命令:

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

要注销来宾,请输入 exit 或按 Control-d。 这将杀死 shell,然后出现内核恐慌:

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

我们得到这个内核恐慌是因为 Linux 内核认为初始化进程总是在运行。 没有它,系统将无法再运行并崩溃。 但由于这是一个用户模式进程,因此结果输出将自身发送到 SIGABRT,这会产生一个输出。

访客网络设置

这就是事情开始出错的地方。 用户模式中的网络 Linux 是有限“用户模式”的整个概念开始崩溃的地方。 毕竟通常在系统层面,网络是有限的 特权 执行模式出于我们所有人都可以理解的原因。

笔记。 per .:您可以阅读有关 UML 中使用网络的不同选项的更多信息 这里.

斯利普之旅

然而,有一种古老且几乎不受支持的工具,称为 滑行,用户模式 ​​Linux 可以通过它与网络交互。 它的工作方式与用户级 TCP/IP 堆栈非常相似,并且不需要任何系统权限即可运行。 这个工具是 1995年发布,并且最新更新日期为 2006年。 斯利普已经很老了。 在没有支持和更新的时间里,编译器已经走得太远了,现在这个工具只能描述为 代码腐烂.

因此,让我们从 Ubuntu 存储库下载 Slirp 并尝试运行它:

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)

天哪。 让我们安装 Slirp 的调试器,看看我们是否能弄清楚这里发生了什么:

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.

错误在我们心中跳动 这条线。 让我们看一下堆栈跟踪,也许有些东西可以帮助我们:

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

在这里我们看到崩溃发生在主循环启动期间,当 slirp 尝试检查超时时。 至此,我不得不放弃调试的尝试。 但让我们看看根据各种方式构建的 Slirp 是否有效。 我直接从网站重新下载了存档 在SourceForge,因为通过命令行从那里拖动一些东西是很痛苦的:

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

在这里,我们看到有关未定义的内置函数的警报,即有关无法链接生成的二进制文件的警报。 从 2006 年至今,gcc 似乎停止生成中间编译文件的内置函数中使用的符号。 我们尝试替换一下关键字 inline 在空评论上并查看结果:

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

没有。 这也行不通。 仍然找不到这些函数的符号。

至此,我放弃了,开始在Github上寻找 Heroku 构建包。 我的理论是一些 Heroku 构建包将包含我需要的二进制文件。 最终,搜索引导我 在这里。 我下载并解压了 uml.tar.gz 并发现以下内容:

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*

这是 slirp 二进制文件! 他工作吗?

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

不会崩溃——所以它应该可以工作! 让我们把这个二进制文件植入到 ~/bin/slirp:

cp slirp ~/bin/slirp

如果包创建者将其删除,我 做了一面镜子.

网络设置

现在让我们在来宾内核上设置网络。 更新启动选项:

linux 
  root=/dev/root 
  rootfstype=hostfs 
  rootflags=$HOME/prefix/uml-demo 
  rw 
  mem=64M 
  eth0=slirp,,$HOME/bin/slirp 
  init=/bin/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

前两条配置命令 /proc и /sys 工作所必需的 ifconfig,设置与 Slirp 通信的网络接口。 团队 route 设置内核路由表以强制所有流量通过 Slirp 隧道发送。 让我们通过 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

它的作品!

注:显然,原始帖子是在带有有线网卡或其他不需要额外驱动程序的配置的台式机上编写的。 在配备 Intel WiFi 8265 的笔记本电脑上,提升网络时出现错误

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

显然,内核无法与网卡驱动程序通信。 不幸的是,尝试将固件编译到内核中并没有解决这个问题。 在发布时,无法在此配置中找到解决方案。 在更简单的配置上(例如,在 Virtualbox 中),接口可以正确启动。

让我们使用以下 shell 脚本自动执行重定向:

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

并将其标记为可执行:

chmod +x init.sh

然后我们将更改内核命令行:

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

让我们重复一遍:

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

网络稳定!

泊坞窗文件

为了方便大家查看,我收集了 Dockerfile,它会自动执行所描述的大部分步骤,并且应该为您提供一个工作配置。 我也有 预配置内核,其中包含帖子中描述的所有内容。 但重要的是要明白,我在这里只概述了最低设置。

我希望这篇文章能够帮助您了解如何构建来宾内核。 结果证明它是某种怪物,但该出版物被认为是在该系列操作系统的现代版本下在 Linux 中构建、安装和配置用户模式的综合指南。 接下来的步骤应该包括安装客户系统中已有的服务和其他软件。 由于 Docker 容器镜像只是公开的 tarball,因此您应该能够通过以下方式提取镜像: docker export,然后确定其在来宾内核文件系统根目录中的安装路径。 好吧,然后执行shell脚本。

特别感谢 Freenode 上 #lobsters 的 Rkeene。 如果没有他调试 Slirp 的帮助,我不可能走到这一步。 我不知道他的 Slackware 系统如何与 slirp 一起正常工作,但我的 Ubuntu 和 Alpine 系统不接受 slirp 以及 Rkeene 向我建议的二进制文件。 但对我来说,至少有一些对我有用的东西就足够了。

来源: habr.com

添加评论