chroot

介绍chroot使用方法

Posted by Cheney.Yin on March 15, 2022

chroot

1 什么是chroot

chroot是在Unix和Linux系统的一个操作,针对正在运作的软件进程和子进程,改变其外显的根目录。由chroot设置根目录的程序是不能够对这个指定根目录之外的文件进行访问、读取、更改。

2 实例

这里,使用现成的busybox镜像来创建一个系统的基础文件目录,其中包含了一些常用的二进制文件。

1
2
3
4
5
6
7
8
# 创建rootfs目录
mkdir rootfs

# 将busybox image的目录文件打包进压缩文件
docker export $(docker create busybox) -o busybox.tar

# busybox文件解压至rootfs
tar -xvf ./busybox.tar -C ./rootfs

操作完成后,进入rootfs目录,目录下会出现类似宿主系统的目录和文件。

1
2
ls ./
bin  dev  etc  home  proc  root  sys  tmp  usr  var
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
❯ tree -L 2 ./
./
├── bin
│   ├── [
│   ├── [[
│   ├── acpid
│   ├── addgroup
│   ├── add-shell
│   ├── adduser
......
├── dev
│   ├── console
│   ├── pts
│   └── shm
├── etc
│   ├── group
│   ├── hostname
│   ├── hosts
│   ├── localtime
│   ├── mtab -> /proc/mounts
│   ├── network
│   ├── passwd
│   ├── resolv.conf
│   └── shadow
├── home
├── proc
├── root
├── sys
├── tmp
├── usr
│   └── sbin
└── var
    ├── spool
    └── www

下面可以通过chroot切换至准备好的根目录,并启动/bin/sh

1
sudo chroot ./ /bin/sh

执行完毕后,查看根目录,可以看到根目录已经变成了busybox根目录。

/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var

此刻,进程/bin/sh已经与它的父进程在目录空间上隔离开了。

3 chroot的隔离局限性

上文,已经提到chroot可以改变进程的根目录,那么其它内核资源(如网络、PID等)是否隔离?

如下是在/bin/shchroot启动的子进程)输出的网络信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eno1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel qlen 1000
    link/ether c4:34:6b:02:34:dd brd ff:ff:ff:ff:ff:ff
3: wlo1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq qlen 1000
    link/ether 00:71:cc:22:cc:bb brd ff:ff:ff:ff:ff:ff
    inet 192.168.2.142/24 brd 192.168.2.255 scope global dynamic noprefixroute wlo1
       valid_lft 42010sec preferred_lft 42010sec
    inet6 fe80::5ce6:a689:8d04:a0b3/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

如下实在宿主系统下输出的网络信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
❯ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eno1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    link/ether c4:34:6b:02:34:dd brd ff:ff:ff:ff:ff:ff
    altname enp14s0
3: wlo1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:71:cc:22:cc:bb brd ff:ff:ff:ff:ff:ff
    altname wlp7s0f0
    inet 192.168.2.142/24 brd 192.168.2.255 scope global dynamic noprefixroute wlo1
       valid_lft 41641sec preferred_lft 41641sec
    inet6 fe80::5ce6:a689:8d04:a0b3/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

通过对比,可以发现网络没有隔离。

接下来,对比PID有没有隔离。由于/bin/sh需要执行psps依赖procfs,所以需要先挂载/proc目录,操作命令如下。

mount -t proc proc /proc

执行ps命令后,可以看到全部宿主系统的进程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PID   USER     TIME  COMMAND
    1 root      0:01 {systemd} /sbin/init
    2 root      0:00 [kthreadd]
    3 root      0:00 [rcu_gp]
    4 root      0:00 [rcu_par_gp]
    8 root      0:00 [mm_percpu_wq]
    ......
13806 1000      0:00 alacritty
13808 1000      0:01 /usr/bin/zsh
13817 1000      0:00 /usr/bin/zsh
13910 1000      0:00 /usr/bin/zsh
13911 1000      0:00 /usr/bin/zsh
13913 1000      0:00 /usr/share/zsh-theme-powerlevel10k/gitstatus/usrbin/gitstatusd
13945 root      0:00 [kworker/0:1H]
13954 root      0:00 ps

综上,chroot的确只隔离了根目录,其它内核资源并未涉及。