假设我有一个带有隔离 MOUNT 命名空间的进程,pid 1200
该进程称为unshare()
将其名称空间与父进程隔离。然后我想安装一个只能在pid 1200
命名空间内部访问的设备pid 1200
。这可能吗?
我想在运行的 LXC 容器内挂载设备或绑定挂载主机上的目录,而无需lxc.monitor.unshare = 1
重新启动容器。
答案1
不太理想,但您始终可以挂载 NFS 或其他网络文件系统。
下面的部分做了不是工作(至少不适用于 4.2 内核),将其作为参考,这样人们就不必自己尝试。
尽管当您输入挂载命名空间(nsenter -m
或setns(CLONE_NEWNS)
)时,您的工作目录会自动更改为该命名空间的根(/
),但仍然可以在某些文件描述符上打开目录,输入命名空间并仍然在该命名空间上打开该目录fd (例如fchdir()
对其执行 a )。
所以你会认为这种方法可能有效:
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mount.h>
#include <sched.h>
void die(char *msg) {perror(msg); exit(1);}
int main(int argc, char *argv[]) {
int fd;
if (argc != 3) {
fprintf(stderr, "Usage: %s <source-in-current-namespace> <dest-in-namespace-on-stdin>\n");
exit(1);
}
fd = open(argv[1], O_RDONLY|O_DIRECTORY);
if (fd < 0) die("open");
if (setns(0, CLONE_NEWNS) < 0) die("setns");
if (fchdir(fd) < 0) die("fchdir");
printf("cwd: %s\n", get_current_dir_name());
if (mount(".", argv[2], 0, MS_BIND, 0) < 0) die("mount");
}
它确实可以工作直到fchdir()
,但mount
失败并显示EINVAL
:
# ~/a.out /home /mnt < /proc/1200/ns/mnt
cwd: (unreachable)/home
mount: Invalid argument
答案2
我在这方面取得了一些成功 - 如果没有使用 lxc 容器,我确实设法使其适用于其他私有挂载命名空间。因为 lxc 是建立在我也在使用的底层 linux 命名空间上的,所以我看不出有任何理由它不适合你。
首先,我设置命名空间,如下所示:
sudo unshare -m sh -c '
mount -ttmpfs none /tmp
echo x > /tmp/mytmp
findmnt -o+PROPAGATION /tmp
echo "$$"
cd /tmp
exec "$0" -i
TARGET SOURCE FSTYPE OPTIONS PROPAGATION
/tmp tmpfs tmpfs rw private
/tmp none tmpfs rw,relatime private
29384
$
...我得到了一个交互式 shell。我在单独的终端会话中做的下一件事是......
sudo sh -c ' { cd /dev/fd/0 ; mkdir mnt
ls -l; cat mytmp
} 3<$0/ns/mnt <$0/29384/cwd
' /proc/29384
drwxr-xr-x 2 root root 40 Jan 4 02:52 mnt
-rw-r--r-- 1 root root 2 Jan 4 02:38 mytmp
x
...这非常令人鼓舞!
但我无法在那里挂载 - 每次我尝试将mount
父 ns 目录覆盖到子 ns 中的目录时,它都会失败 - 悲惨。一些研究表明这是设计使然(特别是:请参阅有关 PROPAGATION 标志的警告man 7 user_namespaces
)。什么做过不过,工作是(在新的命名空间中):
sudo unshare --propagation slave -m sh -c '
mount -ttmpfs none /tmp; cd /tmp
exec "$0" -i'
然后在父命名空间会话中...
sudo mount --bind / /mnt
sudo mount --bind / /tmp
sudo mount --bind /tmp /mnt/img/tmp
现在上面的方法适用于第一种情况,但不适用于第二种情况。因为子 ns 不会向上传播 fs 更改,所以父级 ns 不会影响对其 fs 视图所做的更改。因此,因为孩子有自己的坐骑,所以/tmp
父母所做的任何事情都无关紧要。但是,如果存在一些公共层次结构并且子 ns 配置为接收文件系统更改,那么它将要查看父级向下传播的更改。
在运行上述命令后的子 ns 中......
ls /tmp /mnt /mnt/tmp
/mnt:
bin dev etc lib mnt proc run srv tmp var
boot esp home lib64 opt root sbin sys usr
/mnt/tmp:
serverauth.FT3Z6IFyWW
systemd-private-...systemd-timesyncd.service-YUkVU6
/tmp:
所以我想回答这个问题 - 是的,我相信这是可能的。但是,我也相当确定你需要安排竟然如此提前。
答案3
这个答案有一些工作示例,使用 unshare (不是作为 root)和 nsenter (作为容器内的 root)来引起绑定挂载,并以同步方式调用它们来执行您想要的操作。不需要真正的 root 访问权限
遗憾的是,它需要 util-linux 2.39.1,这可能意味着 ubuntu 23.04 或更高版本。
请注意,取消共享调用具有以前互斥的选项。
我仍在尝试让它适用于早期的 ubuntu,例如 22.04(最新的 LTS)。一旦 24.04 出来我就会停止尝试。