用户模式 Linux

作者:Matthew E. Hoskins

计算机运行程序。从最早的巨型计算机及其硬连线程序,到现代的一次性计算器和台式电脑,我们所有的计算机都运行某种程序。约翰·冯·诺伊曼提出了存储计算机程序的概念,就像存储任何其他数据一样,这使得计算机成为多用途工具,不再局限于单一的硬连线功能。很快,操作系统的概念诞生了,操作系统是一种抽象通用系统级细节(如设备管理和程序执行)的程序。没过多久,一些精明的系统程序员意识到,可以使单个 CPU 看起来同时执行多项任务。这催生了最早的分时和多任务/多用户操作系统。所有现代计算机仍然基于相同的存储程序概念运行。就现代个人计算机而言,在打开电源后,它会运行 BIOS 或固件中的存储程序,最终移交给多阶段引导加载程序,而引导加载程序又会加载 OS 内核。内核执行并建立一个操作环境,在该环境中,内核下执行的程序可以使用系统资源,如 CPU 时间、内存和设备。这一切都是一个漫长的存储程序链。

内核就像任何其他程序一样(尽管是一个相当复杂的程序)。那么,是什么阻止您像执行任何其他程序一样执行内核呢?实际上,根本没有太多阻碍。这就是用户模式 Linux (UML) 的全部内容。

Linux 内核通常以特殊权限运行,因为它需要直接访问您的硬件。用户模式 Linux 提供了一种编译普通 Linux 内核源代码的方法,以便可以将其作为基础 Linux 内核之上的常规二进制程序调用。当您在基础 Linux 内核之上运行内核时,您实际上是在运行一个或多个没有特殊权限的“访客” Linux 系统。(也有一些例外。某些软件必须以 root 身份安装才能使用户模式 Linux 工作。)这些访客 Linux 系统是完整的系统,在(大部分)安全的环境中运行。

如何操作

在本文的其余部分,我将提供一个在您的主机 Linux 机器上启动并运行 UML 系统的指南。然后,我们将探索一些功能并获得一些乐趣。我用于此演示的主机系统是在 Intel P4 上运行的 Fedora Core 4,具有 1GB 内存,但几乎任何系统和发行版都可以工作,前提是它运行的是最新的 2.6 内核并且至少有 256MB 内存。

访客 UML 系统就像任何其他 Linux 系统一样。它是 Linux 内核和构成操作系统的少量程序、库和文件的组合。这些以内核和文件系统镜像两部分提供。文件系统镜像是一个虚拟磁盘分区。这将是我们将要挂载并用作 UML 系统根文件系统的东西。您可以选择自己创建这两部分,也可以从网上下载流行的发行版的现成版本。为了立即获得满足感,我们采取现成路线;请查看 UML Wiki 以获取有关构建您自己的文件系统的更多信息(请参阅在线资源)。

内核和根文件系统镜像有许多版本和发行版。Red Hat、Fedora Core、Debian 和许多专用发行版的镜像可用。我在此演示中使用 Debian 3.1。

COW 是您的朋友

用户模式 Linux 有一个非常特殊的功能,称为写时复制文件或 COW。写时复制是一种常见的计算机科学概念,它定义了一种机制,使数据块保持只读,但允许通过将更改的数据块写入备用位置来进行修改。您下载的文件系统镜像始终保持只读。在我们运行的 UML 系统中对文件系统所做的更改将写入 COW 文件。这允许我们从同一个只读根文件系统镜像启动多个 UML 系统,前提是它们都具有单独的 COW 文件。此外,如果我们的 UML 系统损坏,我们只需清除 COW 文件即可重新开始。COW 文件被称为稀疏文件;即使在查看文件大小时它们看起来可能很大,但实际上只有非空数据才分配了磁盘空间。

收集组件

