写点什么

谷歌将空间内存安全功能“改造”到 C++ 上

  • 2025-01-26
    北京
  • 本文字数:2782 字

    阅读完需:约 9 分钟

大小:1.34M时长:07:49
谷歌将空间内存安全功能“改造”到C++上

本文最初发布于 THENEWSTACK。



在分析了从 2014 年 7 月 15 日到 2023 年 12 月 14 日近 10 年的 CVE 后,谷歌研究人员计算得出,在 C++中,至少 40%的安全漏洞空间内存漏洞(如越界写入内存)有关。



 (查看大图)

 

不过,谷歌正在努力解决这一问题,同时为这个充满不安全遗留代码的世界树立榜样。

 

谷歌研究人员表示,他们能够将空间安全 “加装 ”到 C++ 代码库中,而且对性能的影响非常非常小。网上有一篇关于他们研究成果的博文,引发了更为广泛的讨论,其中不乏一些有趣的跟帖,有人甚至大声质疑,这种低影响是否意味着 C++代码可以默认包含空间内存安全特性。

 

该文还提出了一种可能性,即一些已经存在很长时间的假设可能会随着时间的推移而受到挑战——当面临的问题比较严重时,或许可以尝试引入新技术。

改进安全设计

这一切都源于一篇博文,该文描述了谷歌如何通过在 C++代码中添加边界检查来保护其服务器端生产系统,从而提高 Gmail、YouTube、谷歌地图甚至谷歌搜索引擎的安全性。谷歌是内存安全语言和其他安全编码实践的早期采用者,但全面过渡往往需要数年时间。也就是说,他们还需要额外做一些工作: “尽可能地在现有 C++代码库中改用安全设计原则"。

 

该博文由资深软件工程师Alex RebertKinuko Yasuda(与谷歌的Max Shavrick合作,后者也是安全基础团队的成员)撰写。该文首先指出,C++标准库的 LLVM 实现中包括几种用于发现未定义行为的加固模式,从而可以对 C++代码进行边界检查

 

该文解释说:”[我们]现在已将其作为服务器端生产系统的默认设置,同时密切监控上线情况。“

 

结果如何?

  • 该团队发现了 1000 多个 Bug。(据谷歌估计,平均每年发现的 Bug 可增加到 1000 至 2000 个)。

  • 谷歌 “整个生产环境的基线分段故障率降低了 30%”。在博文中,他们将此归功于更好的代码可靠性和质量: “除了崩溃之外,检查还发现了一些错误。这些错误可能会表现为不可预测的行为或损坏数据"。

  • 最终,它还帮助谷歌 “发现并修复了多个在代码中潜伏了十多年的 Bug”。经过加固的 C++检查 “将许多难以诊断的内存损坏转化为即时且易于调试的错误”。

  • 它甚至还瓦解了内部的一次红队演习,“证明了它在挫败漏洞利用方面的有效性”。



 (查看大图)

 

“我错了”

其中有一项结果最引人关注。谷歌的博文称,加固libc++“对我们的服务平均造成了 0.30%的性能影响”。

C++中的边界检查:有人问,0.3%的开销是否属实?这不仅仅是一个基准测试结果,我们是通过 Google-Wide profiling 得到的这个结果,我们通过它获得了来自 DC 的实时洞察。这也让我们大吃一惊,因为那比我们预想的要少得多。

https://t.co/zBUvoYzGi1 https://t.co/7NAWBuxdtP

— Kinuko Yasuda (@kinu) 2024年11月16日

 

谷歌杰出工程师Chandler Carruth回应了他们的博文。他也是新兴编程语言Carbon的创始人和联合牵头人。Carruth 撰写了一篇博文,其中第一节的标题就是 "边界检查的开销:我错了"。

 

“其他人关于成本的一些历史报告,再加上我自己的一些简单实验,让我坚定地认为,边界检查的成本不可能低到可以默认启用的程度。然而,到目前为止,它们看起来确实非常低。“

 

遗憾的是,这种普遍的看法使得高质量的动态安全检查没有出现在 libc++及其他 C++库中,最初也没有出现在 LLVM 中。

C 的加固之路

但 Carruth 看到,Microsoft Visual C++引入了基于编译器的检查,而 “在这里,苹果公司所有推动在C++中实现安全缓冲区的人都做了一项了不起的工作,让 LLVM 生态系统(包括 Clang 和 libc++)最终在这一领域拥有了一个可靠的工具”。Carruth 认为,另一个因素是内存安全语言开发人员为 LLVM 做出了更多的贡献(因为更多的非 C/C++语言开始使用 LLVM),从而带来了 “一系列稳定而系统化的改进”。

 

回首过去,Carruth 认为,虽然 LLVM 经过了多年的改进,但"我们并没有真正注意到什么时候已经达到了一个临界点。在那一刻,所有改进一起从根本上降低了此类检查的实际成本,使其在默认情况下就普遍适用。“

 

“这种水平的可用性改变了安全游戏的规则,因为我们不用再在性能或安全性之间做出痛苦的权衡取舍,我们可以两者兼得。“

 

Carruth 用粗体字写道:"我认为,通过努力,借助编译器对内存安全检查的持续支持,我们确实有机会默认实现空间内存安全,即使是在 C 和 C++中,即使是在性能最受限制的环境中。”

 

这就提出了一个问题:现在是否应该考虑下参考计数等其他安全检查——即使我们认为这些检查会带来令人望而却步的性能影响。

 

