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

kir*_*sos 7 mount loop-device namespace unshare

我正在使用unshare执行诸如将本地绑定安装到某个进程而不需要 root 访问权限之类的操作,例如:

unshare -mr bash mount --bind a b
Run Code Online (Sandbox Code Playgroud)

(是的,这看起来有点愚蠢;在我的实际用例中;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>
Run Code Online (Sandbox Code Playgroud)

:/

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

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

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

有没有办法做到……这个?根本?

小智 5

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

\n\n
    \n
  1. 设置循环设备
  2. \n
  3. 安装它
  4. \n
\n\n
\n

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

\n
\n\n

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

\n\n

不过,第 2 步仍然是不行的:用户命名空间确实允许创建新的挂载命名空间,用户可以在其中创建新的挂载,但在CAP_SYS_ADMIN 最初的\xe2\x80\x94 中它相当有限挂载块设备仍然需要命名空间user_namespaces(7):如\xe2\x80\xa6所示

\n\n
\n

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

\n
\n\n

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

\n\n

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

\n


Ast*_*ara 3

为了运行 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
Run Code Online (Sandbox Code Playgroud)

所以上面的过程已经安装了'/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
Run Code Online (Sandbox Code Playgroud)

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

Ishtar:/tmp/unshare# su astara
Ishtar:/tmp/unshare> whoami
astara
Ishtar:/tmp/unshare> ls home/PACK*
home/PACKAGES.DIR
Run Code Online (Sandbox Code Playgroud)

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

为了保存,我将“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.
Run Code Online (Sandbox Code Playgroud)

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