让我们首先在一个新创建的空目录中收集组件。确保有足够的磁盘空间可用;毕竟,我们需要容纳整个 Debian 安装。三个千兆字节应该足以满足基本系统。从 uml.nagafix.co.uk 下载 Debian-3.1-x86-root_fs.bz2 文件。然后,从 www.user-mode-linux.org/~blaisorblade/binaries 获取 2.6.14.3-bs3 UML 内核。最后,从 user-mode-linux.sourceforge.net/dl-sf.html 获取 UML 实用程序源代码。如果这些文件中的任何一个丢失,您可以在本文的资源中找到备用下载位置。

下面是一个脚本,用于收集所有部件并编译仅以源代码形式提供的 UML 实用程序。如果您对设置网络不感兴趣,可以省略 uml_utilities tarball 并跳过编译。以下所有步骤都可以作为普通用户执行,除了 UML 实用程序的安装,这需要 su 到 root

mkdir /tmp/UML-Demo
cd /tmp/UML-Demo
wget http://uml.nagafix.co.uk/Debian-3.1/
-->Debian-3.1-x86-root_fs.bz2
bunzip2 Debian-3.1-x86-root_fs.bz2
wget http://www.user-mode-linux.org/~blaisorblade/binaries/
-->2.6.14.3-bs3/uml-release-2.6.14.3-bs3.tar.bz2
tar -xvjf uml-release-2.6.14.3-bs3.tar.bz2
cp um32-2.6.14-release-mod/vmlinux-2.6.14.3-bs3  .
wget http://mirror.usermodelinux.org/uml/
-->uml_utilities_20040406.tar.bz2
tar -xvjf uml_utilities_20040406.tar.bz2
cd tools
make all
su root
make install DESTDIR=/
exit
cd ..

现在我们已经收集了所有部件,并准备好开始运行了。所有 Linux 系统都有内核命令行。在大多数系统中,此命令行由引导加载程序(GRUB、LILO 等)调用。在我们的例子中,我们自己编写命令行来指示内核使用 Debian 根文件系统镜像和一个名为 Debian1.cow 的 COW 文件作为其根 (/) 文件系统。您当前的终端成为访客 UML 系统的控制台

cd /tmp/UML-Demo
./vmlinux-2.6.14.3-bs3
-->ubd0=Debian1.cow,Debian-3.1-x86-root_fs root=/dev/ubda

在该命令执行后,我们看到熟悉的 Linux 内核启动消息,最后是一个 Debian 系统等待某人登录。我们可以以 root 身份登录(没有密码)并像清单 1 中所示那样四处查看。

清单 1. Debian 3.1 UML 访客启动演示

Debian GNU/Linux testing/unstable (none) tty0

(none) login: root  <ENTER>
Linux (none) 2.6.14.3-bs3 #7 Fri Dec 16 17:47:00 CET 2005 i686 GNU/Linux

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

(none):~# ps -ef <ENTER>
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 22:56 ?        00:00:00 init [2]
root         2     1  0 22:56 ?        00:00:00 [ksoftirqd/0]
root         3     1  0 22:56 ?        00:00:00 [watchdog/0]
root         4     1  0 22:56 ?        00:00:00 [events/0]
root         5     1  0 22:56 ?        00:00:00 [khelper]
root         6     1  0 22:56 ?        00:00:00 [kthread]
root         7     6  0 22:56 ?        00:00:00 [kblockd/0]
root         8     6  0 22:56 ?        00:00:00 [pdflush]
root         9     6  0 22:56 ?        00:00:00 [pdflush]
root        11     6  0 22:56 ?        00:00:00 [aio/0]
root        10     1  0 22:56 ?        00:00:00 [kswapd0]
root        12     1  0 22:56 ?        00:00:00 [kjournald]
root       299     1  0 22:56 ?        00:00:00 /sbin/syslogd
root       305     1  0 22:56 ?        00:00:00 /sbin/klogd
root       343     1  0 22:56 ?        00:00:00 /usr/sbin/exim4 -bd -q30m
root       348     1  0 22:56 ?        00:00:00 /usr/sbin/inetd
daemon     361     1  0 22:56 ?        00:00:00 /usr/sbin/atd
root       364     1  0 22:56 ?        00:00:00 /usr/sbin/cron
root       379     1  0 22:56 tty0     00:00:00 /bin/login --
root       380   379  0 22:56 tty0     00:00:00 -bash
root       384   380  0 22:57 tty0     00:00:00 ps -ef

