Apparently a user can create a hardlink to a sensitive root-owned file (like /etc/shadow) in a user-writable directory where they know a privileged process (in this case tmpfiles.d) will come along and chown it to the user, after which that user will own the sensitive file too.
Thanks a lot for the clarification! I hadn't quite puzzled this together in my head.
It's really counterintuitive that creating a hardlink is allowed based solely on the permissions of the directory it is created in. I think I was expecting another permission check based on the directory the file is sitting in, since that's gating unlink() and rename().
It also means that, any file you can "see", if you have write access somewhere on the same filesystem you can prevent it from being deleted[¹] — even if you can't read it. That feels like a possible privacy issue…
[¹] If the user trying to delete file is aware of the problem, they can truncate it to 0 bytes, but that's not what a plain rm does (because rm is also the tool to remove hardlinks…)
Linux does (since version 3.6) have the ability to prevent users from creating hardlinks to files they don't own. (See man 5 proc under "/proc/sys/fs/protected_hardlinks".) I think FreeBSD has a similar sysctl option.
The linked article does mention it but warns "If you're not using systemd, the vanilla Linux kernel does not enable these protections by default".
>Couldn’t they introduce the same security feature mentioned for symlinks?
"The tmpfiles.d specification for the Z type more or less implies some kind of recursive chown. The spec heads off one type of vulnerability by saying that symlinks should not be followed; however, hard links are still a problem"
>As in, make it so by default you can’t create a hard link to a file you don’t already have write access to?
From the CVE: "when the fs.protected_hardlinks sysctl is turned off"
A description of that: "When set to “1” hardlinks cannot be created by users if they do not already own the source file, or do not have read/write access to it."
.. which apparently now won't work under systemd either!
IMO, he was wrong on this; it should have been enabled by default, and then the people who need that exceptionally rare legacy stuff can disable it with the same techniques (/proc, initrd) that he is currently suggesting to enable it.
Apparently a user can create a hardlink to a sensitive root-owned file (like /etc/shadow) in a user-writable directory where they know a privileged process (in this case tmpfiles.d) will come along and chown it to the user, after which that user will own the sensitive file too.