From 0b2d5c2bb3f198acda0b340ec0e5be4ae75b7914 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Tue, 6 Aug 2024 11:21:28 -0500 Subject: [PATCH] Fix BUILTIN=1 mkroot builds for vanilla (unpatched) kernels. When Linux is built with a statically linked initramfs that doesn't contain a /dev/console node, the kernel will fail to open stdin/stdout/stderr and then launches init with no open filehandles. In which case the first file descriptor PID 1 opens will be zero (the lowest available number), and the "<>/dev/console" redirect logic would open /dev/console to a temporary fd, dup2() the temporary fd to 0, and close the temporary fd... which was zero. It didn't notice that the fd we dup() to and the one we immediately close after were the same, and thus the mkroot init script that tried to mount devtmpfs and exec redirect stdin/out/err didn't work right. The Linux's kernel's behavior for static and external initramfs differs because the kernel build notices when CONFIG_INITRAMFS_SOURCE is empty and links in init/noinitramfs.c with a function default_rootfs() that does init_mkdir("/dev") and init_mknod("/dev/console") in the otherwise empty rootfs mount, but ONLY does this when the config doesn't statically link in an initramfs. The "builtin" initramfs is handled (the linked-in cpio.gz extracted or default_rootf() called) before before loading any external initramfs.cpio.gz image supplied by the bootloader (including qemu's -initrd option), which then extracts the exteranl cpio.gz archive into the existing filesystem (meaning it doesn't erase the /dev/console that's already there from default_rootfs()), so in that case PID 1 gets launched with fds 0, 1, and 2 open and pointing to /dev/console. A statically linked initramfs created by pointing the kernel's CONFIG_INITRAMFS_SOURCE at a chroot directory has the downside that /dev/console requires root access to create. You used to be able to append a line to the kernel's scripts/gen_initramfs_list.sh but commits f6f57a46435d and 80e715a06c2d gradually made the code less flexible, so the text list is produced and consumed within the same script and no longer available for external editing. I've repeatedly submitted a patch to linux-kernel since 2017, ala https://lkml.indiana.edu/hypermail/linux/kernel/1705.1/02815.html and https://lkml.indiana.edu/hypermail/linux/kernel/2201.2/00174.html to make the existing CONFIG_DEVTMPFS_MOUNT symbol apply to initramfs, which would also fix this problem, but it has not been accepted. (An updated version for the current kernel is part of the linux-patches in each mkroot release on the website, this issue only manifests when that patch applied or the config symbol isn't enabled, which is why it took so long to notice.) --- toys/pending/sh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toys/pending/sh.c b/toys/pending/sh.c index 2d54e912..5ae18d3f 100644 --- a/toys/pending/sh.c +++ b/toys/pending/sh.c @@ -2691,7 +2691,7 @@ notfd: s = 0; break; - } + } else if (from==to) saveclose |= 2; } // perform redirect, saving displaced "to". -- 2.39.2