【云安全系列】eBPF——提高Seccomp防护生产力

admin 2023年1月23日22:01:19评论164 views字数 4291阅读14分18秒阅读模式

【云安全系列】eBPF——提高Seccomp防护生产力


1.eBPF简介

【云安全系列】eBPF——提高Seccomp防护生产力

1.1 BPF

BPF(Berkeley Packet Filter ),中文翻译为伯克利包过滤器,是类 Unix 系统上数据链路层的一种原始接口,提供原始链路层封包的收发。


1992 年,Steven McCanne 和 Van Jacobson 写了一篇名为《BSD数据包过滤:一种新的用户级包捕获架构》的论文。


在文中,作者描述了他们如何在 Unix 内核实现网络数据包过滤,这种新的技术比当时最先进的数据包过滤技术快 20 倍。


BPF 在数据包过滤上引入了两大革新:

· 一个新的虚拟机 (VM) 设计,可以有效地工作在基于寄存器结构的 CPU 之上;

· 应用程序使用缓存只复制与过滤数据包相关的数据,不会复制数据包的所有信息。这样可以最大程度地减少BPF 处理的数据;

由于这些巨大的改进,所有的 Unix 系统都选择采用 BPF 作为网络数据包过滤技术,直到今天,许多 Unix 内核的派生系统中(包括 Linux 内核)仍使用该技术实现。


BPF 工作在内核层,BPF 的架构图如下:

【云安全系列】eBPF——提高Seccomp防护生产力
【云安全系列】eBPF——提高Seccomp防护生产力

1.2 eBPF

2014 年初,Alexei Starovoitov 实现了 eBPF(extended Berkeley Packet Filter)。


经过重新设计,eBPF 演进为一个通用执行引擎,可基于此开发性能分析工具、软件定义网络等诸多场景。


eBPF 最早出现在 3.18 内核中,此后原来的 BPF 就被称为经典 BPF,缩写 cBPF(classic BPF),cBPF 现在已经基本废弃。现在,Linux 内核只运行 eBPF,内核会将加载的 cBPF 字节码透明地转换成 eBPF 再执行。


eBPF 是一个用于访问 Linux 内核服务和硬件的新方法。这一新技术已经用于网络、出错、跟踪以及防火墙等方面。

【云安全系列】eBPF——提高Seccomp防护生产力

上图对 eBPF 架构进行了一个简单的展示。


eBPF 程序需要满足一系列的需求,才能被加载到内核。Verifier中有一万多行代码用来对 eBPF 程序进行检查。Verifier 会遍历对 eBPF 程序在内核中可能的执行路径进行遍历,确保程序能够在不出现导致内核锁定的循环的情况下运行完成。


除此之外还有其它必须满足的检查,例如有效的寄存器状态、程序大小以及越界等。安全控制方面,eBPF 和 LKM 是颇有差异的。


如果所有的检查都通过了,eBPF 程序被加载并编译到内核中,并监听特定的信号。该信号以事件的形式出现,会被传递给被加载的 eBPF 程序。一旦被触发,字节码就会根据其中的指令执行并收集信息。


所以 eBPF 到底做了什么?程序员能够在不增加或者修改内核代码的情况下,就能够在 Linux 内核中执行自定义的字节码。虽说还远不能整体取代 LKM,eBPF 程序可以自定义代码来和受保护的硬件资源进行交互,对内核的威胁最小。

2.eBPF使用

【云安全系列】eBPF——提高Seccomp防护生产力

2.1 eBPF代码执行流程


如图所示为eBPF程序使用及加载过程图,主要的过程为四步:

1. 将写好的内核代码通过libbpf工具编译为BPF对象文件加载至内核

2. 将BPF程序附加到相应的内核挂载点上

3. 初始化BPF程序中用到的eBPF map即内核与用户态之间的共享内存

4. 在用户态程序中创建ringbuffer监听函数,用于处理内核环形缓冲区中的事件

【云安全系列】eBPF——提高Seccomp防护生产力

【云安全系列】eBPF——提高Seccomp防护生产力

2.2 eBPF重要概念

Events and Hooking—事件和钩子


eBPF 程序是在内核中被事件触发的。在一些特定的指令被执行时时,这些事件会在钩子处被捕获。钩子被触发就会执行 eBPF 程序,对数据进行捕获和操作。钩子定位的多样性正是 eBPF 的闪光点之一。例如下面几种:


· 系统调用:当用户空间程序通过系统调用执行内核功能时。

· 功能的进入和退出:在函数退出之前拦截调用。

· 网络事件:当接收到数据包时。

· kprobe 和 uprobe:挂接到内核或用户函数中。


Helper Calls—辅助函数


eBPF 程序被触发时,会调用辅助函数。这些特别的函数让 eBPF 能够有访问内存的丰富功能。例如 Helper 能够执行一系列的任务:


· 在数据表中对键值对进行搜索、更新以及删除。

· 生成伪随机数。

· 搜集和标记隧道元数据。

· 把 eBPF 程序连接起来,这个功能被称为 tail call。

· 执行 Socket 相关任务,例如绑定、获取 Cookie、数据包重定向等。

【云安全系列】eBPF——提高Seccomp防护生产力

2.3 eBPF代码解析

下面通过一个eBPF示例代码进一步说明eBPF的使用方式。

内核态示例代码:

SEC("kprobe/sys_execve")int kprobe__sys_execve(struct pt_regs *ctx) {__u64 id = bpf_get_current_pid_tgid();__u32 tgid = id >> 32;proc_info *process;if (!process) {return 0;}process->pid = tgid;bpf_get_current_comm(&process->comm, 100);bpf_ringbuf_submit(process, ringbuffer_flags);return 0;}


内核态示例代码主要在内核态通过辅助函数bpf_get_current_pid_tgid获取当前进程的pid,通过辅助函数bpf_get_current_comm获取当前进程的执行命令,将这两个信息放在proc_info结构体中,通过bpf_ringbuf_submit辅助函数发送到环形缓冲区中,这样用户态就可以从环形缓冲区中获取内核态发送的事件信息。


用户态示例代码:

eventsChannel := make(chan []byte)rb, err := bpfModule.InitRingBuf("events", eventsChannel)if err != nil {panic()}rb.Start()for {eventBytes := <-eventsChannelpid := int(binary.LittleEndian.Uint32(eventBytes[0:4]))comm := string(bytes.TrimRight(eventBytes[4:], "x00"))    fmt.Printf("%d %vn", pid, comm)}


用户态示例代码主要是将环形缓冲区events中的数据存到eventsChannel管道中,这样我们可以从eventsChannel管道中持续获取内核发来的信息,将信息进行解析进而获得当前进程pid以及进程执行命令。


通过示例程序我们可以发现,eBPF可以做到在不修改linux内核的前提下,将linux内核信息发送至用户态,交给用户态程序进行处理,这样就大大提高了内核的可观测性。这也eBPF成为linux内核顶级子模块的原因之一。


随着内核跟踪点的丰富,通过设计eBPF程序,我们可以获取非常丰富的内核信息,进而实现对网络,安全,调度等方面的性能提升。

3.eBPF结合Seccomp

Seccomp防护最大的问题点在于系统调用白名单的设计。传统Seccomp防护需要一位对系统调用非常了解的安全专家进行系统调用白名单配置,这样配置费时费力,并且一旦系统调用白名单不全,可能会造成影响业务。


所以如何提高Seccomp防护生产力问题急需解决。如果将eBPF技术运用在系统调用白名单收集中,Seccomp防护生产力问题迎刃而解。


通过在内核挂载点增加eBPF程序,我们可以实现获取系统中每个进程的系统调用,将进程系统调用收集起来,进而得到容器的系统调用,最终获得业务容器的系统调用白名单。这个过程基本不再需要人工干预,只需要确定录制系统调用白名单的时机,就可以生成相应业务容器的系统调用白名单。这样就极大地提高了Seccomp防护生产力。


整个eBPF结合Seccomp过程如图所示:

【云安全系列】eBPF——提高Seccomp防护生产力     


学习模式-开始收集syscall:


我们可以对业务容器进行syscall学习,当Pod开启学习时,seccomp controller会先将ebpf object文件加载至内核,并且初始化ebpf map。根据使用需要可以初始化多个ebpf map,用于用户态与内核态进行信息交互。


业务容器每当有syscall产生都会更新到ebpf map中,并且会向用户态发送一个event事件。这个事件中包含产生系统调用的pid信息,通过pid信息,我们可以确定是由哪个业务容器产生的系统调用行为。最后我们可以通过pid将业务容器与syscall联系起来。


学习模式-结束收集syscall:


当业务容器已经被激发出所有的syscall行为之后,可以进行结束收集syscall。syscall信息保存在内核的ebpf map中,key是pid,value是syscall id构成数组,用户态保存着每个业务容器对应的pid。


所以我们可以在用户态通过业务容器的pid列表,获取到业务容的所有syscall,即获取到业务容器的系统调用白名单。再通过Seccomp机制实现业务容器系统调用维度的安全防护。


备注:这里只是举例说明通过eBPF采集syscall的整个流程,在实际应用中,我们对eBPF采集syscall全流程做了一系列优化措施,使得syscall采集高效可靠。

4.总结

本文从BPF的发展阶段出发,介绍了BPF到eBPF的演进方式。通过eBPFf代码样例详细介绍了eBPF的开发方式以及eBPF使用技巧。


通过开发eBPF程序我们可以获取丰富的内核信息。重要的是,我们可以将eBPF与seccomp结合,使用eBPF获取seccomp需要的系统调用白名单。


通过使用eBPF进行syscall采集,syscall白名单可以通过代码的方式自动生成,再结合seccomp能力使得syscall白名单安全能力生效。


这就构成了完整的云原生系统调用维度安全保护全流程,保证了业务容器syscall维度的安全。


eBPF技术结合seccomp安全机制可以进一步提高seccomp安全防护生产力,深信服创新研究院云安全研究团队将对此持续探索。

参考资料

https://www.tcpdump.org/papers/bpf-usenix93.pdf

https://cloud.tencent.com/developer/article/1684491

https://ebpf.io/what-is-ebpf/

https://blog.aquasec.com/libbpf-ebpf-programs

https://goteleport.com/blog/what-is-ebpf/

 


【云安全系列】eBPF——提高Seccomp防护生产力

原文始发于微信公众号(深信服千里目安全技术中心):【云安全系列】eBPF——提高Seccomp防护生产力

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年1月23日22:01:19
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【云安全系列】eBPF——提高Seccomp防护生产力https://cn-sec.com/archives/1407691.html

发表评论

匿名网友 填写信息