(none):~# df -h <ENTER>
Filesystem            Size  Used Avail Use% Mounted on
/dev/ubda            1008M  264M  694M  28% /
tmpfs                 768M     0  768M   0% /tmp
tmpfs                  14M     0   14M   0% /dev/shm

(none):~# halt <ENTER>

Broadcast message from root (tty0) (Sun Jan 15 22:57:17 2006):

The system is going down for system halt NOW!

很酷,对吧?这是您自己的 Debian 3.1 沙箱,您可以随意创建或破坏。您可以忽略有关 hwclock 和 tty0 的警告,因为这些对于大多数 UML 系统来说是正常的,因为 UML 内核不支持某些硬件功能。此时,您可以随意将 root 密码更改为您喜欢的任何密码。

接下来,让我们设置网络。您需要两个空闲的静态 IP 地址,一个用于我们将要使用我们之前编译的 UML 实用程序创建的隧道的每一侧。我在这里使用 192.168.1.100 和 192.168.1.101。使用适合您本地网络的任何地址。要开始,请再次启动您的 Debian UML,并使用以下命令

cd /tmp/UML-Demo
./vmlinux-2.6.14.3-bs3  ubd0=Debian1.cow,Debian-3.1-x86-root_fs
-->root=/dev/ubda eth0=tuntap,,,192.168.1.100

在我们的 Debian 访客系统启动后,再次以 root 身份登录并按如下方式修改网络配置。

编辑 /etc/network/interfaces 文件,使其仅包含以下行

auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
 address 192.168.1.101
 netmask 255.255.255.0
 gateway 192.168.1.1

在 /etc/hostname 文件中输入您选择的主机名,最后,将您的解析器设置从主机系统上的 /etc/resolv.conf 复制到访客 Debian 系统。停止访客系统并重新启动。

在访客系统启动后,您将能够从网络上的任何位置 ping 它。我建议对您新联网的 Debian 系统做几件事。首先,安装 OpenSSH,然后将所有已安装的软件包更新到最新版本。为此,请执行以下命令并在询问时回答简单的问题

apt-get install openssh-server
apt-get upgrade

此时的可能性是无限的。任何网络服务或应用程序都可以在此访客 Debian 安装下运行。您可以使用 UML 在一个盒子上跨多个内核版本和 Linux 发行版测试应用程序。您可以将文件系统镜像和 COW 文件放在 USB 拇指驱动器上,从而在您使用的所有计算机上为您提供稳定的开发环境。用户模式 Linux 使测试系统更改变得容易且无痛,否则这些更改可能会使系统无法启动。

乐趣——如同破坏!

好吧,您知道您一直想这样做。现在,您的机会来了。启动一个新的独立访客 Debian UML 系统,并执行rm -rf /。如果您像我一样,当您甚至考虑输入该命令时,您的手指会开始蜷缩起来。首先,使用以下命令启动新的 Debian 访客(请注意我们正在使用不同的 COW 文件,因为我们不想干扰我们之前创建的良好联网设置)

cd /tmp/UML-Demo
./vmlinux-2.6.14.3-bs3  ubd0=DangerDanger.cow,Debian-3.1-x86-root_fs
-->root=/dev/ubda

在我们注定要失败的朋友启动后,让他们尝尝苦头。确保您仔细(甚至三重)检查您是否仍在访客 Debian 系统中输入(清单 2)!

清单 2. 如果您只是在测试,破坏也可能很有趣。

Debian GNU/Linux testing/unstable (none) tty0

(none) login: root
Linux (none) 2.6.14.3-bs3 #7 Fri Dec 16 17:47:00 CET 2005 i686 GNU/Linux

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