“我认为,有足够的证明表明,对于比较小的系统(手机、笔记本电脑、其他用电池的东西),缓存流量和潜在同步开销的成本即使再大也微不足道。我认为,Swift 已经提供了强有力的证据,只要在优化基础设施上投入一些资金并认真实施,参考计数就能够在这些处理器上实现极高的效率。”

 

当然,谷歌的博文也在 LinkedIn 上引发了不少讨论:



 (查看大图)

 


 (查看大图)

 

是否需要优化?

Carruth 还回顾了为了“让 LLVM 在优化加固方面做得更好”所作出的努力。他认为,性能敏感型工作负载得益于配置文件引导优化(或 PGO),以及“人们系统性地构建优化基础设施......将代码的热门路径与安全检查的开销隔离开来,并释放了 LLVM 围绕它们所开发的所有其他优化技术,最大限度地降低了它们的成本”。

 

至于谷歌,他们的博文确实承认了这一点以及其他提高性能的技巧,但也补充说:"即使没有这些先进技术,边界检查的开销仍然微乎其微。(谷歌的博文将这种低影响归因于加固后的libc++的高效设计,以及编译器在优化过程中消除冗余检查的方式)。

 

不过,当发现 LLVM 在执行一项不必要的检查(并且对性能有很大影响)时,他们编写了一个修复程序,并将其贡献给了 LLVM 项目,“以便与广大的 C++社区分享这项改进带来的好处”。

各方反应

谷歌的博文在网络上引发了一些积极的反响。在 Hacker News 上,WebAssembly 联合创始人Ben Titzer对此作出了回应,他还记得 20 年前关于 C++中边界检查必要性的争论。”程序中存在边界检查能捕捉到的 Bug。将其作为一种内置特性,编译器就会对其进行专门针对边界检查的优化,这样可以消除许多 Bug,并大大降低动态成本。“

 

“仅仅在库中打开安全检查并不一定能实现所有的编译器优化,但这只是一个开始。安全检查应该真正地内置于语言中"。

 

另一个回应来自Walter Bright,他创建了另一种编译器 Zortech C++。Bright 也是系统编程语言 D 的创建者。他描述了 20 年前 D 引入数组边界检查后发生的事情: “这是一个巨大的胜利“。在另一条评论中,Bright回忆了如何使边界检查成为 D 语言的默认选项。

 

“事实证明,这是正确的选择。”

 

Rust 基金会杰出顾问Shane Miller发表在 LinkedIn 上的回应可能是最积极的,“很高兴你们没有止步于通过这一举措获得安全方面的胜利。“

 

“你们在识别 Bug 和提高可靠性方面所掌握的数据是一个很好的参考"。

 

声明:本文为 InfoQ 翻译,未经许可禁止转载。

 

原文链接:https://thenewstack.io/google-retrofits-spatial-memory-safety-onto-c/

2025-01-26 11:3210

评论

发布
暂无评论

初学字典-python

加里都好

设计千万级学生管理系统的考试试卷存储方案-模块四

小牧ah

架构实战营

分享三个可改进的体验

石云升

用户体验 体验设计 8月日更

【架构实战营】毕业设计

swordman

架构实战营

从java注解漫谈到typescript装饰器——注解与装饰器

zhoulujun

Java 注解 装饰器 ts 元数据

网络攻防学习笔记 Day98

穿过生命散发芬芳

态势感知 网络攻防 8月日更

PNG文件解读(2):PNG格式文件结构与数据结构解读—解码PNG数据

zhoulujun

png jpg

05-高性能复杂度

Lane

架构实战营模块四作业

王晓宇

架构实战营

安全世界观 | 常见WEB安全问题及防御策略汇总

架构精进之路

安全 8月日更

当农产品拥有“身份证”区块链技术如何助力农产品溯源监管?

CECBC

深度解析区块链数字票据及其优势

CECBC

06-高可用复杂度

Lane

毕业设计作业

薛定谔的指南针

架构实战营

Tensorflow API(一)

毛显新

人工智能 深度学习 tensorflow keras

Tensorflow随笔(一)

毛显新

人工智能 深度学习 tensorflow keras

【架构实战营】毕业总结

swordman

架构实战营

架构实战营-毕业设计项目

阿体

【前端 · 面试 】HTTP 总结(七)—— HTTP 缓存概述

编程三昧

面试 HTTP 8月日更 HTTP缓存

毕业感想

薛定谔的指南针

架构实战营

微信朋友圈的高性能复杂度分析

Saber

架构实战营

单向数据流-从共享状态管理:flux/redux/vuex漫谈异步数据处理

zhoulujun

React Redux vuex vue2 状态机

模块四作业

秀聪

架构训练营

JavaScript 开发人员应该理解的 this

devpoint

JavaScript js变量声明 this 8月日更

MongoDB 客户端怎么做负载均衡

海明菌

mongodb 负载均衡 客户端

Kafka 和 Kinesis 之间的对比和选择

HoneyMoose

三维旋转笔记:欧拉角/四元数/旋转矩阵/轴角-记忆点整理

zhoulujun

矩阵旋转 欧拉角 三维旋转 四元数

JIT-动态编译与AOT-静态编译:java/ java/ JavaScript/Dart乱谈

zhoulujun

Java dart JIT

ipfs挖矿怎么选择公司?ipfs挖矿收益怎么计算?

IPFS挖矿收益怎么计算 ipfs挖矿怎么选择公司

数字新基建助推能源互联网“一体两翼”区块链中台应用建设思考

CECBC

PNG文件解读(1):PNG/APNG格式的前世今生

zhoulujun

png

谷歌将空间内存安全功能“改造”到C++上_编程语言_David Cassel_InfoQ精选文章