我有一个 unix 安装,应该既可以用作 chroot,也可以用作独立系统。如果它作为 chroot 运行,我不想运行任何服务(cron、inetd 等),因为它们会与主机系统冲突或冗余。
如何编写一个根据是否在 chroot 中运行而表现不同的 shell 脚本?我迫切需要的是一个现代的 Linux 系统,/proc
安装在 chroot 中,并且脚本以 root 身份运行,但也欢迎更多可移植的答案。 (看如果 /proc 未安装,我如何知道我正在 chroot 中运行?对于没有 . 的 Linux 的情况/proc
。)
更一般地说,适用于其他遏制方法的建议将会很有趣。实际问题是,这个系统应该运行任何服务吗? (在 chroot 中答案是否定的,在成熟的虚拟机中答案是肯定的;我不知道诸如监狱或容器之类的中间情况。)
答案1
我在这里所做的是测试进程的根init
(PID 1)是否与当前进程的根相同。虽然/proc/1/root
始终是一个链接/
(除非init
它本身被 chroot,但这不是我关心的情况),但跟随它会导致“master”根目录。此技术用于 Debian 中的一些维护脚本,例如在 chroot 中安装后跳过启动 udev。
if [ "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" ]; then
echo "We are chrooted!"
else
echo "Business as usual"
fi
(顺便说一句,这是另一个例子,说明为什么chroot
如果 chroot 进程具有 root 访问权限,那么对于安全性来说毫无用处。非 root 进程无法读取/proc/1/root
,但/proc/1234/root
如果有一个 PID 1234 的正在运行的进程以相同的方式运行,它们可以跟随用户。)
如果您没有root权限,您可以查看/proc/1/mountinfo
和/proc/$$/mountinfo
(简要记录在filesystems/proc.txt
在Linux内核文档中)。该文件是世界可读的,并且包含有关进程的文件系统视图中每个挂载点的大量信息。该文件中的路径受到影响读取器进程(如果有)的 chroot 的限制。如果进程读取/proc/1/mountinfo
被 chroot 到与全局根不同的文件系统中(假设 pid 1 的根是全局根),则/
中不会出现的条目/proc/1/mountinfo
。如果进程读取被 chroot 到全局根文件系统上的目录,则中会出现 的/proc/1/mountinfo
条目,但具有不同的挂载 ID。顺便说一句,根字段 ( ) 指示 chroot 在其主文件系统中的位置。/
/proc/1/mountinfo
$4
[ "$(awk '$5=="/" {print $1}' </proc/1/mountinfo)" != "$(awk '$5=="/" {print $1}' </proc/$$/mountinfo)" ]
这是一个纯粹的Linux 解决方案。它可以推广到具有足够相似性的其他 Unix 变体/proc
(Solaris 有一个类似的/proc/1/root
,我认为,但不是mountinfo
)。
答案2
正如中提到的查找 inode 号的便携式方法和从内部检测 chroot 监狱,可以检查inode号是否/
为2
:
$ ls -di /
2 /
索引节点号不同于 2 表示表观根不是文件系统的实际根。这不会检测碰巧以挂载点或具有随机根索引节点号的操作系统。
答案3
虽然显然不如此处列出的许多其他选项那么便携,但如果您使用的是基于 Debian 的系统,请尝试ischroot
.
看:https://manpages.debian.org/jessie/debianutils/ischroot.1.en.html
要直接在控制台中获取状态,请使用 ischroot:
ischroot;echo $?
退出代码:
0 if currently running in a chroot
1 if currently not running in a chroot
2 if the detection is not possible (On GNU/Linux this happens if the script is not run as root).
答案4
这只是一个偶然的观察。但是,如果您可以使用 FUSE 访问任何内容,那么您可以挂载某些内容,然后使用mount
显示挂载路径,该路径将以 chroot 路径为前缀显示。
例如,在 Github Actions Mac 运行器上,您可以执行以下操作:
pip install --user ratarmount
folder=$(mktemp -d)
mountedFolder=$(mktemp -d)
# simple bind mount a folder
ratarmount "$folder" "$mountedFolder"
现在mount
将打印如下内容:
TarMount on /private/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/tmp.P5g4TomF (macfuse, nodev, nosuid, synchronous, mounted by runner)
即使mountedFolder
变量中的完整路径是:/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/tmp.P5g4TomF
。因此,我们似乎已经根深蒂固了/private
。
因为这个 hackymountpoint
命令替代品使用mount
并且grep
对我不起作用。