BPF_PROG_TYPE_CGROUP_SYSCTL

本文档描述了 BPF_PROG_TYPE_CGROUP_SYSCTL 程序类型,该类型为 sysctl 提供 cgroup-bpf 钩子。

该钩子必须附加到 cgroup,并且每当该 cgroup 中的进程尝试从 proc 中的 sysctl 旋钮读取或写入时都会被调用。

1. 附加类型

必须使用 BPF_CGROUP_SYSCTL 附加类型将 BPF_PROG_TYPE_CGROUP_SYSCTL 程序附加到 cgroup。

2. 上下文

BPF_PROG_TYPE_CGROUP_SYSCTL 提供从 BPF 程序访问以下上下文的功能:

struct bpf_sysctl {
    __u32 write;
    __u32 file_pos;
};
  • write 指示 sysctl 值是正在读取 (0) 还是正在写入 (1)。此字段是只读的。

  • file_pos 指示访问 sysctl 时的文件位置(读取或写入)。此字段是读写的。写入此字段会设置 sysctl proc 文件中 read(2) 将从中读取或 write(2) 将写入的起始位置。例如,即使用户空间在 file_pos > 0 时调用 write(2),将零写入此字段也可用于通过 bpf_sysctl_set_new_value() 覆盖整个 sysctl 值。将非零值写入此字段可用于从指定的 file_pos 开始访问 sysctl 值的一部分。并非所有 sysctl 都支持在 file_pos != 0 时进行访问,例如,对数字 sysctl 条目的写入必须始终在文件位置 0。另请参阅 kernel.sysctl_writes_strict sysctl。

有关如何访问上下文字段的更多详细信息,请参阅 linux/bpf.h

3. 返回码

BPF_PROG_TYPE_CGROUP_SYSCTL 程序必须返回以下返回码之一:

  • 0 表示“拒绝访问 sysctl”;

  • 1 表示“继续访问”。

如果程序返回 0,用户空间将从 read(2)write(2) 获得 -1,并且 errno 将设置为 EPERM

4. 辅助函数

由于 sysctl 旋钮由名称和值表示,sysctl 特定的 BPF 辅助函数专注于提供对这些属性的访问:

  • bpf_sysctl_get_name():将 /proc/sys 中可见的 sysctl 名称获取到 BPF 程序提供的缓冲区中;

  • bpf_sysctl_get_current_value():将 sysctl 当前持有的字符串值获取到 BPF 程序提供的缓冲区中。此辅助函数在从 sysctl read(2) 和向 sysctl write(2) 时都可用;

  • bpf_sysctl_get_new_value():在实际写入发生之前,获取当前正在写入 sysctl 的新字符串值。此辅助函数只能在 ctx->write == 1 时使用;

  • bpf_sysctl_set_new_value():在实际写入发生之前,覆盖当前正在写入 sysctl 的新字符串值。sysctl 值将从当前的 ctx->file_pos 开始被覆盖。如果整个值需要被覆盖,BPF 程序可以在调用此辅助函数之前将 file_pos 设置为零。此辅助函数只能在 ctx->write == 1 时使用。通过此辅助函数设置的新字符串值,内核会像处理用户空间传入的等效字符串一样进行处理和验证。

BPF 程序以与用户空间在 proc 文件系统中相同的方式(即作为字符串)看待 sysctl 值。由于许多 sysctl 值表示一个整数或一个整数向量,因此可以使用以下辅助函数从字符串中获取数值:

  • bpf_strtol():将字符串的初始部分转换为长整数,类似于用户空间的 strtol(3)

  • bpf_strtoul():将字符串的初始部分转换为无符号长整数,类似于用户空间的 strtoul(3)

有关此处描述的辅助函数的更多详细信息,请参阅 linux/bpf.h

5. 示例

有关用 C 语言编写的 BPF 程序示例,该程序访问 sysctl 名称和值,解析字符串值以获取整数向量,并使用结果决定是否允许或拒绝访问 sysctl,请参阅 test_sysctl_prog.c

6. 注意事项

BPF_PROG_TYPE_CGROUP_SYSCTL 旨在用于受信任的根环境,例如监控 sysctl 使用情况或捕获在单独 cgroup 中以 root 身份运行的应用程序尝试设置的不合理值。

由于 task_dfl_cgroup(current)sys_read / sys_write 时被调用,它可能返回与 sys_open 时不同的结果,即在 proc 文件系统中打开 sysctl 文件的进程可能与尝试从中读取/写入的进程不同,并且这两个进程可能在不同的 cgroup 中运行,这意味着 BPF_PROG_TYPE_CGROUP_SYSCTL 不应作为限制 sysctl 使用的安全机制。

与任何 cgroup-bpf 程序一样,如果运行在 cgroup 中的应用程序以 root 身份运行,并且不应允许其分离/替换管理员附加的 BPF 程序,则应格外小心。