(none):~#  rm -rf /
rm: cannot remove `//proc/meminfo': Operation not permitted
rm: cannot remove `//proc/uptime': Operation not permitted
(... Many warnings about read-only filesystems omitted ...)
rm: cannot remove `//proc/loadavg': Operation not permitted
rm: `//proc/self' changed dev/ino: Operation not permitted
(none):~# df -k
-bash: df: command not found
(none):~# ps -ef
-bash: ps: command not found
(none):~# halt
-bash: /sbin/halt: No such file or directory
(none):~#

此时它已经非常糟糕了。事实上,您甚至无法运行halt,因为 halt 程序本身已经消失了。从另一个命令窗口,使用以下命令杀死系统

killall -9 vmlinux-2.6.14.3-bs3

然后,看看当您尝试使用相同的命令再次启动它时会发生什么(清单 3)。

清单 3. 一个病入膏肓的 Debian UML 访客

(... boot messages omitted ...)
EXT3-fs: INFO: recovery required on readonly filesystem.
EXT3-fs: write access will be enabled during recovery.
kjournald starting.  Commit interval 5 seconds
EXT3-fs: ubda: orphan cleanup on readonly fs
EXT3-fs: ubda: 66 orphan inodes deleted
EXT3-fs: recovery complete.
EXT3-fs: mounted filesystem with ordered data mode.
VFS: Mounted root (ext3 filesystem) readonly.
Warning: unable to open an initial console.
Kernel panic - not syncing: No init found. Try passing init= option to kernel.
EIP: 0073:[<a01c6691>] CPU: 0 Not tainted ESP: 007b:b7f3afac EFLAGS: 00000282
Not tainted
EAX: 00000000 EBX: 000012eb ECX: 00000013 EDX: 000012eb
ESI: 000012e8 EDI: 00000000 EBP: b7f3afb8 DS: 007b ES: 007b
a10afb80:  [<a0032d2a>] show_regs+0x21a/0x230
a10afbb0:  [<a0016c8c>] panic_exit+0x2c/0x50
a10afbc0:  [<a004a275>] notifier_call_chain+0x25/0x40
a10afbe0:  [<a0037501>] panic+0x71/0x100
a10afc00:  [<a000e2c0>] init+0x100/0x170
a10afc20:  [<a002bf59>] run_kernel_thread+0x39/0x50
a10afce0:  [<a001c3d4>] new_thread_handler+0xc4/0x120
a10afd20:  [<b7f3b420>] 0xb7f3b420

那一定很痛苦。因此,作为一个教训,不要在真实系统上这样做。但是由于这是一个带有 COW 文件的 UML 访客,您可以简单地删除 DangerDanger.cow 文件,并且此访客系统将启动回其初始状态。

关于 COW 文件的更多信息

UML 实用程序中包含的实用程序 uml_moo 将读取文件系统镜像和关联的 COW 文件,并创建一个新的合并文件系统镜像。这允许您将存储在 COW 文件中的更改合并到新的主文件系统镜像中。当您以您想要的方式设置工作访客文件系统镜像时,这使得克隆它们变得容易。

结论

用户模式 Linux 玩起来很有趣,但它也有一些实际用途。您可以使用它来测试未知或不受信任的应用程序,同时限制对正在运行的主机系统的可能损害。您可以通过一次启动多个访客来创建 UML 虚拟网络。这使您可以花费很少的时间和精力创建一个盒中测试实验室环境,因此您可以尝试所有那些您害怕在真实系统上尝试的“愚蠢的 Linux 技巧”!

本文的代码可在 ftp.linuxjournal.com/pub/lj/listings/issue145/8803.tgz 获取。

本文的资源: /article/8883

Matthew E. Hoskins 是新泽西理工学院的高级 UNIX 系统管理员,他在那里维护着许多公司管理系统。他喜欢尝试让截然不同的系统和软件协同工作,通常使用薄薄的一层 Perl(在本地称为“MattGlue”)。不摆弄系统时,他经常可以在厨房里摆弄。Matt 是专业记者协会的成员。他渴望听到您的反馈,可以通过 matt@njit.edu 与他联系。

加载 Disqus 评论