Linux

給定一些文件描述符後,如何在“chroot(2)”之後恢復舊根?

  • March 8, 2021

chroot(2)在給它一些打開的文件描述符後,我怎樣才能找回舊的根?

在下面的程序中,我首先打開一個文件描述符 to /,然後打開chroot(2)to.chdir(2)to /

但是,如果我再到chdir(2)舊根目錄fd,Python 會抱怨它無法列印目前工作目錄getcwd(),因為它不存在。

為什麼我不能將目前工作目錄更改為舊根目錄並列印?

這就是為什麼我們有“pivot_root()”和“chroot()”,它們都可以用來做你想做的事情。您將新根安裝在其他地方,然後將其chroot(或pivot-root)。然後你執行 ‘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

我可以看到三個問題:

  • 您正在使用chdir(2)文件描述符。正確的系統呼叫應該是fchdir(2).

儘管 python 可能足夠聰明,可以fchdir()代替使用。

  • 使用後,fchdir(2)您必須chroot(2)再次使用,以便目前目錄再次位於目前樹的“已知空間”內。
  • 您無法將結果與getcwd(). /在這兩種情況下,即使它不一樣,您也會得到/。例如,您可以顯示 inode 編號(假設它是相同的文件系統,以便進行比較)或其他任何可能不同的內容。

在這裡,通過上面的更改,從 debian Bullseye/sid,我在 LXC buster 容器的根目錄中 chroot。我顯示/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() 在沒有保留文件描述符的情況下,可以濫用“未知空間”來轉義 a 。從 2005 年開始,本頁對此進行了描述:

如何突破 chroot() 監獄

除了給定程式碼中的兩個問題(一個必須在第 62 行添加#include <stdlib.h>和更正雙引號拼寫錯誤fprintf()),它在今天的 Debian 上仍然可以正常工作(當然還有一些 *nixes)。

據我了解,當處於“未知空間”時(即:當cwd位於目前root之外時導致 OP 錯誤的情況),人們可以盲目地回到實際的root

引用自:https://unix.stackexchange.com/questions/638201