Linux中的BPF安全
BPF安全“安全”一词涵盖了广泛的任务:
[*]安全分析
[*]用于实时取证的嗅探活动
[*]权限调试
[*]可执行文件的白名单
[*]对恶意软件的逆向工程
[*]监控
[*]定制化审计
[*]基于主机的入侵检测体系(HIDS)
[*]基于容器的入侵检测体系(CIDS)
[*]策略执行
[*]网络防火墙
[*]检测恶意软件,动态阻塞数据包以及其他入侵行为
安全工程与性能工程相类似,这两者都与要对各种大量差别的软件进行分析。
盘算机的安全概括了三个特性,私密性(Confidentiality)、 完整性(Integrity)、可用性(Availability),简称 CIA。
[*]私密性就是数据不被未授权的人看到
[*]完整性是指存储或传输的信息不被篡改
[*]可用性是指本身的设备在必要使用的时候能够使用
盘算机体系应对安全挑战的方法主要有四种:隔离,控制,审计,混淆
BPF在安全方面可以做什么
BPF可以帮助完成下面的安全任务,包括分析,监控,策略执行。
安全分析
BPF可以复兴的问题包括:
[*]正在被执行的历程有哪些?
[*]什么网络链接正在被创建,来自哪个历程?
[*]什么体系权限正在被哀求,被谁人历程哀求?
[*]体系内正在发生哪些权限拒绝错误?
[*]是否在以给定参数调用当前内核函数和用户态函数(检测实时入侵行为)?
也可以根据可跟踪的目标列表来总结BPF跟踪的分析和监视功能。
https://i-blog.csdnimg.cn/direct/3ff49b02928d4db18754fb67c71a6eea.png
安全监控
BPF跟踪程序可以用于安全监控和入侵检测。当前的监控方案通常使用可加载内核模块来观测内核和数据包事件。然而,这些模块本身也引入了内核错误和漏洞的风险。BPF程序自带验证程序,并使用现有的内核技术。相比来说也更加安全。
BPF跟踪还针对效率进行优化。
BPF监控的一个重要行为特点是在极高工作负载下的行为设计。BPF输出缓冲区射表大小有限定,如果达到了这些上限,某些事件大概会被忽略。这可以被攻击者所使用,可以创造海量事件沉没体系,从而逃避得当的日记纪录或策略执行。当这些限定被超过时BPF会收到关照,并且可以汇报到用户态以接纳符合的措施。任何基于BFF跟踪构建的安全方案都必要纪录这些溢出和事件缺失的情况,以满足“不可反悔”(Non-repudiation)的设计要求。
linux中的BPF和安全
BPF程序附加到Linux安全模块(LSM)钩子(也称为BPF-LSM)的本领是内核的一个新添加的功能,正在被用于“防止有趣的安全攻击”。和别的类型的BPF程序一样,可以附加到LSM钩子(或体系调用)的BPF程序具有与跟踪,网络或其他程序类型差别的特定功能。这些程序可以读取恣意的内核数据并拒绝操纵,但它们也可以休眠,这是 BPF 程序的新特性。这意味着如果它们访问的用户空间地址已被换出,程序大概会引发一个小故障,因此不大概通过引用已换出的内存来规避这些钩子。
安全可观察性必要策略和背景
安全工具和报告事件的可观察行工具的区别在于,安全工具必要能够区分正常情况下的预期事件和大概正在发生恶意活动的事件。
策略不仅要考虑体系正常运行时的正常行为,还要考虑预期的错误路径行为。例如,如果物理磁盘满了,应用程序大概会开始发送网络信息,提醒用户注意。
定义什么是预期行为,什么非预期行为是策略的工作。安全工具会将活动和策略进行比较,并在活动超出策略范围,变得可疑是接纳一些举措。这些举措通常包括生成安全事件日记,该日记通常会被发送到安全信息事件管理平台。大概会向职员发出警报,要求调查所发生的事件。调查的时候上下文信息越多肯定越大概找失事件的根本原因,并确定这是否是一次攻击,哪些组件受到了影响,攻击是怎样产生的,何时发生的以及谁对此负责。这就必要工具从单纯的日记纪录转变为名副其实的“安全可观察性”。
https://i-blog.csdnimg.cn/direct/997a4d9051b9417bb69b8ec62aeb0584.png
方法和工具
eBPF程序用于检测和执行安全事件的一些方法。
eBPF程序可以附加到各种事件上,但是多年来用于安全的一组事件是体系调用。体系调用并不是使用eBPF实现安全工具最有效的方法。
使用体系调用处理安全事件
体系调用是用户空间应用程序与内核之间的接口。如果能限定一个应用程序所能使用的体系调用,就能限定它所能做的事情。
体系调用限定工具Seccomp
seccomp 是 "安全盘算(SECure COMPuting)"的缩写。在其原始或 “严格” 模式下,seccomp 用于将历程可使用的体系调用限定为一个很小的子集:read()、write()、_exit() 和 sigreturn()。严格模式的目的是允许用户运行不受信托的代码,但是不能让这些代码做恶意的事情。
严格模式的限定性很强,有的应用程序都必要很大的体系调用集,但这个应用程序不大概必要全部的体系调用。所以,接纳这中灵活的方式来限定任何特定应用程序可以使用的调用集是故意义的。
seccomp模式没有使用其允许的固定体系调用子集,而是使用BPF代码来过滤允许和不允许的体系调用,常用在容器范畴,称为seccomp-bpf更为适当。
在 seccomp-bpf 中,加载了一组充当过滤器的 BPF 指令。每次调用体系调用时,都会触发过滤器。过滤器代码可以访问传递给体系调用的参数,以便它可以根据体系调用本身和传递给它的参数做出决策。效果是一组大概的举措之一,包括:
[*]允许体系调用继续进行
[*]将错误代码返回给用户空间应用程序
[*]杀死线程
[*]关照用户空间应用程序 (seccomp-unotify)(从内核版本 5.0 开始)
体系调用跟踪安全工具(Syscall-Tracking Security Tools)
最著名的就是Falco,他提供安全警报,在默认情况下,Falco是作为内核模块安装的,但是也有eBPF版本,用户可以订定规则来确定哪些事件和安全有关,当发生与规则中定义的策略不符的事件时,Falco可以生成各种格式的警报。
由于 eBPF 程序可以动态加载,并能检测由已有历程触发的事件,因此 Falco 等工具可将策略应用于已在运行的应用程序工作负载。用户可以修改所应用的规则集,而无需修改应用程序或其设置。这与 seccomp 设置文件形成鲜明对比,后者必须在应用程序历程启动时应用。
问题就是当eBPF程序在体系调用入口点被触发时,它可以访问用户空间传递给该体系调用参数,如果这些参数是指针,内核在对这些数据进行操纵之前必要将指向的数据复制到本身的数据结构中。问题就出在eBPF程序查抄数据之后,内核复制之前,攻击者是有机会修改该数据的。因此,执行体系调用的数据大概与eBPF程序捕获的数据差别。
https://i-blog.csdnimg.cn/direct/b9424f585dd94052a237a7c196061278.png
为了确保查抄的信息和内核执行的信息一致,eBPF程序应该附加到参数复制到内核内存后发生的事件。但是由于体系调用代码对数据处理方式差别,内核中没有一个共同的位置来完成这项工作。
不过有一个定义明确的接口可以安全的附加到eBPF程序,Linux安全模块(LSM)API。这就必要一个相对较新的eBPF功能:BPF LSM。
BPF LSM
这个值得好好的研究一下。
LSM接口提供了一组钩子,每个钩子都在内核即将对内核数据结构进行操纵之前触发。钩子调用的函数可以决定是否允许操纵继续进行。该接口最初是为了允许安全工具以内核模块的形式实现而提供的;BPF LSM对此进行扩展,以便eBPF程序可以附加到相同的挂钩点。使用 LSM BPF,eBPF 程序可由 LSM 钩子事件触发
https://i-blog.csdnimg.cn/direct/7c863c35616c488898041441ef5ba88d.png
值得一提的是,体系调用和LSM挂钩并不是一一对应的,如果某个体系调用有大概从安全角度做一些有趣的事情,那么处理该体系调就会触发一个或多个挂钩。
LSM框架介绍
LSM(linux Security Module)中文翻译就是内核安全模块,从名字上来看是安全模块,其实LSM是一个在内核各个安全模块的根本上抽象出的,轻量级安全访问控制框架。该框架只是提供一个支持安全模块的接口,本身并不具备增加体系安全性的功能,详细的工作还是交给各个安全模块来做。
通俗一点来说,LSM只是搭建了一个舞台,详细的演出还是要详细实现的模块。
LSM在内核中主要体现为一组安全相干的函数,是提供实行强制访问控制(MAC)模块的须要组件。可实现策略与内核源代码解耦,
安全函数在体系调用的执行路径中被调用,对用户态历程访问的内核资源对象进行强制访问控制,受掩护的对象包括许多。
截止到内核5.7版本,一共有九个安全模块的实现,SELinux、SMACK、AppArmor、TOMOYO、Yama、LoadPin、SafeSetID 和 Lockdown 和 BPF(5.7 版本支持) 。
https://i-blog.csdnimg.cn/direct/9abe03c547fa4227b0faa135e32936d8.png
Seccomp和LSM都可以实现内核级别的限定历程和体系的交互方式,但是安全盘算模式(seccomp)是关于限定历程可以进行的体系调用,相比之下,LSM是关于限定对内核中对象的访问。
LSM框架
LSM框架提供了一个模块化的架构,该架构提供了内置于内核的“钩子”(hook),并允许安装安全模块,从而增强访问控制。
https://i-blog.csdnimg.cn/direct/c207ac255a9b4c8c866ea704c13cbac0.png
主要是由五部分组成:
[*]在关键的特定内核数据结构中参加了安全域。
[*]在内核源码中差别的关键点中插入对安全钩子函数的调用。
[*]提供了一个通用的安全体系调用,允许安全模块为安全相干的应用编写新的体系调用。
[*]提供了从之策注销函数,使得访问控制策略可以以内核模块的方式实现,主要是通过security_add_hooks 和 security_delete_hooks;
[*]将capabilities逻辑的大部分移植到一个可选的安全模块
详细实现上,LSM框架通过提供一系列的Hook,钩子函数来控制对内查对象的操纵,其本质就是插桩法。
举个例子,文件open函数的访问过程。
https://i-blog.csdnimg.cn/direct/c02e1bb94b3e44eab07ff72ae6060bf1.png
[*]通过体系调用进入内核后,体系首先进行错误查抄。
[*]错误查抄通过之后,就是DAC查抄,就是传统的权限查抄吗,也就是自主访问控制。
[*]通过之后才会进行强制访问控制MAC,强制访问控制是不允许主题干涉的一种访问控制,接纳安全标识,信息分级等信息敏感性进行访问控制,并通过比较主题的级别和敏感性来确定是否允许访问。
LSM中的钩子函数
详细可见下面的源码分析。
LSM BPF
在LSM BPF出现之前,能够实行安全策略目标的方式主要就是两种:设置现有的安全模块,或自定义的编写内核模块。LSM BPF提供了第三种可以实现的方案,灵活且安全,并具有可编程性。
在内核5.7版本中引入了在LSM中提供对BPF的支持。使用 LSM BPF,开发职员能够在无需设置或加载内核模块的情况下编写精致策略。LSM BPF 程序会在加载时进行验证,然后在调用路径中到达 LSM hook 时执行。
详细可见下面的源码分析。
Cilium Tetragon
Tetragon是Cilium项目的一部分。主要是创建一个框架,将eBPF程序附加到Linux内核中的恣意函数上,而不是附加到LSM API钩子上。主要设计与Kubernets环境,用于定义eBPF程序应附加的一组事件,eBPF代码必要查抄的条件以及满足条件是应接纳的举措。
和LSM BPF程序一样,Tetragon程序也会访问上下文信息,从而完全在内核中做出决定。与项用户空间报告所特定类型事件差别,安全相干事件也可以在内核中进行过滤,只是超出策略范围的事件才会向用户空间报告。
大多数的eBPF安全工具都是使用eBPF程序来检测恶意事件,这些事件会关照用户空间应用程序,然后该应用程序可以接纳举措。
https://i-blog.csdnimg.cn/direct/f33523ebd4284b44abce7466210f425f.png
用户空间应用程序执行的任何操纵都是异步发生的,到那时大概为时已晚——大概数据大概已被泄露,或者攻击者大概已将恶意代码持久保存到磁盘上。从内核到用户空间的异步关照允许攻击有一定的事件继续进行。
在5.3以及更高的内核版本中,有一个名为 bpf_send_signal() 的 BPF 辅助函数。Tetragon使用这个功能进行预防性安全。如果策略定义了Sigkill操纵,则任何匹配事件都将导致Tetragon eBPF代码生成SIGKILL信号,该信号将终止尝试超出策略操纵的历程。
https://i-blog.csdnimg.cn/direct/e9344bc778f44c6e96baaa7d66fc77b1.png
也就是说,内核正在执行的,被eBPF代码判定为超出策略的活动将被制止完成。但是设置不准确的策略大概会导致不必到的终止应用程序,刚开始可以在“审计(audit)”模式下运行,该模式会生成安全事件,但不会应用SIGKILL强制,直到认为该策列不会破坏任何东西后。
Linux5.15内核中关于安全源码的分析
eBPF验证器(Verifier)
是eBPF安全的核心,确保eBPF程序在运行之前经过静态验证以防止非法访问内存或执行不安全的操纵。
int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr)
{
u64 start_time = ktime_get_ns(); // 获取验证器开始时间,用于计算验证时间
struct bpf_verifier_env *env; // 定义验证器环境
struct bpf_verifier_log *log; // 定义日志
int i, len, ret = -EINVAL; // 初始化一些变量
bool is_priv; // 检查用户是否拥有特权权限
// 为 bpf_verifier_env 分配内存。它包含了程序的验证状态和日志信息
env = kzalloc(sizeof(struct bpf_verifier_env), GFP_KERNEL);
if (!env)
return -ENOMEM; // 如果内存分配失败,返回错误
log = &env->log; // 初始化日志指针
len = (*prog)->len; // 获取程序的指令长度
// 分配内存给每条指令的辅助数据,保存原始索引信息
env->insn_aux_data = vzalloc(array_size(sizeof(struct bpf_insn_aux_data), len));
ret = -ENOMEM;
if (!env->insn_aux_data)
goto err_free_env; // 如果内存分配失败,跳转到清理部分
for (i = 0; i < len; i++)
env->insn_aux_data.orig_idx = i; // 初始化每条指令的原始索引
env->prog = *prog; // 将程序指针赋值给验证环境
env->fd_array = make_bpfptr(attr->fd_array, uattr.is_kernel); // 生成文件描述符数组指针
is_priv = bpf_capable(); // 检查是否具有执行 eBPF 的权限
// 初始化验证器状态
mark_verifier_state_clean(env);
// 处理 BPF_LD_IMM64 伪指令,这是将立即数加载到寄存器的特殊指令
ret = resolve_pseudo_ldimm64(env);
if (ret < 0)
goto skip_full_check; // 如果处理失败,跳转到后续部分
// 检查程序的控制流图,确保它是合法的
ret = check_cfg(env);
if (ret < 0)
goto skip_full_check; // 如果控制流检查失败,跳过后续的完整检查
// 验证子程序(如果有的话)模拟整个运行过程,特别是对于指针访问的每个细节进行检查
ret = do_check_subprogs(env); //!!!!!这里就是经常编写ebpf程序容易报错的地方
ret = ret ?: do_check_main(env); // 验证主程序
skip_full_check:
// 释放在验证期间分配的状态表内存
kvfree(env->explored_states);
// 优化程序中的循环结构
if (ret == 0)
ret = optimize_bpf_loop(env);
// 如果用户有特权,移除程序中的死代码
if (is_priv) {
if (ret == 0)
ret = opt_remove_dead_code(env);
} else {
// 如果没有特权,只清理死代码(不移除)
if (ret == 0)
sanitize_dead_code(env);
}
// 转换上下文中的特定访问,如对网络包字段的访问
if (ret == 0)
ret = convert_ctx_accesses(env);
// 修正函数调用参数,确保其合法性
if (ret == 0)
ret = fixup_call_args(env); //将调用指令call 6 调整为真实的函数地址
// 记录验证所花费的总时间
env->verification_time = ktime_get_ns() - start_time;
err_free_env:
// 清理分配的验证器环境
kfree(env);
return ret;
}
下面的代码是定义ebpf验证器的环境结构,提供跟踪和管理eBPF程序验证过程
struct bpf_verifier_env {
u32 insn_idx;// 当前正在验证的 BPF 指令的索引,指向程序中当前处理的指令位置
u32 prev_insn_idx;// 上一条被处理的指令索引,用于在指令之间进行跳转时进行状态回溯。
struct bpf_prog *prog;// 指向正在验证的 eBPF 程序结构体。该结构体包含了 BPF 程序的字节码、程序类型和辅助信息。
const struct bpf_verifier_ops *ops;// 指向 BPF 验证操作的函数指针表,根据不同的 BPF 程序类型(如网络过滤、跟踪等)调用相应的验证逻辑。
struct bpf_verifier_stack_elem *head;// 指向当前待处理的验证状态栈链表的头节点,栈结构存储着不同状态分支的信息。
int stack_size;// 当前验证器状态栈中堆积的状态数量。用于管理并行的分支状态。
bool strict_alignment;// 用于指示是否执行严格的内存对齐检查。如果为真,程序将在某些架构上要求更严格的指针对齐。
bool test_state_freq;// 用于测试验证器在不同修剪频率下的行为,测试时可能改变状态修剪的频率以进行调试。
struct bpf_verifier_state *cur_state;// 当前正在处理的 BPF 验证状态,保存寄存器和栈的状态信息。
struct bpf_verifier_state_list **explored_states;// 已探索的状态列表,用于优化搜索过程以避免重复验证已经处理的状态。
struct bpf_verifier_state_list *free_list;// 空闲状态链表,用于重复利用已经释放的状态,减少内存分配的开销。
struct bpf_map *used_maps;// 保存 eBPF 程序中使用的 BPF map 的数组,最大数量由 `MAX_USED_MAPS` 定义。
struct btf_mod_pair used_btfs;// 保存 eBPF 程序使用的 BTF(BPF Type Format)对象的数组,最大数量由 `MAX_USED_BTFS` 定义。
u32 used_map_cnt;// 当前验证过程中使用到的 BPF map 的数量。
u32 used_btf_cnt;// 当前验证过程中使用到的 BTF 对象数量。
u32 id_gen;// 用于生成唯一寄存器 ID 的计数器,每次生成新的寄存器时该值递增。
bool explore_alu_limits;// 标志是否对 ALU (算术逻辑单元) 的边界进行探索和检查,通常用于确保边界检查的安全性。
bool allow_ptr_leaks;// 是否允许指针泄露。如果为真,验证器将允许程序在某些条件下访问潜在的指针泄露。
bool allow_uninit_stack;// 是否允许未初始化的栈空间访问。若为真,则可以访问未初始化的栈,但这可能引入风险。
bool allow_ptr_to_map_access;// 是否允许直接通过指针访问 BPF map。如果为真,验证器将允许通过指针访问 map 元素。
bool bpf_capable;// 表示当前用户是否有能力执行 eBPF 程序。通常与内核权限或安全模块相关联。
bool bypass_spec_v1;// 标志是否绕过 CPU 的第一版旁路漏洞防护机制(例如 Spectre v1),用于加速验证过程。
bool bypass_spec_v4;// 标志是否绕过 CPU 的第四版旁路漏洞防护机制(例如 Spectre v4)。
bool seen_direct_write;// 记录在验证过程中是否遇到直接的内存写操作。这有助于判断程序是否尝试修改内存中的关键数据。
struct bpf_insn_aux_data *insn_aux_data;// 每条 BPF 指令的辅助状态数据数组,保存该指令的附加信息,例如原始索引等。
const struct bpf_line_info *prev_linfo;// 保存前一条指令的调试信息(如行号、文件名等),用于生成调试日志。
struct bpf_verifier_log log;// 用于保存验证器输出的日志信息,日志可以包括验证失败的详细原因,帮助开发者调试。
struct bpf_subprog_info subprog_info;// 保存子程序信息的数组,BPF 程序可能包含多个子程序,这些子程序的信息存储在此数组中。
struct bpf_id_pair idmap_scratch;// 用于 ID 映射的临时缓存,通常在处理寄存器或状态 ID 时使用。
struct {
int *insn_state;// 控制流图(CFG)中每条指令的状态数组。
int *insn_stack;// 控制流图中每条指令的栈状态数组。
int cur_stack;// 当前指令的栈状态指针,用于跟踪栈指针的变化。
} cfg;// 存储控制流图相关的状态信息,用于分析程序的控制流结构。
u32 pass_cnt;// `do_check()` 函数被调用的次数,表示验证器已经遍历指令的次数。
u32 subprog_cnt;// 当前程序中子程序的数量,BPF 程序可以有多个子程序,每个子程序都会单独验证。
u32 prev_insn_processed, insn_processed;// `insn_processed` 保存总共分析的指令数量,`prev_insn_processed` 保存之前阶段分析的数量,供增量统计使用。
u32 prev_jmps_processed, jmps_processed;// `jmps_processed` 保存总共分析的跳转、调用、退出指令数量, `prev_jmps_processed` 保存之前阶段处理的数量,供增量统计使用。
u64 verification_time;// 用于保存整个验证过程所耗费的时间,以纳秒为单位。
u32 max_states_per_insn;// 在处理分支指令时,保存最大可能存储的状态数量。这限制了状态分支的数量,防止内存消耗过大。
u32 total_states;// 保存分配的验证状态总数量,表示在整个程序验证过程中分配的状态数量,反映内存使用情况。
u32 peak_states;// 验证过程中状态的峰值数量,代表最大状态并行的规模,该值通常会影响内存消耗。
u32 longest_mark_read_walk;// 在 liveness 标记过程中,走过的最长寄存器链条。用于分析寄存器的使用情况。
bpfptr_t fd_array;// 指向文件描述符数组的指针,通常在验证过程中用于处理用户空间与内核空间的交互。
char type_str_buf;// 用于在调试和日志中生成寄存器类型的字符串表示,保存生成的寄存器类型描述。
};
LSM Hook点
LSM 在内核中袒露了一系列 hook 点,用于监控历程、文件、网络等操纵的安全策略。
LSM背后的核心概念就是LSM钩子,LSM钩子袒露在内核的关键位置,可通过挂钩进行管制的操纵示例包括:
[*]文件体系操纵
[*]打开,创建,移动和删除文件
[*]挂载和卸载文件体系
[*]task/process operations 任务/历程操纵
[*]分配和释放任务,更改任务的用户组标识
[*]套接字操纵
[*]创建和绑定套接字
[*]继承发送消息
体系中 LSM 钩子都列在 Linux 内核源码的头文件 include/linux/bpf_lsm.h中查看到。差别的操纵对应场景可通过头部注释获.
* union security_list_options - Linux Security Module hook function list
// 定义了 Linux Security Modules (LSM) 的钩子函数列表,供各个安全模块使用。
* Security hooks for program execution operations.
// 负责程序执行操作的安全钩子。用于在进程执行时进行安全检查,比如是否允许执行某个程序。
* Security hooks for mount using fs_context.
// 挂载文件系统的安全钩子。确保文件系统挂载时遵循权限控制,防止未经授权的文件系统挂载。
* Security hooks for filesystem operations.
// 文件系统操作的安全钩子。用于控制对文件系统的读写、创建和删除操作,确保这些操作符合安全策略。
* Security hooks for inode operations.
// inode 操作的安全钩子。控制对 inode 元数据(如文件权限、所有者等)的访问和修改,保护文件系统安全。
* Security hooks for kernfs node operations
// 用于保护内核文件系统(kernfs)节点操作的安全钩子,确保系统资源管理的安全性。
* Security hooks for file operations
// 文件操作钩子,控制文件的打开、关闭、读写等操作,确保进程只能执行符合安全策略的文件操作。
// Security hooks for task operations.
// 进程任务的安全钩子。用于监控和限制进程的行为,防止进程之间进行不当的交互或访问系统资源。
* Security hooks for Netlink messaging.
// Netlink 消息传递的安全钩子。控制进程间通信,防止未经授权的消息传递或系统配置修改。
* Security hooks for Unix domain networking.
// Unix 域套接字操作的安全钩子。用于本地进程间通信的控制,确保进程间通信符合安全策略。
* Security hooks for socket operations.
// 套接字操作的安全钩子。用于控制网络连接和数据传输的安全策略,防止未经授权的网络访问。
* Security hooks for SCTP
// SCTP(流控制传输协议)操作的安全钩子。用于保护基于 SCTP 协议的网络通信,防止网络层面的攻击。
* Security hooks for Infiniband
// Infiniband 操作的安全钩子。用于保护高性能网络通信(如 Infiniband)的安全性,防止未授权的操作。
* Security hooks for XFRM operations.
// XFRM(IPsec 扩展框架)操作的安全钩子。确保加密和解密操作符合系统安全策略,保护网络流量安全。
* Security hooks affecting all Key Management operations
// 密钥管理操作的安全钩子。控制密钥的创建、修改和删除,确保加密密钥的安全使用。
* Security hooks for individual messages held in System V IPC message queues
// 用于控制 System V IPC 消息队列中的每个消息的安全钩子,确保进程间通信的安全性。
* Security hooks for System V IPC Message Queues
// System V 消息队列操作的安全钩子。用于保护进程间通过消息队列进行的通信,防止信息泄露。
* Security hooks for System V Shared Memory Segments
// System V 共享内存段的安全钩子。用于控制进程对共享内存的访问,确保共享内存的安全使用。
* Security hooks for System V Semaphores
// System V 信号量操作的安全钩子。控制进程对信号量的操作,确保进程同步操作符合系统的安全策略。
* Security hooks for Audit
// 审计系统操作的安全钩子。用于生成和控制审计日志,确保安全事件被正确记录。
* Security hooks for the general notification queue:
// 通用通知队列操作的安全钩子。确保进程对通知队列的访问和使用符合安全策略。
* Security hooks for using the eBPF maps and programs functionalities through eBPF syscalls.
// eBPF 映射和程序操作的安全钩子。用于控制 eBPF 程序的加载和执行,防止未经授权的 eBPF 使用。
* Security hooks for perf events
// 性能事件的安全钩子。控制性能监控事件,防止未授权的进程获取系统性能数据。
* Security hooks for io_uring
// io_uring 异步 I/O 操作的安全钩子。用于控制 I/O 操作的安全性,确保异步 I/O 操作不被滥用。
每个定义的钩子函数都包罗对应的参数,这些参数根据哪些程序可以实行策略决策提供上下文。在5.15内核中一共有55个,在6.10内核中增加到了247个。
https://i-blog.csdnimg.cn/direct/5b2bd4484ca74e9081e550615ac3ae01.png
其中 LSM_HOOK 定义格式如下:
LSM_HOOK(<return_type>, <default_value>, <hook_name>, args...)
LSM提供的大多数钩子都会返回一个整数值(也有部分返void,标识忽略运行效果),返回值的定义如下:
[*]0等于同意授权;
[*]ENOMEM无可用内存;
[*]EACCESS,安全策略拒绝访问;
[*]EPERM,执行此操纵必要权限。
LSM BPF
在5.15内核中,BPF自身安全相干的LSM hook函数有7个,在内核security/security.c 中查看通过编译条件宏 CONFIG_BPF_SYSCALL 控制,主要设涉及BPF 体系调用、BPF 程序和 BPF map 相干操纵:
#ifdef CONFIG_BPF_SYSCALL
// 如果内核配置启用了 BPF 系统调用支持(CONFIG_BPF_SYSCALL),则定义以下钩子
// 用于控制 BPF 系统调用的安全钩子。
// `cmd` 表示系统调用的命令类型,`attr` 是 BPF 的参数,`size` 是参数大小。
LSM_HOOK(int, 0, bpf, int cmd, union bpf_attr *attr, unsigned int size)
// 用于控制 BPF 映射的安全钩子。
// `map` 是 BPF 映射对象,`fmode` 是文件操作模式(如只读或可写)。
LSM_HOOK(int, 0, bpf_map, struct bpf_map *map, fmode_t fmode)
// 用于控制 BPF 程序的安全钩子。
// `prog` 是 BPF 程序对象,通过该钩子可以验证 BPF 程序是否符合安全策略。
LSM_HOOK(int, 0, bpf_prog, struct bpf_prog *prog)
// 用于在分配 BPF 映射时执行安全检查的钩子。
// 该钩子可以确保在分配 BPF 映射时,分配过程符合系统的安全策略。
LSM_HOOK(int, 0, bpf_map_alloc_security, struct bpf_map *map)
// 用于在释放 BPF 映射时执行安全处理的钩子。
// `map` 是要释放的 BPF 映射,通过该钩子可清理与映射相关的安全资源。
LSM_HOOK(void, LSM_RET_VOID, bpf_map_free_security, struct bpf_map *map)
// 用于在分配 BPF 程序时执行安全检查的钩子。
// `aux` 是 BPF 程序的辅助信息,钩子确保 BPF 程序的分配过程符合安全要求。
LSM_HOOK(int, 0, bpf_prog_alloc_security, struct bpf_prog_aux *aux)
// 用于在释放 BPF 程序时执行安全处理的钩子。
// `aux` 是与 BPF 程序关联的辅助信息,钩子用于释放与 BPF 程序相关的安全资源。
LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free_security, struct bpf_prog_aux *aux)
#endif /* CONFIG_BPF_SYSCALL */
每个钩子针对特定的BPF操纵提供了对应的安全见查抄和处理机制,确保只有符合安全策略的BPF操纵被允许执行。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]