脱离chroot的枷锁

2015年8月更新

《The Linux Programming Interface》的Chapter 18 Directories and Links提到chroot jail有几个注意点:

  • chroot()不改变工作目录。因此通常在调用chroot()之后会紧跟chdir("/"),把工作目录设定到新的root;否则仍可使用工作目录访问jail外的文件。只是之后访问jail外的文件不可以用绝对路径了,因为root目录还在jail里。
  • 可以使用jail外文件的文件描述符脱离jail,使用fchdir()即可改变工作目录到jail外。如果是特权进程的话(精确地,指拥有CAP_SYS_CHROOT权限),还可以在fchdir()后使用chroot(".")以把root目录设置到jail外。倘若多chdir("..")几次,可以回到原先的root目录。
  • Unix domain socket提供了进程间传递文件描述符的方法。限定在chroot jail内的进程可以从外部获取文件描述符,之后即可fchdir()使工作目录脱离jail。

下面的例子展示如何使用jail外的文件描述符脱离jail:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
int fd = open(".", O_RDONLY), i; // jail外的文件描述符,供之后脱离
mkdir("tempdir", 0755);
if (fd == -1) return 1;
if (chroot("tempdir") == -1) return 1; // chroot
if (fchdir(fd) == -1) return 1; // 脱离
for (i = 0; i < 1024; i++) // 回到原先的root目录。这里不能使用绝对路径`/`,只能逐步上移
chdir("..");
if (chroot(".") == -1) return 1; // 若是特权进程,则可进一步,把root设回去;不是的话也足以访问jail外的文件
system("ls");
return 0;
}