我用来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
正如您所清楚了解的,创建循环安装由两个步骤组成:
- 设置循环设备
- 安装它
当然,我可以只执行 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 可能是执行此操作所需的上限。