今天,互联网瘫痪了好几个小时,计算机故障的多米诺骨牌效应让全球大片地区陷入数字黑暗。航空公司、金融机构、在线通信和无数其他服务都陷入瘫痪,让全世界都难以置信,一个看似坚不可摧的网络竟然崩溃了。
令人震惊的罪魁祸首是谁?根据网络安全公司 Crowdstrike 的惊人分析,这一切都归结于一行代码中的程序员错误——古老且内存占用高的 C++ 语言中一个看似无害的小故障。
在 X 上的一个帖子中,扎克·沃希斯 (Zach Vorhies) 声称,全球科技崩溃是由一行 C++ 代码中的错误引发的。对于那些不熟悉的人来说,沃希斯是谷歌的前雇员,他曾向美国司法部泄露了 950 页的内部文件,揭露了谷歌审查制度的细节。
Vorhies 在他的 X 帖子中解释道:“这是一个由于 C++ 内存不安全特性而导致的空指针问题。”
一行 C++ 代码中的错误如何导致微软全球中断
据 Vorhies 称,在软件更新期间,Crowdstrike 的代码尝试访问“内存地址 0x9c(或 156)”,这是一个无效的内存区域,随后引发了全球性中断。以下是 Vorhies 在 X 上分享的堆栈跟踪转储的屏幕截图。
CrowdStrike 堆栈跟踪转储
Crowdstrike分析:
它是来自内存不安全的 C++ 语言的空指针。
由于我是一名专业的 C++ 程序员,请让我为您解码此堆栈跟踪转储。pic.twitter.com/uUkXB2A8rm
— Zach Vorhies / Google Whistleblower (@Perpetualmaniac) 2024 年 7 月 19 日
“那么为什么内存地址 0x9c 会被访问?” Vorhies 问道。“答案是程序员的错误。在 CrowdStrike 使用的 C++ 中,地址 0x0 是一个特殊值,表示‘这里什么都没有’——尝试访问它会导致致命错误,”他解释道。
C++ 程序员应该通过在传递对象时检查空值来处理此问题。通常,您可能会看到这样的代码:string* p = get_name(); if (p == NULL) { print(“Could not get name”); }。
在 CrowdStrike 代码的堆栈转储中,Vorhies 注意到该程序试图读取内存地址 0x9c,该地址转换为数值 156。
Vorhies 进一步解释说,问题源于程序员在访问对象的成员变量之前未能验证对象的有效性。计算 NULL + 0x9C = 0x9C = 156 指向无效的内存区域。
“所以发生的事情是,程序员忘记检查它正在处理的对象是否无效,它试图访问其中一个对象成员变量…”
在此堆栈转储中,您可以看到它正在尝试读取内存值 0x9c。用人类数字来说,这是值 156。
所以发生的事情是,程序员忘记检查它正在处理的对象是否无效,它试图访问其中一个对象成员变量……
— Zach Vorhies / Google Whistleblower (@Perpetualmaniac) 2024 年 7 月 19 日
蓝屏死机
蓝屏死机
这个错误尤其严重,因为它涉及具有计算机特权访问权限的系统驱动程序。为了保护系统完整性,操作系统别无选择,只能立即崩溃。
“这就是导致蓝屏死机的原因,”沃希斯说。“虽然非特权代码通常可以通过终止程序从崩溃中恢复,但系统驱动程序却不能。当你的电脑崩溃时,通常是由于系统驱动程序出现故障。”
Vorhies 指出,如果程序员执行了 NULL 检查或使用了专为捕获此类问题而设计的现代工具,错误可能可以避免。不幸的是,这个漏洞被漏网之鱼,进入了生产环境,然后被 CrowdStrike 作为强制更新推出。糟糕!
如果程序员检查了 NULL,或者使用了检查这类东西的现代工具,它本可以被发现。但不知何故它进入了生产环境,然后被 Crowdstrike 强制推送更新……哎呀!
— Zach Vorhies / Google Whistleblower (@Perpetualmaniac) 2024 年 7 月 19 日
展望未来
展望未来,沃希斯建议微软实施更强大的政策来回滚有缺陷的驱动程序,而不是直接向客户推送有风险的更新。他还建议 CrowdStrike 应提升其代码安全官角色,专注于集成可以自动捕获此类问题的代码清理工具。此外,沃希斯表示,CrowdStrike 可能会考虑将其系统驱动程序从 C++ 重写为更现代的语言,如 Rust,这本质上可以避免此类问题。