Suppose we have our Linux system setup with an almost-full disk encryption, with only the /boot
partition unencrypted. Assuming we achieved encryption by using a LUKS container, we need the appropriate software to unlock it at boot. This software, however, is part of the encrypted system. Since the Linux 2.6 series, the solution to this, and other similar problems, is called initramfs (Initial ramfs). In this article we see how an initramfs is composed and how to extract or list its content.
In this tutorial you will learn:
- What is an initramfs
- How to extract/inspect an initramfs with basic tools
- How to list the content of an initramfs with lsinitrd/lsinitramfs
- How to extract an initramfs content using unmkinitramfs on Debian
Software requirements and conventions used
Category | Requirements, Conventions or Software Version Used |
---|---|
System | Distribution-independent |
Software | All the software mentioned in this tutorial should be already installed |
Other | None |
Conventions | # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command$ – requires given linux-commands to be executed as a regular non-privileged user |
What is an initramfs?
We saw the “why” of an initramfs: make required software and kernel modules available at an early boot stage. But what is an initramfs, and where it is stored? An initramfs is basically a compressed cpio archive. Normally it is stored in the /boot
partition, together with the kernel image it is associated with, and named after (e.g initramfs-5.14.14-300.fc35.x86_64.img
). In certain situations it would be useful to know how to check its content and/or extract it. Let’s see how to do it.
How to inspect and extract an initramfs with basic tools
What does an initramfs archive contain? Well, we know how to create and uncompress a cpio archive, so let’s try to do it, and see if we can inspect the initramfs content:
$ 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
The command above is prefixed with sudo
just because the initramfs file I am working with, for the sake of this tutorial, on Fedora, is owned by root
and has 600
as permissions set. Once the command is executed, the following files and directories are created in the working directory:
. ├── early_cpio └── kernel └── x86 └── microcode └── GenuineIntel.bin 3 directories, 2 files
All there is, is basically intel kernel microcode. Is that all there is inside the initramfs? Actually, it is not. If we observe the output of the command we ran in the previous example, we can see cpio stopped after 10 blocks of 512 Bytes (5120 Bytes); if we check the total size of the archive, however, we can see it is bigger than that:
$ 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
From the output of ls
we can see that the total size of the initramfs is of 34594545
Bytes. What happened to the rest of the initramfs content? Sometimes, as in this case, an initramfs can be actually composed by two parts or segments:
- An initial, very small, uncompressed cpio archive
- A compressed cpio archive which contains the main content
In the previous example what we extracted was the content of the first, small cpio archive. How can we extract the content of the second, compressed archive which contains the actual filesystem mounted during the early stages of boot? First of all we should isolate it.
In this case, we know that the first cpio archive is composed by 10 blocks of 512 Bytes, therefore we can use dd
to start reading from that point onward, and save the result to a file which we will call main_archive
. We can achieve that using the skip
option of dd
, which, as its name suggests, let us skip the given number of blocks from input (by default each block is considered to be 512 Bytes). We run:
$ sudo dd if=/boot/initramfs-5.14.14-300.fc35.x86_64.img skip=10 of=main_archive
Once dd
finishes running, we will find the main_archive
file created in our working directory. Now, what we have to do, is to find what type of compression was used for it. We can do it using the file
utility, which in this case returns the following result:
$ file main_archive main_archive: gzip compressed data, max compression, from Unix, original size modulo 2^32 74156544
From the output of the command we can clearly see that the file was compressed using gzip. Now we know everything we need to uncompress and extract the cpio archive. We can do everything with just one command and some shell piping. Before we do it, let’s create a directory called initramfs_filesystem
and extract all the content of the compressed archive inside of it:
$ mkdir initramfs_filesystem $ zcat main_archive | cpio -ivD initramfs_filesystem
To extract the archive into a directory other than our working one, as you can notice, we used the -D
option of the cpio
command, and passed the path of the directory as argument. Once the extraction takes place, if we take a look at the extracted initramfs content, we can see it resembles the real root filesystem:
$ ls initramfs_filesystem bin dev etc init lib lib64 proc root run sbin shutdown sys sysroot tmp usr var
What if we just want to obtain a list of the files and directories contained in the initramfs without actually extracting them? Very simple. We can run
cpio
with the -t
option:
$ zcat main_archive | cpio -t initramfs_filesystem
The command above would produce an output similar to the one below (truncated):
. 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 [...]
Inspecting or extracting the initramfs the way we did it above can be a little tedious; luckily there are some specific utilities designed to achieve the same results. Let’s take a look at them.
Inspecting initramfs content with lsinitrd/lsinitramfs
In the previous section we saw how to extract the content of an initramfs and how to list its content with simple tools like gzip, cpio and dd. To ease those processes, a series of tools are available, depending on the distribution we are using.
To list the content of an initramfs, for example, we can use the lsinitrd
and lsinitramfs
scripts. The former is used on Fedora and the Red Hat family of distributions, the latter on Debian and Debian-based distributions. The lsinitrd
is a little bit misleading, since an initrd
was basically what was used before initramfs was adopted, but so it is. The use of the script is really simple. We invoke it and pass it the path of the initramfs image we want to inspect as argument:
$ sudo lsinitrd /boot/initramfs-5.14.14-300.fc35.x86_64.img
The script produces an output which includes both the content of the “early”, uncompressed cpio archive, the dracut modules used to generate the initramfs (dracut is the program used to create the initramfs on Fedora), and the content of the main, compressed, cpio archive (output is truncated for obvious reasons):
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 [...]
The
lsinitramfs
script works basically the same way. It is part of the “initramfs-tools-core” package on Debian, so there is no need to install it. By default it just outputs the list of the files in the initramfs; if the -l
option is used, however, files and directories permissions are also reported:
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 [...]
Unpacking the initramfs with umkinitramfs (Debian)
To extract the content of an initramfs on Debian and Debian-based distributions we can use the unmkinitramfs
script, which is intelligent enough to detect if the initramfs is composed by multiple cpio
archives, like the one we saw in the first part of this tutorial. The script takes the path of the initramfs file to extract as the first argument, and the path of the directory where the content should be extracted as the second one. To extract the /boot/initrd.img-5.10.0-8-amd64
file into the current working directory, for example, we would run:
$ unmkinitramfs /boot/initrd.img-5.10.0-8-amd64 .
Conclusions
In this tutorial we learned what is an initramfs and what is its purpose on modern Linux distributions. We saw how sometimes it is composed by two cpio archives: the first, uncompressed and really small, which usually contains cpu microcode, and the second, compressed, which contains the rest of the content (software, kernel modules etc…). We saw how to extract an initramfs using basic tools and dedicated scripts, and how to list its content.