后端Pass简介——KCFI
KCFI
这个 Pass 就一百多行,含义就是:在内核代码的间接调用前插入控制流完整性检查(Control-Flow Integrity, CFI)指令,以提高安全性。
实现 Kernel Control-Flow Integrity (KCFI) 的功能 —— 在执行间接函数调用(如通过函数指针调用)之前插入一个检查指令,验证被调用目标是否匹配预期的类型。
背景
控制流完整性是一种编译器和运行时技术,旨在防止攻击者通过劫持程序的控制流(比如通过函数指针、虚函数表、返回地址等)来执行恶意代码。
攻击者通常利用内存漏洞(如缓冲区溢出、Use-after-free 等)修改代码中用于间接跳转的数据(如函数指针),从而劫持控制流,达到执行任意代码的目的。
KCFI(Kernel Control-Flow Integrity) 是 LLVM 项目为 Linux 内核引入的一种轻量级、可部署的控制流完整性机制。它专注于防护 内核中的间接函数调用,如:
void (*handler)(void) = some_func;
handler(); // 间接调用
攻击者若能修改 handler 指针,便可跳转到非法地址,执行恶意代码。
🧠 KCFI 的工作原理
KCFI 的核心思想是:
类型标签(CFI Type)
- 编译器在编译函数时,为每个函数分配一个类型标签(type hash),用于标识该函数的“调用签名”。
- 任何使用函数指针调用的地方,都会带上一个期望的 cfi-type 标签。
插入检查
- 编译器生成的机器代码会在每次间接调用前,插入一条指令来验证目标地址的标签是否匹配期望类型。
- 如果标签不匹配 → 报错 / 崩溃,防止攻击者调用非法代码。
运行时无需复杂支持
- 标签是通过专门的指令嵌入在函数开头或某个固定位置,运行时只需读取目标地址处的数据进行比较。
- 无需复杂的运行时类型系统,代价非常小,适合内核这种对性能要求极高的环境。
对比
特性 | 传统 CFI | KCFI |
---|---|---|
应用范围 | 用户态/内核态 | 专注于 Linux 内核 |
实现方式 | 依赖运行时检查 | 静态编译器插入检查,轻量 |
开销 | 相对较高 | 极低 |
灵活性 | 支持多种语言/签名识别 | 仅支持固定签名(函数指针类型) |
安全性粒度 | 更细粒度(可按签名匹配) | 通过类型 hash 匹配 |
评论