chroot(2)
在给它一些打开的文件描述符后,如何取回旧的根?
在下面的程序中,我首先打开文件描述符 to /
,然后打开chroot(2)
to.
和chdir(2)
to /
。
但是,如果我然后chdir(2)
到旧根目录fd
,Python 会抱怨它无法打印当前工作目录getcwd()
,因为它不存在。
为什么我无法将当前工作目录更改为旧根目录并打印?
这就是为什么我们有“pivot_root()”和“chroot()”,它们都可以用来做你想做的事情。您将新根挂载到其他位置,然后对其进行 chroot(或枢纽根)。然后你执行 'chdir("/")' 将 cwd 也移动到新的根目录中(只有在那时你才“丢失”旧的根目录 - 尽管如果你打开了一些文件描述符,你实际上可以将它找回来到它)。
https://yarchive.net/comp/linux/pivot_root.html
程序:
import os
print(f'cwd: {os.getcwd()}')
fd = os.open('/', os.R_OK, os.X_OK)
os.chroot('.')
os.chdir('/')
print(f'cwd: {os.getcwd()}')
os.chdir(fd)
print(f'cwd: {os.getcwd()}')
输出:
$ sudo python3 chdir_fd.py
cwd: /home/admin/projects/linux-pwn
cwd: /
Traceback (most recent call last):
File "chdir_fd.py", line 14, in <module>
FileNotFoundError: [Errno 2] No such file or directory
答案1
我可以看到三个问题:
您正在使用
chdir(2)
文件描述符。正确的系统调用应该是fchdir(2)
。尽管Python可能足够聪明,可以使用它来
fchdir()
代替。使用后
fchdir(2)
你必须chroot(2)
再次这样你的当前目录又是里面当前的“已知空间”根树。您无法区分结果
getcwd()
。在这两种情况下/
,即使它不一样,你也会得到/
。例如,您可以显示索引节点号(假设它是相同的文件系统,因此比较成立)或其他任何可能不同的内容。
在这里,根据上述更改,我从 debian bullseye/sid chroot 到 LXC Buster 容器的根目录中。我显示两次的内容/etc/debian_version
:
import os
print(f'cwd: {os.getcwd()}')
fd = os.open('/', os.R_OK, os.X_OK)
os.chroot('.')
os.chdir('/')
print(f'cwd: {os.getcwd()}')
debfd=open("/etc/debian_version","r")
print(debfd.read())
debfd.close()
os.fchdir(fd)
os.chroot('.')
print(f'cwd: {os.getcwd()}')
debfd=open("/etc/debian_version","r")
print(debfd.read())
debfd.close()
结果:
root@glasswalker:/var/lib/lxc/buster-amd64/rootfs# /tmp/chrootback.py
cwd: /var/lib/lxc/buster-amd64/rootfs
cwd: /
10.8
cwd: /
bullseye/sid
琐事
可以滥用“未知空间”来逃离chroot()
没有保留了文件描述符。 2005 年的这个页面对此进行了描述:
除了给定代码中的两个问题(其中一个必须添加#include <stdlib.h>
并更正第 62 行中的双引号拼写错误fprintf()
)之外,它在当今的 Debian(当然还有一些 *nixes)上仍然可以正常工作。
根据我的理解,似乎当处于“未知空间”时(即:当西德位于当前之外根)然后我们可以盲目地回到实际的根。