How to modify initrd initial ramdisk of Ubuntu 18.10 Cosmic Cuttlefish

I tried to extract the initrd casper/initrd of Ubuntu 18.10 and got an unexpected result. I did not see the root filesystem and files, but just a folder named kernel.

What I have done

Firstly I tried to know if I should decompress the initrd or just extract the archive directly, so I issued this command:

$ file initrd
initrd: ASCII cpio archive (SVR4 with no CRC)

What I got

According to the output, it should be an cpio archive and I used cpio to extract the archive.

$ cpio -id < initrd 
56 blocks
$ ls
initrd  kernel

If I went to have a look of the directory kernel, I got

kernel/
└── x86
    └── microcode
        └── AuthenticAMD.bin

2 directories, 1 file

What I expect

There should be files and folders like init, etc, usr, and so on. For example:

bin  conf  cryptroot  etc  init  lib  lib64  run  sbin  scripts  usr  var

I figure out the initrd of Ubuntu 18.10 is archived in a different way from the previous releases. In the previous releases the initrd is usually a lzma (or gzip for much earlier releases) compressed cpio archive. The initrd of 18.10 is an archive composed of several binary files in different formats.

To dive into the archive, you may need binwalk (or other similar tools. You could get binwalk by sudo apt install binwalk). Once you get binwalk, issue the command binwalk initrd:

$ binwalk initrd

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             ASCII cpio archive (SVR4 with no CRC), file name: ".", file name length: "0x00000002", file size: "0x00000000"
112           0x70            ASCII cpio archive (SVR4 with no CRC), file name: "kernel", file name length: "0x00000007", file size: "0x00000000"
232           0xE8            ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86", file name length: "0x0000000B", file size: "0x00000000"
356           0x164           ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86/microcode", file name length: "0x00000015", file size: "0x00000000"
488           0x1E8           ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86/microcode/AuthenticAMD.bin", file name length: "0x00000026", file size: "0x00006B2A"
28072         0x6DA8          ASCII cpio archive (SVR4 with no CRC), file name: "TRAILER!!!", file name length: "0x0000000B", file size: "0x00000000"
28672         0x7000          ASCII cpio archive (SVR4 with no CRC), file name: "kernel", file name length: "0x00000007", file size: "0x00000000"
28792         0x7078          ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86", file name length: "0x0000000B", file size: "0x00000000"
28916         0x70F4          ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86/microcode", file name length: "0x00000015", file size: "0x00000000"
29048         0x7178          ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86/microcode/.enuineIntel.align.0123456789abc", file name length: "0x00000036", file size: "0x00000000"
29212         0x721C          ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86/microcode/GenuineIntel.bin", file name length: "0x00000026", file size: "0x00180C00"
1605296       0x187EB0        ASCII cpio archive (SVR4 with no CRC), file name: "TRAILER!!!", file name length: "0x0000000B", file size: "0x00000000"
1605632       0x188000        LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: -1 bytes

You could see there are two microcode binary files and a LZMA compressed data file. The latter is what we want: the lzma compressed initrd.

Let's get the lzma compressed initrd by

dd if=initrd bs=1605632 skip=1 | unlzma -c | cpio -id

You will get the expected files mentioned in the questions. Edit the files you want to change. Use the following commands to repack the binary files:

find | cpio -H newc -o | lzma -c > initrd.partial.lz

And finally concatenate the microcode files and your new initrd (initrd.partial.lz) by

dd if=initrd of=initrd.microcode bs=512 count=3136
cat initrd.microcode initrd.partial.lz > initrd.new

Now rename initrd.new to be initrd and put it back to casper/initrd. You could boot your live system with your new initrd.

My answer is inspired by this post https://unix.stackexchange.com/questions/163346/why-is-it-that-my-initrd-only-has-one-directory-namely-kernel