Bug#1150884: udev: initramfs hook copies symlinks with 'cp -r' and modifies chmod /dev/null !

develchizewr at mailbox.org develchizewr at mailbox.org
Wed Oct 14 11:20:50 BST 2026


Package: udev
Source: systemd
Version: 259.5-0ubuntu3.4
Severity: normal

Dear Maintainer,

since "initramfs-tools: copy network drop-ins too" (#1074564, systemd 
256.2-1), debian/extra/initramfs-tools/hooks/udev copies .link files with:

   find -L /etc/systemd/network -name '*.link*' -execdir cp -r -pt 
"$DESTDIR/usr/lib/systemd/network/" '{}' +

(same for /usr/lib/systemd/network and, in debian/master, 
/usr/local/lib/systemd/network).

Because of -r, symlinks (e.g. masks pointing to /dev/null) are copied as 
symlinks into $DESTDIR. If a regular file of the same name is copied 
later into the same destination, cp writes through the existing symlink 
in $DESTDIR and fchmod()s its target. With a mask pointing to /dev/null, 
/dev/null becomes mode 0644 until the next reboot (devtmpfs resets it). 
Login shells then fail with "Permission denied: /dev/null" for non-root 
users.

I hit this on Ubuntu 26.04 after update-initramfs -u. The installed hook 
is identical to debian/master except for the /usr/local block (compared 
by eye).

Reproduction without any special system state (touches only a temporary 
directory; "victim" stands in for /dev/null):

   t=$(mktemp -d); mkdir -p $t/usr $t/etc $t/dst; : > $t/victim; chmod 
666 $t/victim
   ln -s $t/victim $t/usr/99-default.link
   echo admin > $t/etc/99-default.link; chmod 644 $t/etc/99-default.link
   find -L $t/usr -name '*.link*' -execdir cp -r -pt $t/dst/ '{}' +
   find -L $t/etc -name '*.link*' -execdir cp -r -pt $t/dst/ '{}' +
   stat -c '%A %s' $t/victim

Result: "-rw-r--r-- 6" (mode and content of the victim file changed). 
Expected: unchanged.

In my case it was triggered by running the hook twice into the same 
$DESTDIR (a leftover symlink /etc/initramfs-tools/hooks/udev -> 
/usr/share/initramfs-tools/hooks/udev), together with symlinks to 
/dev/null in a subdirectory of /etc/systemd/network that the recursive 
find descends into. The plain "documented mask" case (regular file in 
/usr/lib, symlink in /etc, one run) is not affected.

Proposed fix: add --remove-destination to the three cp calls in the 
hook, i.e.

   find -L ... -name '*.link*' -execdir cp -r --remove-destination -pt 
"$DESTDIR/usr/lib/systemd/network/" '{}' +

An existing entry in $DESTDIR (symlink or regular file) is then replaced 
instead of followed, so later files of the same name override earlier 
ones as intended and nothing outside $DESTDIR is touched. I verified 
this with the reproduction above and with the two-run variant (hook run 
twice into the same $DESTDIR): the victim file stays unchanged in both 
cases. I did not test it inside a full package build.

Best regards
Chizzon



More information about the Pkg-systemd-maintainers mailing list