0

I want to create a new namespace with a different /etc/hosts, so I tried to use mount --bind with unshare to create it as referenced in this answer: https://unix.stackexchange.com/a/242830/271204

# Create temp hosts
export TEMP_HOSTS=$(mktemp XXXXXXX.hosts)
trap "{ rm -f $TEMP_HOSTS; }" EXIT
cat /etc/hosts > $TEMP_HOSTS

Create new ns

unshare -m bash mount --make-private "$TEMP_HOSTS" /etc/hosts --bind

Then I got a new shell (denoted as Shell2), and wrote something to it. It's ok and /etc/hosts is still in mount after append or edit.

(Shell2) # cat /proc/self/mountinfo | grep /etc/hosts
218 189 8:1 /tmp/Z3flEXS.hosts /etc/hosts rw,relatime - ext4 /dev/sda1 rw,errors=remount-ro
(Shell2) # echo '127.0.0.1 aaaa' >> /etc/hosts
(Shell2) # cat /proc/self/mountinfo | grep /etc/hosts
218 189 8:1 /tmp/Z3flEXS.hosts /etc/hosts rw,relatime - ext4 /dev/sda1 rw,errors=remount-ro

When I start a new terminal window or create or new ssh session, I get a shell with old namespace of the system and denote it as Shell1.

The /etc/hosts under Shell1 is still the old version as expect because the mount is --make-private. But when I modify the /etc/hosts under Shell1 with `vim, /etc/hosts under Shell2 is also changed and the mount is disappeared.

# Append "127.0.0.1 aaaaa" with vim, or you can use vim interactively.
(Shell1) # vim -c "$ s/$/\r127.0.0.1 aaaaa/" -c "wq" /etc/hosts
(Shell1) # md5sum /etc/hosts
1580e29f05e6af70012afe37ce08cb5a  /etc/hosts
(Shell2) # cat /proc/self/mountinfo | grep /etc/hosts
* Nothing here
(Shell2) # md5sum /etc/hosts
1580e29f05e6af70012afe37ce08cb5a  /etc/hosts

But in the step of modifying /etc/hosts in shell1, /etc/hosts in new namespace will not be affected when I use echo '127.0.0.1 aaaa' >> /etc/hosts instead of using vim to edit and save.

So my question is why I modified file with vim in old namespace, the file in the new namespace is also been affected? Why the behavior is different when using shell redirection? Can I change unshare or mount options to avoid the change caused by vim in old namespace?

  • Thanks a lot! At when the problem occurred, I used vim to edit the file. Modification of file with shell redirection indeed can not reproduce it. I have updated the description. – Komeiji Kuroko Jan 18 '21 at 11:33

1 Answers1

1

That's because vim is not editing the file in place -- when saving the file, vim creates a temporary file in the same directory and then renames it to the original.

You'll probably get the same effect with cp /etc/hosts{,~}; mv /etc/hosts{~,} (or with sed -i, which does the same thing as vim); renaming a file to another is like unlinking the old dir entry and then creating another one in its place (but in a single atomical step).

The unlinking part is obliterating any mount from another namespace.

And this is intended behaviour -- see the calls to detach_mounts in fs/namei.c from vfs_{unlink,rename,rmdir}(). Only a mount in the same namespace will cause them to fail with EBUSY.

That feels a bit sketchy, but without this, any process could mount over a file or directory in a private namespace as a way to prevent it from ever being removed ----- which may turn into a denial of service attack [1]

The same puzzling behaviour happens when you mount over files under /proc/PID/ -- the mount just disappears when process PID exits, without being explicitly unmounted.


[1] This is actually the rationale from the commit which changed the behaviour in 2013, also mentioned in the mount_namespaces(7) manpage:

Previously (before Linux 3.18), attempting to unlink, rename, or remove a file or directory that was a mount point in another mount namespace would result in the error EBUSY. That behavior had technical problems of enforcement (e.g., for NFS) and permitted denial-of-service attacks against more privileged users. (i.e., preventing individual files from being updated by bind mounting on top of them).

  • That's it. I used strace with vim and found it rename file to name suffix with ~ and write to /etc/hosts then unlink the old file. According to https://man7.org/linux/man-pages/man7/mount_namespaces.7.html it would never results EBUSY when unlink mountpoint at other namespace in recent kernel versions. – Komeiji Kuroko Jan 19 '21 at 03:20