速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

前车之鉴:苹果的 GoToFail Bug

  • 2014-03-12
  • 本文字数:2344 字

    阅读完需:约 8 分钟

新近发现的 iOS 和 OS X安全缺陷揭示出编码规范、单元测试、系统测试、代码复查方案、错误管理策略和工具部署方面的缺陷冰山。

ZDNet 的 Larry Seltzer 称这一缺陷“震撼且尴尬”,苹果同时为 iOS 6 发布补丁更是从侧面证实了其严重性。“苹果并不愿意 iOS 用户继续使用 iOS 6 系统,但尽管如此,他们还是修复了缺陷。这足以说明其严重程度。”Larry 说。

到这篇文章完成时,苹果已经为 iOS 和 OS X 发布了软件更新,用以修复该问题:一个能让攻击者拦截、获取并修改加密数据的通信漏洞。但从这个故事中,我们还是能够学到某些东西。

谷歌的Adam Langley 解释说,这一缺陷位于苹果开源发布的SSL/TLS 协议实现—— SecureTransport 框架中,缺陷的引发原因在于部分代码不可达。试看如下代码:

复制代码
static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
uint8_t *signature, UInt16 signatureLen)
{
OSStatus err;
...
if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
...
fail:
SSLFreeBuffer(&signedHashes);
SSLFreeBuffer(&hashCtx);
return err;
}

注意其中有两个连续的 goto fail 语句。由于 if 语句没有加大括号,因此执行时,第二处 goto fail 会让程序直接跳转到 fail 标签,从而避开 if 语句之后的验证。这会导致在跳转的那一刻 err 变量不含任何错误信息,方法也无法返回任何。Adam Langley 继续解释道:

签名验证将检查 ServerKeyExchange 消息中的签名。DHE 和 ECDHE 密文族将这一技术用于连接过程中的临时密钥交换。服务器发起请求:“这里是临时密钥和签名,你可以通过我的证书证实我是发起者。”如果这时临时密钥和证书链之间的关联被破坏,所有的验证都会失效。这种情况下虽然仍然可以向客户端发送正确的证书链,但握手过程可能用错误的私钥签名,甚至没有签名!我们无法证实服务器端是否持有与证书中公钥配对的私钥。

诚如 Larry Seltzer 所言,因为苹果没有给出更多细节,我们无从知道这一 bug 是如何被发现的,但这件事让他开始好奇苹果的代码复查实践。他还指出,虽然这个错误一眼就能够发现,但当你面对足有 1970 行长度的整个文件时,将其识别出来就会很难。

Twitter 上#gotofail 主题的很多评论者公然视“使用 goto”为罪魁祸首,最著名的当属 Dijkstra 论文中对 goto“有害”的定性。这点是无可争议的,荷兰代尔夫特理工大学的软件工程教授 Arie van Deursen 试着通过返回错误代码这种惯用法实现一种类似C 中的异常机制来解释goto 的用法,这样一来,那种惯用法就成了罪魁祸首。

Van Deursen 写道,实际上,返回错误代码惯用法普遍存在于含 bug 的文件中,并且本身存在一定的问题。 2005 年 van Deursen 与 Magiel Bruntink,Tom Tourwe 合著论文的主要成果之一就是,通过审查某相当规模的代码库发现“每千行代码中因为 return-error-code 惯用法而导致的缺陷密度达 2.1”。 这么高的缺陷密度的罪魁祸首是未检查调用、未正确传播的返回值以及未正确处理的错误条件导致的,落实了“这一惯用法相当容易出错”的罪名。

苹果前职员 Kevin Marks 在 van Deursen 的跟帖后留言指出,可以使用预处理宏使返回错误代码的方式更安全。这方面的例子包括 BailOSErr 以及致力于实现C 的异常机制方面的工作就是这样用的例子。

说起错误代码的管理,Chris Leishman 在评论van Deursen 观点时称,错误指示变量被初始化为success,这才是两行goto 真正引发漏洞的主要原因。如果错误指示变量的初始化改为OSStatus err = OSUnknownError,系统执行会更安全。

另一方面, Plausible Labs 的软件工程师 Landon Fuller 提供了bug 所影响那部分代码的可测性分析并证实 SSLVerifySignedServerKeyExchange 能够进行隔离性单元测试。 C. Keith Ray 强调了 TDD 的一个观点:“如果你要编写一条 if 语句,那你必须事先准备一个调用这条语句的测试。你需要在条件为真和为假的情况下分别测试”。

Arie van Deursen 指出这一事件还有更多值得争议的地方。

