Linux Cgroup与Device Whitelist详解
第一部分:Cgroup 是什么?
Cgroup 是 Control Group 的缩写。它的核心功能是:对一组进程及其未来创建的子进程进行资源限制、隔离和统计。
你可以把它想象成一个“管理员”,这个管理员可以给不同的“进程组”(比如“前端服务组”、“数据库组”、“用户A的容器组”)分配固定的资源配额,防止某个组占用过多资源而影响到其他组,甚至整个系统。
Cgroup 主要管理和限制以下几类资源:
-
CPU:限制进程组可以使用多少 CPU 时间片(
cpu
子系统)或核心(cpuset
子系统)。 -
内存:限制进程组可以使用的最大内存量,包括物理内存和交换分区。
-
I/O:限制进程组的磁盘读写带宽或 IOPS(每秒读写次数)。
-
网络:虽然传统 Cgroup 不直接管理网络,但可以通过
net_cls
给进程组的网络包打上标签,再结合tc
等工具进行流量控制。 -
设备访问:这就是我们下面要讲的
Device Whitelist Controller
所负责的。
Cgroup 的层次结构:
Cgroup 采用树形层次结构。系统有一个根 Cgroup,下面可以创建子 Cgroup,子 Cgroup 可以继续划分。子 Cgroup 会继承父 Cgroup 的某些属性,并且其资源限制不能超过父 Cgroup。
为什么 Cgroup 如此重要?
它是现代容器技术(如 Docker、LXC、Kubernetes)的基石之一。当你运行一个 Docker 容器时,Docker 会为这个容器创建一个或多个 Cgroup,来限制容器能使用的 CPU、内存等资源,从而实现多个容器在同一台主机上安全、隔离地运行。
第二部分:Device Whitelist Controller(设备白名单控制器)是干嘛用的?
参考链接:Device Whitelist Controller — The Linux Kernel documentation
Device Whitelist Controller
是 Cgroup 众多子系统(或叫控制器)中的一个,它的名字通常简写为 cgroup devices
或对应的文件系统条目是 devices
。
它的核心功能非常简单且强大:控制一个 Cgroup 内的进程可以访问哪些设备节点。
在 Linux 中,一切皆文件,硬件设备也不例外(如 /dev/sda1
、/dev/kvm
、/dev/dri/card0
等)。默认情况下,一个进程如果有足够的文件系统权限,它就可以访问这些设备文件,从而操作底层硬件。
Device Whitelist Controller 的作用就是打破这个默认规则,实现更细粒度的设备访问控制。
它是如何工作的?—— “白名单” 机制
它遵循 “默认拒绝,显式允许” 的原则。
-
默认情况:当一个 Cgroup 被创建时,如果没有进行任何配置,其内部的进程默认无法访问任何设备节点。这是一个非常严格的安全策略。
-
配置白名单:系统管理员需要显式地在这个 Cgroup 的配置文件中写入规则,明确“允许” 该 Cgroup 内的进程访问哪些设备。
-
规则生效:配置完成后,该 Cgroup 内的进程就只能访问规则中明确允许的设备,其他所有设备的访问都会被内核拒绝(即使进程是以
root
身份运行的)。
如何配置?
主要通过操作 Cgroup 文件系统中 devices
子系统下的几个文件:
-
devices.allow
:写入允许访问的规则。 -
devices.deny
:写入拒绝访问的规则(在白名单模式下较少使用)。 -
devices.list
:列出当前生效的规则。
规则格式:
<type> <major>:<minor> <access>
-
<type>
:-
a
:代表 All,所有类型(字符设备和块设备)。 -
c
:代表 Character,字符设备。 -
b
:代表 Block,块设备。
-
-
<major>:<minor>
:设备的主设备号和次设备号。可以用a
来表示所有设备(即*:*
)。 -
<access>
:访问权限。-
r
:读权限。 -
w
:写权限。 -
m
:创建设备节点的权限(mknod)。
-
举个例子:
假设我们有一个 Cgroup 路径:/sys/fs/cgroup/devices/container_a/
-
查看当前规则:
bash
cat /sys/fs/cgroup/devices/container_a/devices.list
(初始状态下可能为空,意味着所有访问都被拒绝)
-
允许访问所有设备(通常用于特权容器,但很不安全):
bash
echo "a *:* rwm" > /sys/fs/cgroup/devices/container_a/devices.allow
-
更安全的做法:只允许访问空设备(/dev/null)和零设备(/dev/zero):
bash
# 首先,清除所有规则(如果需要的话,通常从一个干净的状态开始) # echo "a *:* rwm" > devices.deny # 这会拒绝所有,但默认就是拒绝的# 允许访问 /dev/null (字符设备,主次设备号为 1:3) echo "c 1:3 rwm" > /sys/fs/cgroup/devices/container_a/devices.allow# 允许访问 /dev/zero (字符设备,主次设备号为 1:5) echo "c 1:5 rwm" > /sys/fs/cgroup/devices/container_a/devices.allow# 现在再查看规则列表 cat /sys/fs/cgroup/devices/container_a/devices.list
输出会是:
text
c 1:3 rwm c 1:5 rwm
现在,
container_a
这个 Cgroup 里的进程只能读写/dev/null
和/dev/zero
,尝试访问/dev/sda1
等设备都会失败。
总结与关系
特性 | Cgroup(控制组) | Device Whitelist Controller(设备白名单控制器) |
---|---|---|
角色 | 资源管理的框架/管理者 | Cgroup 框架下的一个具体功能模块 |
目的 | 限制和隔离进程组的资源(CPU、内存、IO等) | 限制和隔离进程组对设备文件的访问 |
关系 | 整体 | 部分(子系统) |
重要性 | 容器技术的基石,实现资源隔离 | 容器安全的关键,防止容器内的进程逃逸并访问宿主机敏感硬件 |
简单来说:
-
Cgroup 是一个大管家,负责给不同的“家庭”(进程组)分配预算(CPU、内存等)。
-
Device Whitelist Controller 是这个大管家手下一个专门管“钥匙”的保安。它决定每个“家庭”的成员可以进入哪些“房间”(设备),其他的房间一律禁止入内。
在 Docker 等容器引擎中,当你使用 --device
参数来将宿主机设备挂载到容器内时,或者当你使用 --privileged
参数时,底层就是在操作这个 Cgroup 的 devices
子系统,来动态地修改容器的设备访问白名单。