Posix hardlink heartache
michael.orlitzky.com
michael.orlitzky.com
> While hard links are certainly a lesser evil than setuid, and there is little motivation to rid ourselves of them, they do serve to illustrate how a seemingly clever and useful design can have a range of side effects which can weigh heavily against the value that the design tries to bring.
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.
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?
"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"
https://github.com/OpenRC/opentmpfiles/issues/3
>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 just seems a bit discriminatory.
https://github.com/torvalds/linux/commit/561ec64ae67ef25cac8...
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.
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".
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…)
I've been using Linux for more than 20 years and the only case I've found is for rsync incremental backups (--link-dest option), which is great for doing backups to an external USB hard drive and saving space. But that's rather niche.
As an advanced feature there's plenty of room for abuse and footgun problems, but it's still occasionally, maybe even rarely, the correct tool for the job.
Besides, won't this walk and copy the entire directory subtree? (i.e., CoW only applied to the files themselves, not just directory entries.)
I'm saying I'd like to just have a hard link to the directory itself; if the directory is effectively a list of inode pointers, I just want to add another pointer to that list of pointers. Then, if I create or modify a new file in some deep nested directory in either copy, it will be instantly available in both or more locations without any metadata changes on disk to more than one copy of the metadata itself. This would be interesting for certain use cases.
It's the most straightforward way to ensure the directory structure remains a directed acyclic graph.
1. create, write, close/sync "file.new"
2. hardlink "file" to "file.old" and sync again
3. rename "file.new" to "file"
4. sync to finish
With these steps, regardless of where you are interrupted, you always have a "functioning" copy of the file. This is quite important for tools writing configuration files or state to disk, but also just your plain old office suite preventing total loss of your PhD thesis.
(Yes it's not perfect, sync()ing correctly is hard [you need to sync the files and the directory!], and hard filesystem damage/kernel panics can always break things.)
Edit: WTF, apparently it's a core Apple Time Capsule feature. Okay. Cool. Never touching that.
Edit²: https://arstechnica.com/gadgets/2011/07/mac-os-x-10-7/12/ claims that hard links are actually hidden files(?) on HFS+:
> One particularly scary example is the implementation of hard links on HFS+. To keep track of hard links, HFS+ creates a separate file for each hard link inside a hidden directory at the root level of the volume. Hidden directories are kind of creepy to begin with, but the real scare comes when you remember that Time Machine is implemented using hard links to avoid unnecessary data duplication.
IIRC ln(1) can't create directory hardlinks, but link(2) allows it (on HFS+, directory hardlinks were not ported over to APFS).
Directory hardlink support was originally added for time machine.
AT&T UNIX System V allowed it for the root user only.
Depends what you mean by "not exposed to the user": while ln(1) can't create directory hardlinks it works fine via link(2) (on HFS+), with the limitation that hardlinked directories can't be siblings.
And of course directory hardlinks are fucking terrifying because `unlink(1)` will not work, and `rm(1)` will recursively remove directory contents, so you need to go through `unlink(2)` in C.
Hardlinks to directories not only break bunch of userspace expectations, but more importantly create a structure that cannot be unlink(2)ed (unlink(2) does not work on directories and rmdir(2) works only for directories with st_nlink==2). So even on systems that allow creation of that it is restricted to root.
I once googled if there is a mount option to disable symlink creation, unfortunately there is no.
So, yes the Internet is great - it connects what 5 billion adults now, and allows faster finding of the things you want etc. But there is soooo much ... of this stuff. I am guessing that "Digital marketing for the Rental market" means you have a house to let, and you want to list it with these people and their five competitors because you might miss out because who knows where one's audience really looks.
Now we could talk about disaggregation of AiBnB as a positive thing, but really - no, lets not.
What we can talk about is there is a bare minimum of cost / effort we can imagine here. Call it a Craigslist for the whole internet. Want to sell something - just find the right RDF tuple and list it. A search engine can find it and anyone searching for "house to rent in London" or "new pair trainers" will have a complete JSON list to walk through - sortable by price, location, availability etc etc.
Now this is not something I think should exist, but if it did it would still have a cost to operate. But we could measure the unnecessary churn by comparing the actual cost (in people, dollars, time etc) of things like RentPath to this bare minimum.
I expect there are Economics PhDs on this, but it struck me as interesting.