How to uncompress and list an initramfs content on Linux

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
How to uncompress and list an initramfs content on Linux
How to uncompress and list an initramfs content on Linux

Software requirements and conventions used

Software Requirements and Linux Command Line Conventions
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:

  1. An initial, very small, uncompressed cpio archive
  2. 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.



Comments and Discussions
Linux Forum