他最先注意到含 bug 的文件“明显不是自动规范化的,其中有大量格式不一的空格、制表符和代码注释”,而“正确的缩进能立刻显示正在发生的可疑事”,并让 bug 查找更容易。除此之外,他进一步建议“将编码格式作为一项安全特性”,而“将空格作为一项安全关注点”。

Langley 在其博客中写道,他认为代码复查是防止这类问题发生的有效手段。但 Arie van Deursen 指出,先前微软有一项代码复查研究曾证实以下观点:

复查并不是像很多项目成员所想的那样,通常情况下都能找出缺陷;而找出深层、微妙或是“宏”层次的问题就更罕见了。也许依靠这种程度的代码复查来保证质量境况堪忧。

最后一点,这种情况下工具也没起到作用,如 Langley 所说,Clang 的 -Wall 参数不会发现两行 goto 和其后的死代码。据 Simon Nicolussi 所言,Clang 提供了能发现该问题的 -Weverything 标识,但 GCC 默认去除了这一标识。这点也为 Peter Nelson ——另一位特定 -Wunreachable-code 参数存在指出者所证实。Van Deursen 指出主要问题在于死代码的删除从根本上讲是一个不可判定问题,这需要完备性和误报间的权衡,也正是因为这一原因,缺省情况下才不含不可达检验。

查看英文原文: Lessons Learned from Apple’s GoToFail Bug


感谢邵思华对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2014-03-12 08:063201

评论

发布
暂无评论
发现更多内容

从mybatis-plus-generator看如何编写代码生成器

Rubble

4月日更 4月月更

java培训redis的集群策略

@零度

redis JAVA开发

云融科技加入龙蜥社区,助力金融行业数字化转型

OpenAnolis小助手

数字化转型 龙蜥社区 CLA 云融科技

nginx proxy_next_upstream 与openresty balancer.set_more_tries的使用

飞翔

nginx openresty

Kafka设计的基本原理

平凡人生

区块链招聘会完美收官,行业大咖教你如何 Get Web3高薪职位

TinTinLand

区块链

【课程汇总】Hello HarmonyOS系列课程,手把手带你零基础入门

HarmonyOS开发者

HarmonyOS ArKUI 3.0

APISIX jwt-auth 插件存在错误响应中泄露信息的风险公告(CVE-2022-29266)

API7.ai 技术团队

api 网关 APISIX CVE

web前端培训React 泛型组件

@零度

前端开发 React

真正的量子计算机触手可及!英特尔宣布规模化生产硅量子比特

科技新消息

开发者友好型公链Neo | 如何连接 Web2 开发者到 Web3 世界

TinTinLand

区块链

在互联网+的背景下,企业如何创新客户服务?

小炮

客户服务

Docker Compose 部署Kibana和 Elasticsearch本地集群 8.1.3

Geek漫游指南

elasticsearch

Gartner调查研究:中国的数字化发展较之世界水平如何?高性能计算能否占据主导地位?

GPU算力

GPU服务器 GPU算力

友好型公链Neo,助力开发者轻松掌握区块链智能合约

TinTinLand

区块链

Ampere Computing释放观测云“芯”算力,强强联合推动可观测性发展

观测云

可观测性 可观测

观测云入驻阿里云计算巢,为用户构建稳定安全的云上连接

阿里云弹性计算

“开源之夏”活动火热报名中,丰厚奖金等你来拿!

云智慧AIOps社区

开源 活动 开源软件

Dubbo 编程之夏报名启动了

阿里巴巴云原生

如何写出有价值的竞品分析报告?

基调听云

竞品分析 基调听云

vue中使用element-resize-detector

CRMEB

深入理解JMM-CPU多核硬件架构剖析及Java内存模型

janyxe

JVM cpu Java内存模型

深度报告:异构时代,芯片需集成多个模板

Finovy Cloud

人工智能 云计算 gpu GPU服务器

人为什么看不到真相?

源字节1号

网站开发

CrashSight 接入上报常见问题及解决方案

WeTest

Talent Plan 学习营初体验:交流+坚持 开源协作课程学习的不二路径

PingCAP

基于 TiDB 的 Apache APISIX 高可用配置中心的最佳实践

API7.ai 技术团队

微服务网关 api 网关 APISIX TiDB

云原生虚拟化:基于 Kubevirt 构建边缘计算实例

火山引擎边缘云

容器 k8s 边缘计算 Kubevirt

量化系统开发,量化交易系统APP搭建

Geek_56201b

量化交易系统开发 量化交易源码 量化APP搭建

大数据培训Flink面试宝典

@零度

flink 大数据开发

NFT、GameFi、SocialFi、云存储,DFINITY 生态上最热赛道详解

TinTinLand

区块链

前车之鉴:苹果的GoToFail Bug_安全_Sergio De Simone_InfoQ精选文章