On Tue, Jan 14, 2020 at 04:57:33AM +0000, Al Viro wrote:
On Sat, Jan 11, 2020 at 08:07:19AM +1100, Aleksa Sarai wrote:
If I'm understanding this proposal correctly, this would be a problem for the libpathrs use-case -- if this is done then there's no way to avoid a TOCTOU with someone mounting and the userspace program checking whether something is a mountpoint (unless you have Linux >5.6 and RESOLVE_NO_XDEV). Today, you can (in theory) do it with MNT_EXPIRE:
- Open the candidate directory.
- umount2(MNT_EXPIRE) the fd.
* -EINVAL means it wasn't a mountpoint when we got the fd, and the fd is a stable handle to the underlying directory.
- -EAGAIN or -EBUSY means that it was a mountpoint or became a mountpoint after the fd was opened (we don't care about that, but fail-safe is better here).
- Use the fd from (1) for all operations.
... except that foo/../bar *WILL* cross into the covering mount, on any kernel that supports ...at(2) at all, so I would be very cautious about any kind "hardening" claims in that case.
I'm not sure about Linus' proposal - it looks rather convoluted and we get a hard to describe twist of semantics in an area (procfs symlinks vs. mount traversal) on top of everything else in there...
PS: one thing that might be interesting is exposing LOOKUP_DOWN via AT_... flag - it would allow to request mount traversals at the starting point explicitly. Pretty much all code needed for that is already there; all it would take is checking the flag in path_openat() and path_parentat() and having handle_lookup_down() called there, same as in path_lookupat().
A tricky question is whether such flag should affect absolute symlinks - i.e.
chdir /foo ln -s /bar barf overmount / do lookup with that flag for /bar/splat do lookup with that flag for barf/splat
Do we want the same results in both calls? The first one would traverse mounts on / and walk into /bar/splat in overmounting; the second - see no mounts whatsoever on current directory (/foo in old root), see the symlink to "/bar", jump to process' root and proceed from there, first for "bar", then "splat" in it...