在非共享命名空间内挂载文件系统映像

在非共享命名空间内挂载文件系统映像

我用来unshare执行诸如绑定安装到某个进程本地的操作无需 root 访问权限,例如:

unshare -mr bash mount --bind a b

(是的,这看起来有点愚蠢;在我的实际用例中;unshare正在运行一个执行绑定安装的 bash 脚本。我在这里没有这样做,所以它是一个较小的示例。)

但是,如果我尝试循环安装,则会失败:

ryan@DevPC-LX ~/stuff/util-linux master $ unshare -mr mount -o loop x.img a
mount: no permission to look at /dev/loop<N>

:/

我尝试过mknod创建一个假循环设备(需要非root用户无法获得的权限),手动运行losetup(仍然需要root权限),以及一堆其他不起作用的东西。

当然,我可以这样做chown myuser /dev/loop*,但这似乎可能成为一个重大的安全问题。

此外,guestmount对于我的用例来说太慢了,并且fuseext2有关于写入模式下可能丢失数据的警告(而且也太慢了)。

有什么办法可以做到这一点吗?到底有没有?

答案1

正如您所清楚了解的,创建循环安装由两个步骤组成:

  1. 设置循环设备
  2. 安装它

当然,我可以只执行 chown myuser /dev/loop* ,但这似乎可能成为一个主要的安全问题。

我相信这将允许创建适当的循环设备(通过授予访问权限/dev/loopcontrol)。我不知道是否还有某种可用的命名空间会影响循环设备的视图。这可能会允许更安全地执行此操作。

不过,第 2 步仍然是不行的:用户命名空间确实允许创建新的挂载命名空间,用户可以在其中创建新的挂载,但它相当有限 -CAP_SYS_ADMIN 在初始命名空间中仍然需要安装块设备:正如user_namespaces(7)所说......

但请注意,安装基于块的文件系统只能由在初始用户命名空间中保存 CAP_SYS_ADMIN 的进程来完成。

循环设备是由文件支持的块设备,因此这仍然是不行的。这是不幸的,我确实认为应该有一种方法可以安全地工作。但我想这里面有很多错综复杂的地方(特别是 setuid)这就是它尚未实施的原因。

据我了解,您真正能做的就是解决这个问题。也许您可以从映像中提取文件(如果最坏的情况发生,即没有可用于直接处理特定格式的工具,您可以将其安装在临时虚拟机中来执行此操作),然后绑定安装结果目录。

答案2

为了运行 unshare,您必须具有 root 能力来创建单独的安装空间。

我尝试过这个似乎可以满足您的要求(我认为):

Ishtar:> mkdir -p /tmp/unshare/home
Ishtar:> cd /tmp/unshare
Ishtar:/tmp/unshare> sudo unshare -m /bin/bash
Ishtar:/tmp/unshare# mount --rbind /home/packages /tmp/unshare/home
Ishtar:/tmp/unshare# tty
/dev/pts/4
Ishtar:/tmp/unshare# # ls home
BUILD@      RPMS@     build/           linux@    sources/           tmp/
BUILDROOT@  SOURCES@  buildroot/       logs/     specs/
OSbuild/    SPECS@    config-scripts/  perlsrc/  srpms/
OTHER/      SRPMS@    debug@           rpms/     sysvinit-288.spec

所以上面的过程已经安装了'/home/packages @ /tmp/unshare/home。

在另一个 tty 窗口中,对于任何用户,我都可以尝试查看: /tmp/unshare/home 中有什么:

Ishtar:/> tty
/dev/pts/5
Ishtar:/> ll /tmp/unshare/home
total 0
Ishtar:/> cd tmp/unshare
Ishtar:/tmp/unshare> sudo
Ishtar:/tmp/unshare# ls home
Ishtar:/tmp/unshare# ll home
total 0
# create file in original "bound" dir from 1st usr above:
Ishtar:/tmp/unshare# touch /home/packages/PACKAGES.DIR 
Ishtar:/tmp/unshare# ll home  #home still empty
total 0
Ishtar:/> tty
/dev/pts/5
# now on other user again
Ishtar:/tmp/unshare# tty
/dev/pts/4
Ishtar:/tmp/unshare# ls home
BUILD@        RPMS@     buildroot/       perlsrc/  sysvinit-288.spec
BUILDROOT@    SOURCES@  config-scripts/  rpms/     tmp/
OSbuild/      SPECS@    debug@           sources/
OTHER/        SRPMS@    linux@           specs/
PACKAGES.DIR  build/    logs/            srpms/
#^^^ see PACKAGES.DIR appear (as created in original dir by another
# user

一旦你在“pts/4”中为用户安装了“私有目录”,你就可以更改为你想要在该程序下运行的 UID:

Ishtar:/tmp/unshare# su astara
Ishtar:/tmp/unshare> whoami
astara
Ishtar:/tmp/unshare> ls home/PACK*
home/PACKAGES.DIR

注意对于非特权用户来说挂载仍然存在。

为了保存,我将“su to other user”放在一个脚本文件中,然后是“unmount /tmp/unshare/home”,(因为当su OTHERUSER退出时,它将再次成为root,并卸载该文件私人空间,)。然后就可以退出了。

这接近你想要的吗? -- 您必须使用“root”来设置子环境,然后运行子环境 - 并且只有它才能访问在新挂载命名空间中创建的挂载。

(更新)顺便说一句 - 刚刚注意到 unshare 有一个 --map-root-user ,专门允许使用 root 或 caps 在新命名空间中设置选项。联机帮助页说(关于此开关):

....This makes it possible to  conveniently
gain  capabilities needed to manage various aspects of the newly
created namespaces (such as configuring interfaces in  the  net-
work  namespace  or mounting filesystems in the mount namespace)
even when run unprivileged.

这可以让你管理你的循环开发而不需要root(或者手册页上是这么说的)。 CAP_SYS_ADMIN 可能是执行此操作所需的上限。

相关内容