1

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?

1
  • 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. Jan 18 at 11:33
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).

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.