为什么我不能从同一文件系统上的“mount --bind”目录创建到文件的“硬链接”?

SO_*_*bug 10 mount ln bind-mount

原问题

我在一个文件系统上有一个文件: /data/src/file

我想将它硬链接到: /home/user/proj/src/file

但是/home在一个磁盘上,/data在另一个磁盘上,所以我收到一个错误:

$ cd /home/user/proj/src
$ ln /data/src/file .
ln: failed to create hard link './file' => '/data/src/file': Invalid cross-device link
Run Code Online (Sandbox Code Playgroud)

好的,所以我了解到我不能跨设备进行硬链接。说得通。

手头的问题

所以我想我会喜欢并绑定挂载一个src位于/data文件系统上的文件夹:

$ mkdir -p /data/other/src
$ cd /home/user/proj
$ sudo mount --bind /data/other/src src/
$ cd src
$ # (now we're technically on `/data`'s file system, right?)
$ ln /data/src/file .
ln: failed to create hard link './file' => '/data/src/file': Invalid cross-device link
Run Code Online (Sandbox Code Playgroud)

为什么这仍然不起作用?

解决方法

我知道我有这个设置,因为只要我在“真实”/data目录而不是绑定目录中,我就可以建立硬链接。

$ cd /data/other/src
$ ln /data/src/file .
$ # OK
$ cd /home/user/proj/src
$ ls -lh
total 35M
-rw------- 2 user user 35M Jul 17 22:22 file

$
Run Code Online (Sandbox Code Playgroud)

一些系统信息

$ uname -a
Linux <host> 4.10.0-24-generic #28-Ubuntu SMP Wed Jun 14 08:14:34 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

$ findmnt
.
.
.
??/home                               /dev/sdb8   ext4       rw,relatime,data=ordered
? ??/home/usr/proj/src             /dev/sda2[/other/src]
?                                                 ext4       rw,relatime,data=ordered
??/data                               /dev/sda2   ext4       rw,relatime,data=ordered

$ mountpoint -d /data
8:2

$ mountpoint -d /home/usr/proj/src/
8:2
Run Code Online (Sandbox Code Playgroud)

注意:我手动更改了文件和目录名称以使情况更清楚,因此命令读数中可能存在一两个错字。

sou*_*edi 9

代码中缺少注释令人失望。好像没有人认为它有用,因为时间绑定挂载是在 v2.4 中实现的。当然,您需要做的就是替换.mnt->mnt_sb它所说的.mnt......

因为它为您提供了围绕子树的安全边界。

PS:这已经讨论过很多次了,但为了避免搜索:考虑例如 mount --bind /tmp /tmp; 现在,您遇到的情况是,即使用户具有可写的 /tmp,也无法在没有 root fs 的情况下创建指向其他地方的链接。类似的技术适用于其他隔离需求 - 基本上,您可以将重命名/链接限制为给定的子树。IOW,这是一个故意的功能。请注意,您可以将一堆树绑定到 chroot 中并获得可预测的限制,而不管这些内容一年后如何在主树中重新排列,等等。

—— 阿尔维罗

后面还有一个具体的例子

每当我们让 mount -r --bind 正常工作时(我使用它在 chroot jail 中放置必要共享库的副本,同时允许页面缓存共享),此功能将破坏安全性。

mkdir /usr/lib/libs.jail
for i in $LIST_OF_LIBRARIES; do
ln /usr/lib/$i /usr/lib/libs.jail/$i
done
mount -r /usr/lib/libs.jail /jail/lib
chown prisoner /usr/log/jail
mount /usr/log/jail /jail/usr/log
chrootuid /jail prisoner /bin/untrusted &
Run Code Online (Sandbox Code Playgroud)

虽然保护应该足够了,但我宁愿避免将囚犯链接 /jail/lib/libfoo.so(写入返回 EROFS)到 /jail/usr/log 那里它可能是可写的。