CHERI:硬件能力指针与内存安全的架构革命
从 Cambridge 大学的学术研究到 ARM Morello 的真实硅片,CHERI (Capability Hardware Enhanced RISC Instructions) 正在硬件层面重新定义内存安全的边界。我们用 128 位 capability pointer 替代传统裸指针的尝试,能否终结 C/C++ 的内存安全魔咒?
1. 内存安全:一个未解的古老难题
2024 年 2 月,美国白宫国家网络总监办公室 (ONCD) 发布了一份名为《Back to the Building Blocks》的报告,明确呼吁行业从内存不安全的编程语言(C/C++)向内存安全的语言过渡。这不是第一次——也不是最后一次——有人在高层文件中强调内存安全的重要性。
然而现实是残酷的:全球数十亿行 C/C++ 代码运行在操作系统内核、数据库引擎、网络设备、航空航天控制系统中。重写?不现实。如何用硬件机制保护这些既有代码?这成了体系结构学界数十年来持续探索的问题。
在这个背景下,CHERI 被广泛认为是最系统、最具工程可行性的硬件内存安全方案之一。它不要求你更换编程语言,不要求重写数百万行代码,而是在硬件层面给"指针"这个概念一个新的定义。
2. 什么是 CHERI?
CHERI 起源于 2010 年剑桥大学的一项研究,最初作为 DARPA 资助的 CHERI(Capability Hardware Enhanced RISC Instructions)项目的一部分启动。它的核心思想是:在硬件层面为每个指针附加元数据——边界(bounds)、权限(permissions)和标签(tag)——形成一个新的数据类型:capability(能力)。
2.1 传统指针 vs CHERI Capability
传统 64 位指针:
┌─────────────────────────────────────────────────────────────────┐
│ 64-bit virtual address (only) │
└─────────────────────────────────────────────────────────────────┘
CHERI 128 位 capability pointer(混合模式,兼容架构):
┌──────────────────────────────────────┬──────────┬─────┬─────┐
│ 64-bit address (cursor) │ bounds │ perms│ tag │
└──────────────────────────────────────┴──────────┴─────┴─────┘
^ ^ ^ ^
当前指针值 允许访问范围 读/写/执行 有效标记
关键字段说明:
- Base + Length(边界):定义允许访问的内存区域
[base, base+length) - Permissions(权限):细粒度的读、写、执行、加载 capability 等权限
- Tag(标签):一个单比特标记,只有 tag=1 的 capability 才能被解引用。一旦 capability 被复制到内存,写入任意字节会清零 tag,从根源阻止伪造 capability
2.2 能力的不变性(Monotonicity)
CHERI capability 有一个关键数学性质:monotonicity(单调性)。你可以缩小一 个 capability 的边界或减少权限,但不能扩大。这意味着一个 capability 一经创建,就只能变得更受限,不能任意越权。
这个特性足以在硬件层面杜绝 OOB(越界访问)和权限升级攻击。
3. CHERI C:在 C 语言之上的安全增强
CHERI 不仅仅是硬件机制——它还提供了一套在 C 语言层面的语义增强,称为 CHERI C。你可以把它理解为 C 语言的一个严格子集转换:
3.1 指针的精确定义
在标准 C 中,指针可以指向任意对象(甚至越界)。CHERI C 将指针严格分类:
- 常规指针(int *):整数地址,无硬件保护,可任意运算但不安全
- Capability 指针(attribute((address_space(200)))):受硬件保护的指针,严格遵循边界和权限
// 标准 C — 悬垂指针UB,CHERI 会捕获
int *p = malloc(sizeof(int) * 10);
free(p);
*p = 42; // ⚠️ UAF — CHERI 在 free 时撤销 capability,此处 tag=0 触发异常
// CHERI 安全版本
int *__capability safe_arr = cheri_setbounds(malloc(40), 40);
// safe_arr 的 base 和 length 被硬件记住
safe_arr[10] = 1; // ✅ 合法
// safe_arr[11] = 1; // ❌ 触发出界异常 (Capability Bounds Violation)
3.2 安全的子对象推导
CHERI C 允许从结构体 capability 安全地派生出成员 capability:
typedef struct {
char name[64];
int age;
struct address *addr;
} person_t;
person_t *__capability p = ...;
int *__capability page = &p->age;
// page 的 base = offsetof(person_t, age), length = sizeof(int)
// 硬件自动限制边界,无法通过 page 访问 name 或其他成员
// 对比标准 C:int *q = (int*)((char*)&p->name[60]); q[1] 就是 age,完全合法但危险
3.3 跨边界检查的安全数学
传统指针算术的漏洞:
char buf[64];
int offset = get_user_input(); // 可能为 65
buf[offset] = 'X'; // OOB 写入!
CHERI 版本:
char *__capability buf = cheri_setbounds(malloc(64), 64);
int offset = get_user_input();
// buf[offset] = 'X'; // 编译 + 双重保护:若 offset 超出 capability 边界,触发异常
4. ARM Morello:CHERI 走向真实世界
2022 年,ARM 发布了 Morello 开发板——全球首款实现 CHERI 扩展的商业处理器。基于 ARMv8.2-A 架构,Morello 在 Neon/SIMD 流水线中集成了完整的 CHERI 支持。
4.1 Morello 的关键规格
| 特性 | 详情 |
|---|---|
| 架构 | ARMv8.2-A + CHERI 扩展 |
| CPU 核心 | 2× Cortex-A75 (应用核) / 2× Cortex-A55 (效率核) |
| Capability 宽度 | 128 位 (64-bit 地址 + 64-bit 元数据) |
| 硬件支持 | 能力指针加载/存储、自动 tag 清除、边界检查 |
| 软件栈 | CheriBSD (FreeBSD 的 CHERI 移植版) |
| 发布 | 2022 开发板,2023 扩展支持 |
4.2 性能开销实测
根据剑桥大学和 SRI International 的实测数据:
| 工作负载 | MITIGATE (内存安全改进项目) | CheriBSD 用户态 |
|---|---|---|
| LMBench 微基准 | +1-3% (capability 操作) | |
| SQLite 全负载 | +5-10% | |
| nginx Web 服务器 | +8-15% | |
| FreeRTOS 裸机 (IoT) | +3-5% | |
| ANNEAL 规约应用 (带保护) | +15-20% |
结论是:对于大多数真实应用,CHERI 在混合模式下 (legacy + capability) 的开销在 5-15% 范围内。纯 capability 模式 (全 CHERI C) 的开销可能更高,但混合模式允许渐进迁移。
5. CheriBSD:硬件能力指针与操作系统的融合
ARM Morello 上运行的标准操作系统是 CheriBSD——FreeBSD 的深度 CHERI 移植版。它展示了 CHERI 如何在完整 OS 栈中工作:
5.1 内核与用户空间的边界
CheriBSD 中,内核 capability 和用户 capability 严格隔离。系统调用通过 syscall capability 传递——一个被裁剪过权限的 capability,只能访问内核公开的接口:
// 内核接收到用户空间的 capability,必须明确地:
// 1. 检查 tag 是否有效
// 2. 检查 bounds 是否在用户空间内
// 3. 使用 cheri_andperm() 仅保留必要的权限
// 4. 在 copyin/copyout 时利用硬件能力检查
struct proc *p = ...;
// capability 权限仅限于当前进程的所有权范围
5.2 兼容性处理
CheriBSD 的关键设计决策是 混合模式兼容:
- 未被编译为 CHERI C 的旧代码仍以纯 64-bit 地址运行
- CHERI 编译的代码使用 capability 指针
- 两者通过显式转换接口 (
cheri_getaddress()/cheri_setaddress()) 交互
这种设计证明了一个关键假设:你可以在不重写所有代码的前提下,逐步迁移到 CHERI 安全世界。
6. 对比 MTE、CFI 和其他安全扩展
| 安全机制 | 粒度 | 能防御的漏洞 | 开销 | 部署状态 |
|---|---|---|---|---|
| MTE (Memory Tagging) | 16 字节 (随机标签) | 部分 UAF/OOB | 1-3% | Android 12+ (软件模拟), 硬件 ARMv8.5+ |
| BTI (Branch Target Identification) | 函数入口 | ROP/JOP 攻击 | <1% | iOS 14+, Android 12+ |
| PAC (Pointer Authentication) | 单个指针 | 指针篡改 | 1-2% | iOS, Android |
| CFI (Control Flow Integrity) | 控制流图 | 间接跳转劫持 | 5-15% | LLVM CFI, Microsoft CFG |
| CHERI | 字节级 | 几乎所有内存安全漏洞 | 5-20% | Morello 开发板, CheriBSD |
CHERI 的优势在于防护的完整性和表达能力——它能同时防御 OOB、UAF、类型混淆、权限升级等多种攻击面,而 MTE 只能做粗略的检查且可绕过。
劣势也很明显:128 位指针导致内存占用增加、缓存压力上升。对于需要保存大量指针的数据结构(如指针密集的链表、树),内存开销可能增加 20-30%。
7. CHERI 的未来:从学术到产业
7.1 产业动态
- HGF (Hardware Enforced Security):基于 CHERI 的商业化项目开始出现,提供 PCIe 加速卡形式的硬件能力保护
- Microsoft Azure CTO Mark Russinovich 在 BlueHat 会议上公开讨论 CHERI 对云基础设施安全的意义
- Leliwa、Capsicum:在 FreeBSD 和 CheriBSD 中,CHERI 与能力安全模型(Capsicum)结合,实现比 Linux seccomp 更强的沙箱
- RISC-V 上的 CHERI:RISC-V 基金会将 CHERI 作为安全扩展的备选方案,有望在开源 ISA 中实现
7.2 与 Rust 的关系
CHERI 不是 Rust 的替代,而是互补。Rust 通过借用检查在编译期保证内存安全,但仍有以下局限:
- Rust
unsafe块可以绕过安全检查 - 无法保护已有的 C/C++ 代码库
- 无法防御内核代码中的内存错误
CHERI 在运行时提供硬件级别的保障,可以与 Rust 协同工作:Rust 编译器(nightly 已有实验性 CHERI target)可以生成直接使用 capability 指令的代码,实现编译期和运行时的双重安全。
8. 实战参考:如何在 Morello 上进行实验
如果你想亲手体验 CHERI,可以借由 Morello 开发板或 QEMU CheriBSD 镜像进行实验:
8.1 QEMU 模拟(无需硬件)
# 下载 CheriBSD QEMU 镜像
wget https://releases.cheribsd.org/releases/23.11/Morello-cheribsd64.qcow2.xz
xz -d Morello-cheribsd64.qcow2.xz
# 启动 QEMU
qemu-system-morello \
-M morello \
-cpu morello \
-m 4G \
-drive file=Morello-cheribsd64.qcow2,format=qcow2,if=none,id=disk0 \
-device virtio-blk-device,drive=disk0 \
-nographic
8.2 体验 CHERI C 的安全检测
// oob_demo.c — 演示 CHERI 捕获越界
#include <stdio.h>
#include <stdlib.h>
int main() {
int *__capability arr = (__capability int *)malloc(sizeof(int) * 10);
arr = __builtin_cheri_bounds_set(arr, sizeof(int) * 10);
// 合法访问
arr[0] = 42;
arr[9] = 99;
printf("arr[0] = %d, arr[9] = %d\n", arr[0], arr[9]);
// 越界访问 — 运行时触发 CapabilityBoundsException
arr[10] = 100; // 💥 硬件异常: 越界
return 0;
}
编译运行:
# Morello 平台上的编译
cc -o oob_demo oob_demo.c
./oob_demo
# 输出:
# arr[0] = 42, arr[9] = 99
# In capability mode: oob_demo (thread 100053):
# Capability bounds fault: arr[10] is outside bounds [0x...,0x...)
9. 总结与展望
CHERI 代表了一种思路的根本转变:将软件安全检查下沉到硬件层。不是让编译器在编译期猜测所有可能出错的地方,而是让处理器在保证性能的前提下拒绝执行危险的指针操作。
它的价值不仅在于防御已知的内存安全漏洞,更在于给未来硬件架构设计指明了一条可行路径。随着 Morello 的推出、CheriBSD 的成熟、以及 RISC-V 社区的跟进,CHERI 很可能成为下一代体系结构安全扩展的重要参考。
对于系统工程师而言,现在是时候开始理解 CHERI 及其背后的 capability 安全模型了——不是因为明天就要部署它,而是因为它正在重新定义我们关于"指针"和"内存安全"的直觉认知。
延伸阅读: CHERI 的学术基础来自剑桥大学 Robert Watson 和 Peter Neumann 团队长达十余年的研究。可以参考他们的论文 "Capability Hardware Enhanced RISC Instructions: CHERI Instruction-Set Architecture" (Version 9, 2023)。

发表评论 取消回复