2

I can move the parent directory of a mount point as follows:

$ mkdir -p f/mnt
$ bindfs --no-allow-other f/mnt f/mnt
$ mv f g
$

But I cannot rename the mount point itself:

$ mv g/mnt g/m
mv: cannot move 'g/mnt' to 'g/m': Device or resource busy

Is there a security, compatibility, or implementation reason for this distinction?

My kernel version is 4.17.19-200.fc28.x86_64.

sourcejedi
  • 50,249

3 Answers3

2

Schily's answer about why this is not working is accurate.

However, you actually can move mount points themselves on Linux. Borrowing from the example in the question, the correct way to do this is:

mount --move g/mnt g/m

The target directory (in this case g/m) has to be a valid location for a mount point (the directory has to exist, etc) and you must be running with root privileges (or CAP_MOUNT), but otherwise there are essentially no restrictions.

This operation will update all kernel managed data structures referencing that mount point, including mount table entries (within the current mount namespace), open file descriptors, root and current working directories for running programs, and a few other things, so it is (reasonably) safe to do this on a mount point in active use.

The caveat is that anything which is running and uses paths instead of file descriptors may not properly handle it (for example, moving the root of your website this way will probably break the website, because most web servers don't keep open references to all the files for the site).

You may also find the pivot_root command interesting, it's a special case of moving a mount point (it swaps two mount points and updates the root and current working directory of everything on the system), and is used during startup on most modern Linux systems to switch from the initramfs to the real root filesystem.

  • +1. This is not at all the answer I was looking for. I should apologize, as it is a good answer to the question I actually wrote :-). – sourcejedi Sep 11 '18 at 20:11
  • fails with bsd mount mount: illegal option -- - – Geoff Langenderfer Oct 19 '22 at 08:44
  • 1
    @GeoffLangenderfer Yes, because BSD uses different options. AFAIK, BSD does not support moving mount points without unmounting them. The question itself is tagged Linux though, so my answer just focused on Linux. – Austin Hemmelgarn Oct 19 '22 at 12:00
1

You cannot rename the root directory of a filesystem and this is what you like to do.

If you NFS-mount the filesystem with the underlying mount point, you may be able to rename it as this allows you to see the uncovered mount point.

Background: if something is mounted to an entry in the filesystem, this hides the orignal file, but you would need to rename the original file. What you see is the root directory of the mounted filesytem and that cannot be renamed.

schily
  • 19,173
  • Right, thanks. You can't rename() a directory to move it from one filesystem to another (EXDEV error). – sourcejedi Sep 11 '18 at 17:52
  • 1
    I am indeed able to rename the underlying file, if I use Linux mount namespaces :-). Or a bind mount would allow it also. – sourcejedi Sep 11 '18 at 17:57
  • I'm curious if I could explain why the error I get is EBUSY not EXDEV. But I didn't ask about that in the question :-). – sourcejedi Sep 11 '18 at 18:05
  • @sourcejedi Because that's the standard return code for indicating that a filesystem object can't be manipulated in the requested way due to it being in use by something that is mutually exclusive with the requested operation. You will get the same return code trying to unmount a filesystem that has open files for example. – Austin Hemmelgarn Sep 11 '18 at 19:34
  • @AustinHemmelgarn What is using it in my example? – sourcejedi Sep 11 '18 at 19:51
  • @sourcejedi The mount point itself is using the root directory of the volume mounted there, which is what mv would be trying to move. – Austin Hemmelgarn Sep 12 '18 at 19:52
  • @AustinHemmelgarn Right, agreed. That terminology doesn't generalize if I think about proper bind mounts on current Linux. mkdir a b; mount --bind a b; rmdir a. Success, no EBUSY. The POSIX answer is "in use by the system or some process", so it would just say "the system". I suggest we recognize that a was addressing a slightly different object to b. Then we can say you are not allowed to unlink b because it is the root of a mount point. A more generalized rule is that you can't unlink unless you're addressing a same-mount parent that you're unlinking the file from. – sourcejedi Sep 12 '18 at 21:46
  • @AustinHemmelgarn OTOH: this is not solid proof, but the only reason Linux VFS developers found to forbid unlink of a mount point like b was application compatibility. From that point of view I think "busy" / "in use" might not be the correct justification, it is "just" the historical error code for most of these cases. https://lwn.net/Articles/570338/ – sourcejedi Sep 12 '18 at 21:53
0

Yes: compatibility reasons which affect security.

This restriction was deliberately not removed, for a reason reported faithfully by LWN.net. Removing the restriction would create a security hole in some versions of fusermount. fusermount had been improved earlier by adding UMOUNT_NOFOLLOW, and this made it safe. However the old versions of fusermount were still widespread enough to be a concern.

See Mount point removal and renaming, LWN.net 2016.

As far as I can tell from the linked thread, patches 1-3 would have allowed moving a mount point. And then patch 4 was added to forbid it :-).

This is not complete proof. However it suggests the restriction in patch 4 was not due to internal implementation reasons. I also believe kernel developers would have mentioned, if they had any idea that user expectations would have been broken by allowing mount points to be moved.

@schily, however, points out there is something strange about allowing mount points to be moved (or unlinked). It appears that it was possible to allow rename() of a mount point. But only because it was interpreted as renaming the file underlying the mounted filesystem(s).

It would be a strange exception to the current rule, that rename(oldpath, newpath) requires that the oldpath and newpath are on the same filesystem. Otherwise it fails with EXDEV. (In fact they must be on the same mount of the filesystem).

I thought of one extra little strangeness under Linux. If you set the Linux "immutable bit" on the underlying file, I think the rename() should be denied. But if you inspect the immutable bit on the mount point, you will not see the immutable bit of the underlying file! I expect it works fine, it would just be rather annoying if you ever had to troubleshoot it.

sourcejedi
  • 50,249