为什么我在新的命名空间中挂载 --bind --make-private /etc/hosts ,在旧的命名空间中使用 vim 修改此文件也会影响新的 ns ?

为什么我在新的命名空间中挂载 --bind --make-private /etc/hosts ,在旧的命名空间中使用 vim 修改此文件也会影响新的 ns ?

我想使用不同的名称空间创建一个新的名称空间/etc/hosts,因此我尝试使用mount --bindunshare 来创建它,如本答案中所引用的: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

然后我得到了一个新的 shell(记为 Shell2),并在其中写了一些东西。没关系,/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
(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

当我启动新的终端窗口或创建或新的 ssh 会话时,我会得到一个带有系统旧命名空间的 shell,并将其表示为 Shell1。

Shell1 下的 /etc/hosts 仍然是旧版本,因为挂载的是--make-private.但是当我用`vim修改Shell1下的/etc/hosts时,Shell2下的/etc/hosts也改变了,挂载消失了。

# 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

但是在shell1中修改/etc/hosts的步骤中,/etc/hosts在新的命名空间中,当我使用echo '127.0.0.1 aaaa' >> /etc/hosts而不是使用vim编辑和节省

所以我的问题是为什么我修改了vim旧命名空间中的文件,新命名空间中的文件也受到影响?为什么使用 shell 重定向时行为不同?我可以更改unsharemount选项来避免旧命名空间中 vim 引起的更改吗?

答案1

这是因为vim没有就地编辑文件——保存文件时,vim 在同一目录中创建一个临时文件,然后将其重命名为原始文件。

cp /etc/hosts{,~}; mv /etc/hosts{~,}使用(或使用sed -i,其作用与)可能会得到相同的效果vim;将一个文件重命名为另一个文件就像取消旧目录条目的链接,然后在其位置创建另一个文件(但在单个原子步骤中)。

取消链接部分正在删除来自另一个命名空间的任何挂载。

detach_mounts这是预期的行为 - 请参阅对in 的调用fs/namei.cvfs_{unlink,rename,rmdir}()。只有一个坐骑相同的命名空间将导致它们失败并显示EBUSY.

这感觉有点粗略,但如果没有这个,任何进程都可以挂载在私有命名空间中的文件或目录上,以防止其被删除 ----- 这可能会变成拒绝服务攻击 [1]

当您挂载以下文件时,会发生相同的令人费解的行为/proc/PID/——当进程退出时,挂载就会消失PID,而不会被显式卸载。


[1] 这实际上是来自犯罪这改变了 2013 年的行为,也在挂载命名空间(7)联机帮助页:

以前(Linux 3.18 之前),尝试取消链接、重命名或删除作为另一个挂载命名空间中的挂载点的文件或目录将导致错误EBUSY。这种行为存在执行方面的技术问题(例如,对于 NFS),并且允许对更有特权的用户进行拒绝服务攻击。 (即,防止通过在单个文件之上绑定安装来更新单个文件)。

相关内容