如何在 Linux 上解压缩并列出 initramfs 内容
假设我们的 Linux 系统设置几乎是全盘加密,只有 /boot
分区未加密。假设我们通过使用 LUKS 容器实现了加密,我们需要适当的软件在启动时解锁它。然而,该软件是加密系统的一部分。从Linux 2.6系列开始,这个问题以及其他类似问题的解决方案被称为initramfs(Initial ramfs)。在本文中,我们将了解 initramfs 的组成方式以及如何提取或列出其内容。
在本教程中您将学习:
什么是 initramfs
如何使用基本工具提取/检查 initramfs
如何使用 lsinitrd/lsinitramfs 列出 initramfs 的内容
如何在 Debian 上使用 unmkinitramfs 提取 initramfs 内容
使用的软件要求和约定
什么是 initramfs?
我们看到了 initramfs 的“原因”:在早期启动阶段提供所需的软件和内核模块。但什么是 initramfs,它存储在哪里? initramfs 基本上是一个压缩的 cpio 存档。通常它与与之关联的内核映像一起存储在 /boot
分区中,并以它的名称命名(例如 initramfs-5.14.14-300.fc35.x86_64.img
)。在某些情况下,了解如何检查其内容和/或提取它会很有用。让我们看看如何做。
如何使用基本工具检查和提取 initramfs
initramfs 存档包含什么?好吧,我们知道如何创建和解压缩 cpio 存档,所以让我们尝试一下,看看是否可以检查 initramfs 内容:
$ sudo cpio -ivF /boot/initramfs-5.14.14-300.fc35.x86_64.img
.
early_cpio
kernel
kernel/x86
kernel/x86/microcode
kernel/x86/microcode/GenuineIntel.bin
10 blocks
上面的命令以 sudo
为前缀,只是因为为了本教程的目的,我在 Fedora 上使用的 initramfs 文件由 root
所有并具有 600
作为权限设置。执行该命令后,将在工作目录中创建以下文件和目录:
.
├── early_cpio
└── kernel
└── x86
└── microcode
└── GenuineIntel.bin
3 directories, 2 files
所有这些基本上都是英特尔内核微代码。这就是 initramfs 中的全部内容吗?事实上,事实并非如此。如果我们观察上一个示例中运行的命令的输出,我们可以看到 cpio 在 512 字节(5120 字节)的 10 个块之后停止;然而,如果我们检查存档的总大小,我们可以看到它比这个还要大:
$ sudo ls -l /boot/initramfs-5.14.14-300.fc35.x86_64.img
-rw-------. 1 root root 34594545 Nov 25 15:38 /boot/initramfs-5.14.14-300.fc35.x86_64.img
从ls
的输出中我们可以看到initramfs的总大小为34594545
字节。 initramfs 的其余内容发生了什么?有时,就像在本例中一样,initramfs 实际上可以由两个部分或段组成:
一个初始的、非常小的、未压缩的 cpio 存档
包含主要内容的压缩 cpio 存档
在前面的示例中,我们提取的是第一个小型 cpio 存档的内容。我们如何提取第二个压缩存档的内容,其中包含在启动早期阶段安装的实际文件系统?首先我们应该隔离它。
在这种情况下,我们知道第一个 cpio 存档由 10 个 512 字节的块组成,因此我们可以使用 dd
从该点开始读取,并保存结果保存到我们称为 main_archive
的文件中。我们可以使用 dd
的 skip
选项来实现这一点,顾名思义,让我们从输入中跳过给定数量的块(默认情况下,每个块都被认为是为 512 字节)。我们跑:
$ sudo dd if=/boot/initramfs-5.14.14-300.fc35.x86_64.img skip=10 of=main_archive
一旦dd
运行完成,我们将在工作目录中找到创建的main_archive
文件。现在,我们要做的就是找出它使用的压缩类型。我们可以使用 file
实用程序来完成此操作,在本例中它返回以下结果:
$ file main_archive
main_archive: gzip compressed data, max compression, from Unix, original size modulo 2^32 74156544
从命令的输出中我们可以清楚地看到该文件是使用 gzip 压缩的。现在我们知道了解压缩和提取 cpio 存档所需的一切。我们只需一个命令和一些 shell 管道就可以完成所有事情。在此之前,我们先创建一个名为 initramfs_filesystem
的目录,并提取其中压缩存档的所有内容:
$ mkdir initramfs_filesystem
$ zcat main_archive | cpio -ivD initramfs_filesystem
如您所见,为了将存档解压到工作目录以外的目录中,我们使用了 cpio 命令的 -D 选项,并传递了目录的路径作为论证。提取完成后,如果我们查看提取的 initramfs 内容,我们可以看到它类似于真正的根文件系统:
$ ls initramfs_filesystem
bin dev etc init lib lib64 proc root run sbin shutdown sys sysroot tmp usr var
如果我们只想获取 initramfs 中包含的文件和目录的列表而不实际提取它们怎么办?很简单。我们可以使用 -t
选项运行 cpio
:
$ zcat main_archive | cpio -t initramfs_filesystem
上面的命令将产生类似于下面的输出(截断):
.
bin
dev
dev/console
dev/kmsg
dev/null
dev/random
dev/urandom
etc
etc/authselect
etc/authselect/nsswitch.conf
etc/block_uuid.map
etc/cmdline.d
etc/conf.d
etc/conf.d/systemd.conf
etc/crypttab
[...]
按照我们上面的方式检查或提取 initramfs 可能有点乏味;幸运的是,有一些特定的实用程序旨在实现相同的结果。让我们来看看它们。
使用 lsinitrd/lsinitramfs 检查 initramfs 内容
在上一节中,我们了解了如何提取 initramfs 的内容以及如何使用 gzip、cpio 和 dd 等简单工具列出其内容。为了简化这些过程,可以使用一系列工具,具体取决于我们使用的发行版。
例如,要列出 initramfs 的内容,我们可以使用 lsinitrd 和 lsinitramfs 脚本。前者用于 Fedora 和 Red Hat 系列发行版,后者用于 Debian 和基于 Debian 的发行版。 lsinitrd
有点误导,因为 initrd
基本上是在采用 initramfs 之前使用的,但事实确实如此。该脚本的使用非常简单。我们调用它并将我们想要检查的 initramfs 映像的路径作为参数传递给它:
$ sudo lsinitrd /boot/initramfs-5.14.14-300.fc35.x86_64.img
该脚本生成一个输出,其中包括“早期”未压缩的 cpio 存档的内容、用于生成 initramfs 的 dracut 模块(dracut 是用于在 Fedora 上创建 initramfs 的程序)以及主压缩文件的内容, cpio 存档(由于明显的原因输出被截断):
Early CPIO image
========================================================================
drwxr-xr-x 3 root root 0 Oct 28 21:55 .
-rw-r--r-- 1 root root 2 Oct 28 21:55 early_cpio
drwxr-xr-x 3 root root 0 Oct 28 21:55 kernel
drwxr-xr-x 3 root root 0 Oct 28 21:55 kernel/x86
drwxr-xr-x 2 root root 0 Oct 28 21:55 kernel/x86/microcode
-rw-r--r-- 1 root root 4096 Oct 28 21:55 kernel/x86/microcode/GenuineIntel.bin
========================================================================
Version: dracut-055-6.fc35
Arguments: --kver '5.14.14-300.fc35.x86_64' -f
dracut modules:
systemd
systemd-initrd
systemd-sysusers
nss-softokn
dbus-broker
dbus
i18n
network-manager
network
ifcfg
drm
plymouth
crypt
dm
kernel-modules
kernel-modules-extra
kernel-network-modules
lvm
rootfs-block
terminfo
udev-rules
dracut-systemd
usrmount
base
fs-lib
shutdown
========================================================================
drwxr-xr-x 12 root root 0 Oct 28 21:55 .
crw-r--r-- 1 root root 5, 1 Oct 28 21:55 dev/console
crw-r--r-- 1 root root 1, 11 Oct 28 21:55 dev/kmsg
crw-r--r-- 1 root root 1, 3 Oct 28 21:55 dev/null
crw-r--r-- 1 root root 1, 8 Oct 28 21:55 dev/random
crw-r--r-- 1 root root 1, 9 Oct 28 21:55 dev/urandom
lrwxrwxrwx 1 root root 7 Oct 28 21:55 bin -> usr/bin
drwxr-xr-x 2 root root 0 Oct 28 21:55 dev
drwxr-xr-x 13 root root 0 Oct 28 21:55 etc
drwxr-xr-x 2 root root 0 Oct 28 21:55 etc/authselect
-rw-r--r-- 1 root root 2999 Oct 28 21:55 etc/authselect/nsswitch.conf
[...]
lsinitramfs
脚本的工作方式基本相同。它是 Debian 上“initramfs-tools-core”软件包的一部分,因此无需安装它。默认情况下,它只输出 initramfs 中的文件列表;但是,如果使用 -l
选项,还会报告文件和目录权限:
lsinitramfs -l /boot/initrd.img-5.10.0-8-amd64
drwxr-xr-x 7 root root 0 Dec 1 10:56 .
lrwxrwxrwx 1 root root 7 Dec 1 10:56 bin -> usr/bin
drwxr-xr-x 3 root root 0 Dec 1 10:56 conf
-rw-r--r-- 1 root root 16 Dec 1 10:56 conf/arch.conf
drwxr-xr-x 2 root root 0 Dec 1 10:56 conf/conf.d
-rw-r--r-- 1 root root 49 Dec 1 10:50 conf/conf.d/resume
-rw-r--r-- 1 root root 1365 Jan 14 2021 conf/initramfs.conf
[...]
使用 umkinitramfs 解压 initramfs (Debian)
要在 Debian 和基于 Debian 的发行版上提取 initramfs 的内容,我们可以使用 unmkinitramfs
脚本,该脚本足够智能,可以检测 initramfs 是否由多个 cpio
存档组成,就像我们在本教程第一部分中看到的那样。该脚本将要提取的 initramfs 文件的路径作为第一个参数,将要提取内容的目录的路径作为第二个参数。例如,要将 /boot/initrd.img-5.10.0-8-amd64
文件提取到当前工作目录中,我们将运行:
$ unmkinitramfs /boot/initrd.img-5.10.0-8-amd64 .
结论
在本教程中,我们了解了什么是 initramfs 以及它在现代 Linux 发行版上的用途。我们看到有时它是由两个 cpio 存档组成:第一个是未压缩的,非常小,通常包含 cpu 微代码,第二个是压缩的,其中包含其余内容(软件、内核模块等)。我们了解了如何使用基本工具和专用脚本提取 initramfs,以及如何列出其内容。