导语
突破长期依赖运行时防御的传统范式,系统软件安全和可靠性研究组从语言设计的根源切入,构建了业界首个涵盖“语法约束”与“语义校验”双维度的系统化知识(SoK)图谱,深度解构了语言层面上,内存安全与性能开销上的本质权衡,更为下一代安全编译体系的演进锚定了基准。该研究成果的论文"Survey of Language Level Memory Safety"被IEEE CRESS 2025接收。论文第一作者为复旦大学系统软件与安全实验室25级硕士研究生郭鑫明,导师是硕导、青年副研究员杨广亮老师。
研究背景
内存安全对于操作系统内核等底层系统软件的编程至关重要。工业界报告表明,当前约有70%的安全漏洞源于内存安全问题。因此,多国政府与组织已达成共识,将内存安全确立为未来软件编程的强制性要求。过去数十年间,业界主要将防御重心置于运行时阶段,部署了一系列漏洞利用缓解机制。包括用于栈保护的StackGuard、用于内存布局随机化的ASLR与防御数据执行的DEP,以及旨在防止非授权代码执行的控制流完整性(CFI)等。尽管这些技术被广泛应用并提升了攻击门槛,但日益复杂的现代内存破坏攻击已证明能够绕过上述防御。由于运行时缓解机制仅能在漏洞被利用时尝试防御,而无法从根本上消除代码层面的安全隐患,因此,在编程语言层面内建安全机制、从源头构建内存安全防线,已成为当下的关键研究方向 。
编程语言及其编译器构成了程序员与底层系统资源交互的接口,是程序员与底层硬件之间唯一渠道,更是内存安全的第一道防线 。内存不安全的根源并非运行时的偶然,而是语言设计阶段语义表达力与约束机制失衡的必然产物。有别于以往针对运行时技术的综述。本文基于最新的语言级内存安全SoK成果,系统性地梳理了业界在语言层面的技术演进,并首次将其核心机制抽象为两大维度:语法约束与语义校验。
语法约束: 源码级的安全边界
语法约束的核心理念是通过引入显式的语言结构(如类型注解)或禁用高危操作(如无限制的指针算术),在源码层面规避内存错误。作为与系统资源交互的首要屏障,它主要围绕指针的类型化与生命周期管理展开。
标准演进与方言扩展:C/C++ 等传统系统级语言赋予了开发者极高的内存控制权,但也使其独自承担了内存安全的全部重任。为了缓解这一问,C++11引入了unique_ptr、shared_ptr等智能指针范式以管理指针所有权与共享状态。此外,学术界提出了如 Cyclone、CCured等C语言方言,通过引入类型注解将指针细分为不同类别(如 SAFE、SEQUENCE、DYNAMIC),并在编译期强制执行静态类型检查。
边界划定: 现代系统级语言Rust 在语法约束上实现了创新,其核心在于确立了严格的安全边界。在安全的Rust 代码中,裸指针的解引用和算术运算被严格禁止,从语法层面根除了大量空间违规及悬垂指针风险。然而,出于对底层系统编程表达能力(如双向链表操作或底层内存遍历)的考虑,Rust 保留了unsafe关键字。实证研究表明,而unsafe区域正是当前 Rust 生态中内存安全漏洞的主要原因。
语义安全: 空间与时序的深层保障
当语法约束不足以应对复杂的动态内存状态时,必须依赖编译器和运行时的语义校验机制。我们将其细分为空间安全与时序安全两个维度的技术路径。
1
空间内存安全
空间安全旨在确保内存访问被严格限制在合法对象的边界内。其核心技术挑战在于如何精准存储和验证内存对象的边界信息:
分离元数据: 代表方案如SoftBound,它在独立的“影子空间(Shadow Space)”中维护指针的基址与边界信息。其显著优势在于与现有C/C++ 内存模型高度兼容,无需修改源码即可部署。但全局共享的元数据表在面对海量指针或多线程并发时,会引入高昂的查找延迟与同步开销。
胖指针:将边界元数据直接嵌入指针结构内部,将其从单字长扩展为多字长结构。Cyclone、Checked C以及Rust的切片(Slice)均采用了该机制。胖指针天然具备线程安全性,但其改变了内存布局与调用约定,破坏了应用程序的二进制接口(ABI),且阻碍了部分寄存器优化。
硬件辅助扩展: 如CHERI 架构,通过硬件指令原生支持扩展能力的指针校验,以极低的开销实现了类似胖指针的功能。但由于强依赖专用硬件,其在异构系统或传统设备上的兼容性仍受限。
2
时间内存安全
时序安全致力于防止对象被释放后再度遭遇非法访问(即Use-After-Free和Double-Free)。语言级层面的应对策略呈现出高度的差异化:
垃圾回收:Go等语言通过运行时接管内存的生命周期,从根本上消灭了悬垂指针。但其引入的非确定性暂停(GC Pauses)使得该方案难以在操作系统内核等要求极高实时性与确定性的底层场景中落地。
所有权机制:Rust摒弃了GC,转而依赖编译期的细粒度生命周期追踪。所有权机制实现了零运行时开销的内存安全。但其对单一所有权的严苛要求,也极大限制了复杂数据结构的自由表达。
基于元数据的“密钥-锁”机制:Checked C等方案在对象分配时绑定唯一“锁”,并在每次解引用时校验指针持有的“密钥”。该方案检测具有确定性,但高频的运行时比对依然会带来显著的性能损耗。
硬件辅助:ARM PAC利用指针高位嵌入密码学签名(Tag)进行有效性验证,CHERI则实现了硬件级的延迟地址重用机制。硬件辅助大幅降低了软件开销,但目前大多缺乏对栈内存漏洞的完整覆盖。
总结
综上所述,在语言级内存安全的探索中,现有的技术方案始终在安全性、性能开销与表达能力之间面临着固有的权衡取舍。例如,依赖胖指针的C方言不仅难以重构代码,还会带来显著的运行时开销;而即使是具备严苛类型系统且无需垃圾回收的Rust,为了满足底层系统编程,也不得不引入unsafe。这些绕过编译器安全检查的unsafe代码块,已被实证研究确认为当前Rust生态中内存安全漏洞的主要根源 。
而解决这一权衡问题,正是未来底层软件安全体系研究的核心命题。面对众多历史遗留项目,需要探索高保真的C/C++到安全Rust的自动化翻译与漏洞消解技术,或在保留原有语法的基础上定义整合现代安全机制的“安全子集” 。同时,针对不可避免的unsafe安全缺口,未来的突破口在于细粒度程序分析技术的演进:例如实现unsafe边界的系统级沙盒隔离,开发上下文感知的自动化漏洞检测与修复工具,以及深度结合AI模型进行语义级的安全模式识别与代码重构。只有在编译器架构、类型系统与前沿漏洞分析技术的深度耦合下,语言级内存安全的防线才能真正走向可证明的坚固。
供稿:郭鑫明
排版: 王羿
责编:董佳仪
审核:洪赓、杨广亮
复旦白泽战队
一个有情怀的安全团队
还没有关注复旦白泽战队?
公众号、小红书搜索:复旦白泽战队也能找到我们哦~
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……




还没有评论,来说两句吧...