An inconsistent behaviour if using built-in initramfs and damaged external one

From: Marcin Szewczyk
Date: Mon Jun 12 2017 - 17:04:15 EST


Hi,

during my experiments with initramfs I have noticed there is something
that looks like a bug in the 9-year old code[1] of the clean_rootfs()
function in init/initramfs.c. An inconsistent behaviour appears when
I have both the built-in initramfs and the one in the external file but
the latter is somehow damaged (e.g. wrong padding).

I wanted to leverage the functionality described in the ramfs
documentation[2]: "It can also be used to supplement the kernel's
built-in initramfs image. The files in the external archive will
overwrite any conflicting files in the built-in initramfs archive."

Clearly there is an intention in the code to do cleanup and return to
the built-in initramfs if the external initramfs was only partially
unpacked:

#v+
char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
if (err)
panic(err); /* Failed to decompress INTERNAL initramfs */
if (initrd_start) {
#ifdef CONFIG_BLK_DEV_RAM
int fd;
printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n");
err = unpack_to_rootfs((char *)initrd_start,
initrd_end - initrd_start);
if (!err) {
free_initrd();
goto done;
} else {
clean_rootfs();
unpack_to_rootfs(__initramfs_start, __initramfs_size);
}
printk(KERN_INFO "rootfs image is not initramfs (%s)"
"; looks like an initrd\n", err);
#v-

But inside the clean_rootfs() function non-empty directories are not
going to be removed:
#v+
ret = sys_newlstat(dirp->d_name, &st);
WARN_ON_ONCE(ret);
if (!ret) {
if (S_ISDIR(st.st_mode))
sys_rmdir(dirp->d_name);
else
sys_unlink(dirp->d_name);
}
num -= dirp->d_reclen;
#v-
Call to sys_rmdir() is assumed to be always successful.

I am aware that this is not a serious bug (if a bug at all) but I would
like this note to last in the mailing list archive because debugging it
took me some time and possibly some could stumble upon it as well.

Because I missed the "rootfs image is not initramfs [â] looks like an
initrd" message in the dmesg at first I thought that files are not
overwritten with their external versions at all. I wondered how it was
possible to have the following effects:

- if no /etc/shadow in the built-in image, /etc/shadow in the external
though damaged image â password from the *external* image works,

- if /etc/shadow in the built-in image, /etc/shadow in the external
though damaged image â password from the *built-in* image works,

- files in / from the external though damaged initramfs disappear, but
files in /etc survive.



[1]: https://github.com/torvalds/linux/commit/df52092f3c97788592ef72501a43fb7ac6a3cfe0
[2]: https://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt

--
Marcin Szewczyk
http://wodny.org