Linux之父Linus中国香港首讲:安全、Rust、AI与核心Kernel
2024年8月23日,在中国香港举行的 Linux 基金会的 OpenSource Summit China 大会上,Linus Torvalds 和他的好友 Dirk Hohndel(Verizon 开源项目办公室负责人)再次就 Linux 开发及相关议题进行了热烈的交流。
两人聊到了Linux开发的各个环节,比如版本发布的节奏、系统的安全性、Rust语言在 Linux 中的融合,还有AI在编程里的新角色。
首先,Torvalds有点失望地告诉大家,sched_ext这个用eBPF来构建灵活调度策略的调度器,不会包含在下一个Linux内核发布版本中。不过他还是希望在Linux 6.12版本中能见到它的身影。【Sched_ext是一个可扩展调度程序类,允许使用eBPF构建调度策略。它已经有很多使用,并且有兴趣将其纳入主流】
Torvalds坦言:“旧内核确实稳,我们也确实会给它们补补丁、修漏洞,但有时候一些修复会漏掉,因为大家觉得它们不重要,结果证明其实它们还挺重要的。”他还提醒说,如果你一直坚持使用旧内核,等到哪天真的升级到新内核时,可能会遇到一大堆麻烦。所以,Torvalds向那些还在用Linux 4.9内核的中国国内嵌入式Linux厂商喊话:“差不多得了,该更新了。”
Torvalds提到,尽Linux已经走过了三十三年的风风雨雨,“你可能觉得那些基础问题早该解决了,但实际上并没有。我们还在努力攻克内存管理等基础难题。”
Linux内核在2022年主要发布了5.16-5.19以及6.0和6.1这几个版本,每个版本都为eBPF引入了大量的新特性,所以相当支持eBPF的发展,从某种意义来讲,eBPF正朝着一个完备的内核态可编程接口快速进化。
有作用力就有反作用力,本篇分析来自于Cymulate研究团队。
eBPF(扩展伯克利数据包过滤器)是一种强大而灵活的技术,最初设计用于 Linux内核中的数据包过滤。随着时间的推移,它已发展成为一个多功能框架,允许在Linux内核中执行自定义程序,而无需更改内核源代码或加载内核模块。
eBPF扩展了这一概念,允许用户空间程序挂接到支持该技术的许多其他Linux 子系统。eBPF程序预定义钩子可以附加到系统调用、内核和用户空间中的函数入口/出口、网络事件以及几个其他事件基础钩子点。
能够挂接到不同的 Linux 子系统(不仅仅是套接字)并在内核上下文中运行用户空间程序而无需编写任何内核模块或驱动程序,这就是 eBPF 成为如此强大的技术的原因。
eBPF如何工作?
当黑客发起攻击时,他们面临着多项挑战。其中一项挑战是绕过组织的防御系统而不被抓住。这些防御系统包括网络防火墙、WAF、EDR/XDR 等。
另一个挑战是保持终端持久性,同时避免被用户或现有监控系统检测到。为了克服这些障碍,黑客依靠MITRE ATT&CK中记录的大量恶意技术(一旦被发现)。
例如,黑客试图绕过防御和监控系统,并使其入侵尝试在目标机器上看起来合法,可以使用进程注入和防御规避技术。此外,为了在被攻破的端点上保持立足点,该黑客会使用持久性技术。
随着安全产品在缓解这些复杂技术方面的能力不断提高,黑客不断研究新技术、系统服务、操作系统内部子系统等,以创建安全产品无法捕获的新方法。其中一项技术是eBPF。Linux操作系统中的这项新技术开始越来越流行。
【eBPF的总体架构和组件】
当使用Clang或LLVM编译器将eBPF程序编译为字节码并使用bpf系统调用将其加载到内核时,程序将进入eBPF验证程序。验证程序将(在内核上下文 – ring0 中)执行一系列测试,以检查eBPF是否具有所需的功能(请参阅所需权限和功能部分),以及程序是否可以安全加载且不会使系统崩溃或挂起。
在验证程序确认程序被允许且可以安全加载后,它将继续进入eBPF JIT(即时)编译器。eBPF JIT编译器会将程序的字节码转换为机器码,并将其附加到正确的内核挂钩点。这是编译和加载eBPF程序的一般流程。
该架构中的另一个重要组件是eBPF映射。eBPF映射是键值对通用存储。它们可用于在内核和用户空间之间或多个eBPF程序之间共享数据。此外,它们还可以帮助在同一程序中存储信息。映射有不同的类型:哈希、数组、堆栈跟踪、环形缓冲区等。
可移植性
eBPF 社区面临的众多问题之一是eBPF程序在不同系统之间的可移植性。
使用内核数据结构和类型需要访问系统内核调试信息。过去,这通常是通过安装相应版本的内核头文件来实现的。当尝试在不同目标上运行eBPF程序时,对内核头文件的依赖性非常成问题。通过开发BTF(BPF 类型格式)和CO-RE(一次编译,随处运行)解决了这个问题。
BTF是一种元数据格式,用于对与BPF程序/映射相关的调试信息进行编码。此元数据包括内核数据结构和类型。它是一种简约、紧凑的格式,可将bpf程序所需的所有数据封装到Linux内核中。
CO-RE – BPF 一次编译,随处运行,这是eBPF领域中一种相对较新的方法,用于仅编译一次eBPF模块。虽然BTF允许捕获有关内核类型和数据结构的关键信息,但CO-RE会记录BPF程序的哪些部分需要重写以及如何重写,以便 bpf 程序与任何内核版本兼容(只要内核包含BTF信息)。
BTF和CO-RE的结合解决了可移植性问题。唯一的先决条件是目标内核必须在配置选项设置为CONFIG_DEBUG_INFO_BTF=y的情况下构建。
所需的特权和能力
将eBPF程序加载到内核需要特定权限。过去,加载它需要完全root权限或CAP_SYS_ADMIN功能。如今,为了允许在没有CAP_SYS_ADMIN功能的情况下加载这些程序(出于稳健性原因),使用了CAP_BPF。添加其他功能(例如CAP_PERFMON或CAP_NET_ADMIN)将增强系统上的eBPF程序功能。
https://elixir.bootlin.com/linux/v5.0.21/source/include/uapi/linux/capability.h
在加载eBPF程序时有一些例外。非特权用户可以加载BPF_PROG_TYPE_SOCKET_FILTER类型的程序。这种类型的程序在套接字上启用非常有限的过滤功能。阻止非特权用户加载任何类型的 eBPF 程序的唯一方法是将/proc/sys/kernel/unprivileged_bpf_disabled的值设置为 1 或 2:
·设置为 1 时,非特权 eBPF 将被禁用。更改此值后,需要重新启动系统才能启用它。
·设置为 2 时,非特权 eBPF 将被禁用。更改此值后,无需重启系统即可启用它。
eBPF在哪里使用?
近年来,基于eBPF的项目数量激增,越来越多的项目宣布开始采用该技术。小型初创公司开始基于该技术开发新产品,企业也开始将其用于各种用例。基于 eBPF 的程序主要在四个领域有用:网络、分析、可观察性和安全性。
1. 网络
Linux 内核TC(流量控制)和XDP(eXpress 数据路径)eBPF基础设施可用于处理数据包,甚至在网络堆栈中的不同挂钩点行数据包缓冲区并对它们执行各种操作。
此功能有多种用途。例如:
(1)读取和写入数据包元数据
(2)通过绕过复杂的路由来改变网络路径
(3)接收或丢弃进入系统的行数据包缓冲区
(4)决定网络政策
(5)在现代数据中心或云原生环境中提供高性能网络和负载平衡
许多公司都使用这些功能。例如,Facebook 使用 Katran(一个 C++ 库和 eBPF 程序)构建高性能第 4 层负载平衡转发平面。Katran 利用 XDP 基础架构提供内核设施以快速处理数据包。另一方面,Cloudflare 使用数据包丢弃工具 L4Drop 作为其拒绝服务 (DDoS)攻击缓解措施的一部分。此工具也使用XDP 基础架构。
2. 分析
多年来,分析和跟踪一直是软件开发周期的关键部分。将 eBPF 程序附加到跟踪点以及内核和用户函数的能力使应用程序和系统本身的运行时行为具有前所未有的可视性。此功能可以帮助开发人员跟踪他们的应用程序,甚至通过对从内核中提取的数据进行分析来排除系统性能故障。
该领域最著名的工具之一是bpftrace。bpftrace 是一种用于Linux eBPF的高级跟踪语言,用于分析生产性能问题并排除故障。还有其他工具选项,其中一些甚至能够跟踪和分析云原生环境,而不会造成主机(节点)崩溃的危险,并且开销很低。
3.可观察性
在管理包含多个pod、节点甚至集群的Kubernetes环境时,如果不进行手动检测,几乎不可能获得完整的可见性。eBPF解决了这个问题。
使用Kprobes和Uprobes等事件基础机制从主机(内核)启用数据收集,可以深入了解Kubernetes环境流程。这对于简化组织流程和解决开发或生产环境中的问题非常有帮助。
如今,随着组织环境和SaaS产品开始在云原生环境中运行,更具体地说是在 Kubernetes 框架上运行,这一可观察性领域变得非常重要。这就是为什么我们开始看到更多像Cilium (Hubble) 或Pixie这样的解决方案,它们在节点级别、集群级别,甚至在多集群场景中跨集群提供高级和低级视图。
4. 安全
安全性是eBPF程序可以提供帮助的另一个方面。使用eBPF来获取来自PC或云原生堆栈的系统事件可以捕获恶意行为并在运行时阻止它们。所有这些都可以通过使用eBPF程序挂接到系统调用、网络堆栈以及不同的内核和用户函数的能力来实现。例如,Falco和Tracee是云原生运行时安全工具,可以检测可疑行为并发出警报。
总而言之,eBPF技术简化了许多开发周期阶段,实现了不同的网络功能,并提高了安全性。这就是我们换个角度思考这项技术如何帮助黑客扩大其恶意技术库的地方。
黑客如何使用eBPF
eBPF技术的一种恶意用途是寻找机制本身的漏洞。例如,恶意行为者可以瞄准在内核上下文中验证eBPF程序的eBPF验证器。如果发现漏洞,并且黑客可以利用此漏洞在内核中执行未经授权的代码,则可能导致特权提升场景 (ZDI-20-1440)。其他逻辑问题或高级操作可能会导致容器逃逸(CVE-2021-31440) 或沙盒逃逸(问题 1320051)。
https://issuetracker.google.com/issues/40059484?pli=1
另一种方法是使用eBPF 程序在受害机器上安装rootkit。rootkit可能会使用 XDP和TC基础设施来操纵入口和通信或从网络中提取敏感数据。它还可以隐藏自身并使用不同的挂钩点实现持久性,提升进程权限,甚至创建后门来维持其立足点。
在这篇文章中,我们关注一个场景:使用eBPF rootkit,并通过跟踪点子系统挂接到getdents64系统调用,从而隐藏来自“ps”等程序的恶意进程。【就是使用ps命令看不到恶意进程了】
使用跟踪点进行挂钩时,可以挂钩到系统调用过程的入口点和出口点。此示例使用了这两个选项。
需要注意的是,在系统调用的入口处使用tracepoint挂钩点可以访问所有系统调用参数。但是,挂钩到系统调用的出口处只能获取返回值,而无法访问其指定参数。
介绍了跟踪点子系统及其特点之后,我们来看一下用于隐藏恶意进程的 getdents64 系统调用。
https://elixir.bootlin.com/linux/v5.19.12/source/include/linux/syscalls.h
https://man7.org/linux/man-pages/man2/getdents.2.html
此系统调用读取通过 fd 参数传递的目录文件描述符的 linux_dirent64 结构。如果此系统调用成功运行,它将返回一个数组,该数组填充了dirent 指向的用户空间缓冲区中的 linux_dirent64 结构数据。
linux_dirent64 结构中的两个关键字段需要密切关注:
(1)d_name à目录条目结构引用的文件/目录的名称。
(2)d_reclen à linux_dirent64 结构的大小。d_reclen 字段使诸如readdir之类的函数(内部调用 sys_getdents64)能够遍历 dirent 指向的数组缓冲区中的所有目录条目,而不会意外跳过或损坏其中的项目。
跳过……好吧……这就是黑客可以介入的地方。使用bpf-helpers函数bpf_probe_write_user,黑客可以操纵 dirent 缓冲区(位于用户空间)。这使黑客能够让 readdir “意外地”跳过 /proc 目录中的一个条目,令人惊讶的是,这将是恶意进程。
以下是实现该目标的步骤:
1. 将调用 getdents64 的每个进程的 dirent 指针保存在 eBPF 哈希映射中。这是在进入系统调用时完成的,因为它是授予对系统调用参数的访问权限的点。
2. 当到达 sys_getdent64 退出挂钩点时,查找哈希图中保存的 dirent 指针。
3. 此时(系统调用退出),dirent 缓冲区已包含数据。换句话说,dirent_pointer 指向一个实际的数组,该数组中填充了 linux_dirent64 结构。如果遍历其条目的目录是 /proc 目录,则黑客必须搜索恶意进程目录并将其删除。搜索将使用 eBPF bpf_probe_read_user和bpf_probe_read_user_str辅助函数执行。
4. “删除”恶意进程是通过将之前的 linux_dirent64->d_reclen 字段更改为其自身大小加上恶意进程 d_reclen 字段的大小来完成的。这是通过使用bpf_probe_write_user来实现的。因此,在读取 dirent 缓冲区时,将跳过恶意进程 linux_dirent64 结构。
关键要点
总而言之,eBPF技术已在各个领域风靡一时,本文中提到了其中一些领域。Cymulate研究团队看到了这项技术的积极一面,但也看到了它被恶意行为者利用的潜力。
零信任安全背景下的可观察性[译]
数据安全态势管理的一切指南
原文始发于微信公众号(安全红蓝紫):警惕,Linux 黑客新的强力工具
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论