挂载在挂载命名空间中的文件系统在根命名空间中可见

问题描述 投票:0回答:1

我有一个程序,它使用 和

unshare(CLONE_NEWNS)
系统调用创建挂载命名空间,然后使用
/path/to/my/mount
/path/to/my/mount
mount syscall with mountflags=0. The mount succeeds and I can see the filesystem at 
/path/to/my/mount` 在
from a shell running in the mount namespace, but the mount also shows up in the root mount namespace - i.e. from an ordinary shell running on my computer I can see the contents of
挂载文件系统。我期望挂载只能在挂载命名空间内可见。

我使用的Go代码是这样的:

// lock this goroutine to a single OS thread because namespaces are thread-local
runtime.LockOSThread()
defer runtime.UnlockOSThread()

// switch to a new mount namespace
err := unix.Unshare(unix.CLONE_FS)
if err != nil {
    return fmt.Errorf("error entering new mount namespace: %w", err)
}

mountopts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lower, upper, work)
err = unix.Mount("overlay", target, "overlay", 0, mountopts)
if err != nil {
    return fmt.Errorf("error mounting overlay filesystem: %w", err)
}

如何才能使挂载命名空间中挂载的文件系统对于该命名空间是私有的?

这与挂载命名空间之间的挂载传播有关吗?我尝试通过在上面的 unshare 和 mount 系统调用之间插入以下内容,将挂载命名空间中的

/
更改为私有挂载:

// make the root filesystem in this new namespace private
err = unix.Mount("ignored", "/", "ignored", unix.MS_PRIVATE, "ignored")
if err != nil {
    return fmt.Errorf("error making root filesystem private")
}

这不起作用。

/
确实在挂载命名空间中变为私有(根据 /proc/self/mountinfo),但它也在根挂载命名空间中变为私有,尽管如此,我在
/path/to/my/mount
创建的挂载在两个命名空间中仍然可见。

mount linux-namespaces unshare
1个回答
0
投票

解决方案是在“/”的重新挂载中添加MS_REC标志。相关的系统调用是(必须在取消共享之后,安装新文件系统之前):

unix.Mount("ignored", "/", "ignored", unix.MS_PRIVATE|unix.MS_REC, "ignored")

根据手册页,linux 会忽略上面的第一个、第三个和第五个参数。上面的“忽略”字符串只是为了向代码读者表明这一点——它们可以是任何东西。

完整的工作解决方案:

// lock this goroutine to a single OS thread because namespaces are thread-local
runtime.LockOSThread()
defer runtime.UnlockOSThread()

// switch to a new mount namespace
err := unix.Unshare(unix.CLONE_NEWNS | unix.CLONE_FS)
if err != nil {
    return fmt.Errorf("error unsharing mounts: %w", err)
}

// make the root filesystem in this new namespace private, which prevents the
// mount below from leaking into the parent namespace
// per the man page, the first, third, and fifth arguments below are ignored
err = unix.Mount("ignored", "/", "ignored", unix.MS_PRIVATE|unix.MS_REC, "ignored")
if err != nil {
    return fmt.Errorf("error making root filesystem private")
}

// mount an overlay filesystem
// sudo mount -t overlay overlay -olowerdir=$(pwd)/lower,upperdir=$(pwd)/upper,workdir=$(pwd)/work $(pwd)/merged
err = unix.Mount("overlay", target, "overlay", 0, mountopts)
if err != nil {
    return fmt.Errorf("error mounting overlay filesystem: %w", err)
}
© www.soinside.com 2019 - 2024. All rights reserved.