initd/coldplug: create /dev/null before running udevtrigger
authorSteev Klimaszewski <threeway@gmail.com>
Sat, 17 Jan 2026 04:10:22 +0000 (22:10 -0600)
committerDaniel Golle <daniel@makrotopia.org>
Mon, 9 Feb 2026 11:09:58 +0000 (11:09 +0000)
When procd_coldplug() runs, it unmounts /dev and mounts a fresh empty
tmpfs before forking udevtrigger to populate device nodes via hotplug
events. Since udevtrigger runs asynchronously, there is a race window
between the fresh mount and when the "null" device uevent is processed.

If any code executes a shell redirect to /dev/null during this window
(e.g., from hotplug handlers or other event processing), the shell
creates /dev/null as a regular file. When the null device uevent is
later processed, makedev()'s mknod() fails silently with EEXIST,
leaving /dev/null as a regular file permanently.

This causes all subsequent redirections to /dev/null to append to the
file instead of discarding output, eventually filling up the tmpfs.

Fix by explicitly creating /dev/null immediately after mounting the
fresh tmpfs, before any other code can run.

Signed-off-by: Steev Klimaszewski <threeway@gmail.com>
plug/coldplug.c

index f84acef97e29aef03751c78f951158281b12164e..19254024850fba49004502a4b1a16a23754346a3 100644 (file)
@@ -49,6 +49,7 @@ void procd_coldplug(void)
                umount2("/dev/pts", MNT_DETACH);
                umount2("/dev/", MNT_DETACH);
                mount("tmpfs", "/dev", "tmpfs", MS_NOATIME | MS_NOEXEC | MS_NOSUID, "mode=0755,size=512K");
+               mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3));
                mkdir("/dev/pts", 0755);
                mount("devpts", "/dev/pts", "devpts", MS_NOATIME | MS_NOEXEC | MS_NOSUID, 0);
        }