设备白名单控制器
1. 描述
实现一个 cgroup 来跟踪和强制设备文件的打开和 mknod 限制。设备 cgroup 将设备访问白名单与每个 cgroup 关联起来。白名单条目有 4 个字段。'type' 是 (all)、c (字符) 或 b (块)。'all' 表示它适用于所有类型和所有主次编号。主次编号可以是整数,也可以是 * 表示所有。访问是 r (读)、w (写) 和 m (mknod) 的组合。
根设备 cgroup 从 'all' 开始具有 rwm。子设备 cgroup 获取父级的副本。管理员可以从白名单中移除设备或添加新条目。子 cgroup 永远不会接收被其父级拒绝的设备访问。
2. 用户界面
使用 devices.allow 添加条目,使用 devices.deny 移除条目。例如:
echo 'c 1:3 mr' > /sys/fs/cgroup/1/devices.allow
允许 cgroup 1 读取和 mknod 设备,通常被称为 /dev/null。执行:
echo a > /sys/fs/cgroup/1/devices.deny
将移除默认的 'a : rwm' 条目。执行:
echo a > /sys/fs/cgroup/1/devices.allow
将添加 'a : rwm' 条目到白名单中。
3. 安全性
任何任务都可以在 cgroup 之间移动。这显然是不够的,但随着人们对此有了一些经验,我们可以决定适当限制移动的最佳方式。我们可能只想要求 CAP_SYS_ADMIN,至少这是与 CAP_MKNOD 不同的一个单独的位。我们可能只想拒绝移动到不是当前 cgroup 的后代的 cgroup。或者我们可能想使用 CAP_MAC_ADMIN,因为我们确实正在尝试锁定 root。
需要 CAP_SYS_ADMIN 来修改白名单或将另一个任务移动到新的 cgroup。(再次,我们可能会想要更改这一点)。
cgroup 不得被授予比其父 cgroup 更多的权限。
4. 层次结构
设备 cgroup 通过确保 cgroup 永远不具有比其父级更多的访问权限来维护层次结构。每当向 cgroup 的 devices.deny 文件写入条目时,所有子级将从其白名单中移除该条目,并重新评估所有本地设置的白名单条目。如果本地设置的白名单条目中有一个比 cgroup 的父级提供更多访问权限的条目,它将从白名单中移除。
示例:
A / \ B 组 行为 异常 A 允许 "b 8:* rwm", "c 116:1 rw" B 拒绝 "c 1:3 rwm", "c 116:2 rwm", "b 3:* rwm"
如果在组 A 中拒绝了一个设备:
echo "c 116:* r" > A/devices.deny
它将向下传播,在重新验证 B 的条目后,白名单条目 "c 116:2 rwm" 将被移除:
组 白名单条目 被拒绝的设备 A all "b 8:* rwm", "c 116:* rw" B "c 1:3 rwm", "b 3:* rwm" 所有其余设备
如果父级的异常更改,本地异常不再允许,它们将被删除。
请注意,新的白名单条目不会被传播:
A / \ B 组 白名单条目 被拒绝的设备 A "c 1:3 rwm", "c 1:5 r" 所有其余设备 B "c 1:3 rwm", "c 1:5 r" 所有其余设备
当添加 c *:3 rwm 时:
echo "c *:3 rwm" > A/devices.allow
结果为:
组 白名单条目 被拒绝的设备 A "c *:3 rwm", "c 1:5 r" 所有其余设备 B "c 1:3 rwm", "c 1:5 r" 所有其余设备
但现在可以向 B 添加新条目:
echo "c 2:3 rwm" > B/devices.allow echo "c 50:3 r" > B/devices.allow
甚至:
echo "c *:3 rwm" > B/devices.allow
通过向 devices.allow 或 devices.deny 写入 'a' 来允许或拒绝所有将不再可能,一旦设备 cgroup 具有子级。
4.1 层次结构(内部实现)
设备 cgroup 在内部使用行为(允许、拒绝)和异常列表来实现。内部状态使用相同的用户界面来控制,以保持与先前仅白名单实现的兼容性。向下传播将删除或添加减少对设备访问的异常。对于每个传播的异常,将根据当前父级的访问规则重新评估有效规则。