技术深度解析
CHERI C/C++编程指南围绕一个看似简单的核心前提构建:教会开发者如何编写与CHERI能力模型正确配合的代码。但技术现实远比这复杂得多。
CHERI的核心是用128位或256位的能力取代传统的64位指针。每个能力不仅包含地址,还包含基址、边界(长度)以及一组权限(读、写、执行、加载能力、存储能力等)。硬件强制执行:任何通过能力进行的内存访问都必须落在其边界内并遵守其权限。这与传统的基于MMU的保护有本质区别,后者以页粒度(通常为4KB)运行。CHERI实现了字节级保护,这意味着即使单个字节的缓冲区溢出也能在运行时被捕获。
该指南将大量篇幅用于指针压缩,这是实际部署中的关键优化。完整的128位能力会使每个指针的大小翻倍,这对许多工作负载来说是不可接受的。CHERI的压缩方案(如Morello架构中所实现的)尽可能将能力存储在64位寄存器中,利用了许多能力共享共同基址和边界值这一特性。指南解释了开发者如何组织数据以最大化可压缩性——例如,将具有相似生命周期和权限的对象分组到同一内存区域。
另一个关键部分涵盖了CHERI与C/C++类型系统之间的交互。指南解释了如何使用`__capability`关键字注释指针,以及编译器如何自动为代码插入边界检查。它还介绍了用于手动能力操作的CHERI特定内建函数,例如`cheri_bounds_set`和`cheri_perms_and`。当自动插装不足时,这些内建函数为开发者提供了细粒度的控制。
对于从事CHERI-RISC-V实现的开发者,指南引用了开源的CHERI LLVM编译器及相关工具链。CHERI LLVM项目的GitHub仓库(ctsrd/cheri-llvm)一直保持活跃,拥有超过1200颗星和定期提交。指南展示了如何以最小修改编译现有的C/C++代码库,通常只需添加诸如`-mabi=purecap`(纯能力ABI)之类的编译器标志。
数据表:CHERI开销与传统内存安全方法对比
| 方法 | 内存开销 | 性能开销 | 粒度 | 检测时机 |
|---|---|---|---|---|
| CHERI(128位能力) | 指针大小增加约100-200% | 平均5-15% | 字节级 | 运行时(硬件) |
| Address Sanitizer | 内存增加约200-300% | 2-3倍减速 | 字节级 | 运行时(软件) |
| SoftBound/CETS | 内存增加约50-100% | 1.5-2倍减速 | 字节级 | 运行时(软件) |
| Rust(所有权) | 运行时约0% | 运行时0% | 编译时 | 编译时 |
| MPK(内存保护键) | 指针大小约0% | 开销<1% | 页级 | 运行时(硬件) |
数据要点: CHERI提供了一个引人注目的中间地带:硬件强制的字节级保护,性能开销适中,远低于仅软件方法(如Address Sanitizer)。然而,指针大小的增加是一个真实成本,压缩方案只能部分缓解。
该指南还深入探讨了CHERI与C++特性(如虚函数表、异常和标准库容器)之间的交互。例如,CHERI的能力模型要求虚函数表指针被视为能力,这意味着硬件可以验证对虚函数表的访问是否超出其边界——从而防止虚函数表劫持攻击。指南提供了编写CHERI安全的自定义分配器和智能指针的模式。
关键参与者与案例研究
CHERI生态系统主要由学术和研究机构推动,剑桥大学计算机实验室是其起源地。该指南由来自剑桥、SRI International和Arm的研究人员共同撰写,反映了该项目的协作性质。
Arm的Morello板是最突出的商业CHERI实现。Morello于2021年宣布,并于2022年开始向选定合作伙伴发货,它是一款在修改后的Armv8-A架构上实现CHERI的原型片上系统。指南包含了针对Morello的具体示例,例如如何使用`morello`目标三元组以及如何在板上调试CHERI异常。Arm在CHERI上投入了大量资源,将其视为在物联网、汽车和云基础设施领域实现安全计算的一个潜在差异化优势。
在开源方面,CHERI-RISC-V项目(github.com/CTSRD-CHERI/cheri-riscv)提供了CHERI在RISC-V上的完整FPGA实现。这对于无法访问Morello硬件的研究人员和爱好者尤其重要。指南涵盖了这两个平台,并指出其编程模型几乎相同。
比较