微软开源了 Checked C ,一个旨在对 C 和 C++ 增加边界检查的研究项目。
C 和 C++ 语言上最大的漏洞之一可能就是越界的内存访问。根据美国国家标准技术研究所的国家漏洞数据库数据,从2010 年至2015 年,缓冲区溢出占所有安全漏洞的10-16%。由于大部分系统软件(操作系统、数据库、编译器、解释器、浏览器等)都使用C 和C++ 两种语言之一编写,许多系统都面临内存冲突问题,这使得它们面临故障或者受到攻击,导致隐私信息泄露和系统被控制。来自微软和马里兰大学的一群研究者正在尝试解决这些问题,实现了 Checked C ,它是一个 C 语言的扩展和 C++ 语言的子集,为这些语言增加边界检查。
不像现代语言(如 Java、C#)这些自带自动边界检测,将该功能加入到 C 语言非常困难,项目参与者、微软研究员 David Tarditi 解释道:
为 C 语言增加边界检查有两个障碍。第一是运行时边界信息的存放位置,第二是如何高效的进行边界检查。在实践中发现,改变所有 C 语言指针类型和数组,以携带边界信息不是一个有效的方案。C 语言可能被用于系统基础,一些硬件和标准指定了数据布局,且数据布局无法改变。同时 C 程序还与现存的操作系统交互,这些软件都需要特定的数据布局。
Checked C 允许程序员在 C/C++ 中编写“确保边界检查”的代码。为了实现这个功能 Checked C 增加了新的指针和数组类型,它们可以在编译期和运行时进行边界检查:
- ptr
:指向类型 T 且无须边界检查的指针。这种类型的指针不允许参与算数运算。当访问内存时,该类型指针不能为 null。大部分指针应该用此类型。 - array_ptr
:指向包含类型 T 数组的指针。该指针可以进行算数运算。当读写内存时它不能为 null。程序员需要检查这类指针的边界。 - span
:包含边界信息的指针。塔支持算数运算。当进行内存读写的时候不能为 null。 - T array_var checked[100]:声明类型为 T、大小为 100 的数组并且包含边界检查。当进行 C 语言类型转换时,包含边界检查的数组将被转换成 array_ptr 类型。
该规范确定了变量操作行为,包括指针类型的间接寻址、数组引用、赋值、指针加法、比较、取址(&)、含边界检查数组类型和指针类型的转换等。
现存的 C 程序可以继续工作,很明显 C* 仍然未检查,且指针的算数运算会破坏当前代码。但是编译器可以通过增加参数在指针非正常使用时发出警告或者错误。
Checked C在GitHub 上开源,包含规范、一个 clang 的实现和一个 LLVM 的实现。对此项目感兴趣的开发者被邀请参与项目,即可以改进规范、提出新的功能例如类型转换或者内存管理、增加测试,也可以扩展其他编译器对Checked C 的支持。
过去也有其他尝试对C 语言增加边界检查,包括使用静态分析、增强编译器或者运行时以避免修改语言本身、程序验证或者创造基于C 的新语言。规范的第九章“相关工作”包含了这些其他实现的细节,并且解释了为什么作者选择了扩展语言。
查看英文原文: Checked C - A Safer C/C++ from Microsoft
感谢张龙对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们。
评论