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/sh
(chroot
启动的子进程)输出的网络信息。
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
需要执行ps
,ps
依赖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
的确只隔离了根目录,其它内核资源并未涉及。