AI代码分析器在curl项目中的突破性应用

本文详细介绍了AI驱动的代码分析工具如何在curl项目中发现传统工具难以检测的漏洞,包括协议实现错误、内存泄漏和文档不匹配等问题,展示了AI在代码质量提升方面的实际应用价值。

新一代分析器

(看我多么巧妙地在标题中没有提到AI!)

你知道我们已经收到了相当多的低质量报告发送到curl项目,所以当我们享受到这项技术的一些积极方面时,我写一些关于AI状态的文字似乎也是公平的。让我们按时间顺序来尝试做这件事。

事物的规模

curl有近18万行C89代码,不包括空行。C和H文件中约有63.7万字。相比之下,原著《战争与和平》(一本厚厚的书)由58.7万字组成。

curl的最初想法和痕迹起源于1996年底开始的httpget项目。这意味着这里有很多历史和遗产。

curl为28种URL方案进行网络传输,它已经在100多个操作系统和近30个CPU架构上运行。它可以用广泛的可选第三方库构建。

我们已经发布了超过270个curl版本,为此我们记录了总共超过12,500个错误修复。超过1,400人贡献了合并到仓库的提交,超过3,500人因提供帮助而受到感谢。这是一个非常活跃的开发项目。

从睡眠开始

2025年8月11日,有人报告了一个curl漏洞,该漏洞后来被证明是合法的,并随后发布为CVE-2025-9086。此漏洞的报告者是Google Big Sleep团队。该团队声称他们使用“由Google DeepMind和Google Project Zero开发的AI代理,主动搜索和发现软件中未知的安全漏洞”。

这是我们收到的第一个似乎使用AI准确发现并报告curl中安全问题的报告。当然,我们不知道在研究和报告中涉及了多少AI和多少人类。整个报告过程感觉非常人性化。

krb5-ftp

2025年9月中旬,我们从一个以前没有联系过的安全研究人员那里收到了一个新的针对curl的安全漏洞报告。该报告准确识别了一个问题,但由于纯粹的运气没有变成CVE:代码由于其他原因无法工作,因此实际上无法到达该漏洞。作为这一教训的直接结果,我们取消了krb5-ftp的支持。

ZeroPath

krb5-ftp问题的报告者名叫Joshua Rogers。他联系我们并慷慨地转发了大量他提取的更多潜在问题列表。据我理解,这主要是在ZeroPath的帮助下完成的。ZeroPath是一个具有AI功能的代码分析器。

在curl项目中,我们持续运行具有最大挑剔性的编译器,并使用scan-build、clang-tidy、CodeSonar、Coverity、CodeQL和OSS-Fuzz对其进行扫描,并且我们总是处理并修复它们报告的每一个警告和投诉,所以这个工具现在突然能产生超过两百个新的潜在问题有点令人惊讶。但它确实做到了。而这仅仅是开始。

三则有一个模式

当我们开始处理Joshua发来的巨大问题列表时,我们又收到了另一个针对curl的安全报告。这次是由Aisle的Stanislav Fort报告的(使用他们自己的AI驱动工具和代码分析流水线)。收到安全报告对我们来说并不罕见,我们每周往往会收到2-3份,但在9月23日,我们又收到了一份可以确认是真实漏洞的报告。再次,使用了AI驱动的分析工具。(在我写这篇博客文章时,这个特定问题尚未披露,所以我无法链接它。)

风向转变

当我惊讶于Joshua最初发送的列表中的一些问题的质量和见解时,我在Mastodon上发布了相关信息,后来被Hacker news、The Register、Elektroniktidningen等媒体转载。

这些新报告的问题在性质上感觉与代码分析器报告的缺陷非常相似:小错误、遗漏、缺陷、bug。它们大多数只是简单的变量混淆、返回代码混淆、奇怪情况下的内存泄漏、状态转换错误和可能导致问题的变量类型转换等。明显误报的非常少。

报告的质量让人感觉像是新一代的问题识别。就像从旧时代开始的工具进化阶梯一样。每一个新步骤都将水平提升了一个层次:

  • 在某个时刻,我认为是从2000年代初开始,C编译器在实际警告和检测许多错误方面变得更好,而在黑暗时代它们只是默默地允许这些错误。
  • 然后代码分析器将我们从那里带到了下一个层次,并在代码中发现了更多错误。
  • 我们在2010年代中期将模糊测试加入其中,并发现了大量在我们拥有之前从未意识到的问题。
  • 现在这种新型的,几乎像一个新类别的分析器,似乎能更好地连接点,并看到以前工具和分析器无法看到的模式。并告诉我们其中的差异。

25%左右

在最初的列表中,我们合并了大约50个单独可识别的错误修复。其余部分是一些误报,但也有许多我们认为不值得处理或者我们不太同意的次要问题。

小型海啸

我们(主要是Stefan Eissing和我自己)努力在短短几天内完成Joshua的最初列表。我们错误地认为这个列表就是“全部”。

Joshua随后通过立即交付第二个包含47个额外问题的列表为我们增添了趣味。接着是第三个列表,又增加了158个潜在问题。与此同时,Stanislav做了类似的事情,并向我们交付了两个列表,总共大约二十个可能的问题。

请不要误解我的意思。这是好事。这些问题质量很高,即使我们驳回的问题也常常有一些见解,并且明显误报的比例仍然很低且相当易于管理。我们发现的每一个bug并修复都使curl变得更好。每一次修复都改进了这个影响并赋能世界很大一部分的软件。

这两位先生提交的疑似问题总数现已超过四百个。对我们curl维护者来说是一大堆工作!

由于这些报告的问题可能包括安全敏感问题,我们决定不发布它们,而是将访问权限限制在报告者和curl安全团队。

在我写这篇文章时,我们仍在处理这些报告,但合理地假设我们很快会收到更多……

所有代码

与其他工具相比,这个工具的一个明显而强大的优势是它无需构建即可扫描所有源代码。这意味着它可以检测所有构建组合中使用的所有后端中的问题。旧式代码分析器需要适当的构建来分析,并且由于您可以用无数种后端设置(其中一些是特定于架构或操作系统的)以无数种组合构建curl,因此使用此类工具分析所有代码实际上是不可能的。

此外,这些工具还可以注入(部分)第三方库,并发现curl与其依赖项之间边界上的问题。

我认为这是它发现如此多问题的一个主要原因:它检查了许多其他分析器几乎没有研究过的代码。

几个例子

为了说明这个工具的“智能”水平,请允许我展示几个我认为能展示其能力的例子。这些是最近几周针对curl报告的问题,并且它们都已被修复。请注意,您可能需要了解一些关于curl做什么的知识才能正确理解这里的内容。

函数头注释错误

它正确地发现函数头中的文档错误地声称一个参数是可选的,而实际上它不是。修复方法是纠正注释。

1
2
3
# `Curl_resolv`: NULL输出参数解引用`*entry`
* **证据:** `lib/hostip.c`API承诺"在`entry`参数中返回一个指向该条目的指针(**如果提供了的话**)。"然而,代码包含无条件写入:`*entry = dns;`  `*entry = NULL;`
* **理由:** API允许`entry == NULL`,但实现在每个退出路径上都对其进行解引用,如果调用者传递`NULL`,会导致立即崩溃。

我可以补充一点,它如此认真地对待注释也可能在注释过时并陈述错误的“事实”时导致它报告错误的事情。这当然不应该发生,因为注释不应该撒谎!

代码破坏了telnet协议

它发现了一段telnet代码实际上不符合telnet协议并指出了这一点。我得说,这相当令人印象深刻。

1
2
Telnet子协商将未转义的用户控制值tn->subopt_ttype, tn->subopt_xdisploc, tn->telnet_vars)写入temp(第948989行)而不转义IAC0xFF
lib/telnet.c(第948989行)中,代码使用msnprintf将Telnet子协商有效载荷格式化到temp中,并直接将用户可控值tn->subopt_ttype(第948951行)、tn->subopt_xdisploc(第960963行)和来自tn->telnet_vars的v->data(第976989行)插入子选项数据中。然后使用swrite(第951963995行)将缓冲区temp写入套接字,而不复制CURL_IAC0xFF)字节。Telnet要求子协商数据内的任何IAC字节通过加倍进行转义;因为这些值没有被转义,其中任何一个中的0xFF字节将被解释为IAC命令,并可能破坏子协商流,导致协议错误或故障。

没有TFTP地址固定

另一个案例是,它似乎知道TFTP实现的最佳实践(在传输期间固定使用的IP地址),并且它检测到curl在代码中没有应用这个最佳实践,因此它正确地抱怨:

1
2
没有TFTP对等端/TID验证
TFTP接收处理程序在每次数据报时从recvfrom()更新state->remote_addr,并且不验证传入的数据包来自先前建立的服务器地址/端口(传输ID)。因此,任何能够向客户端发送UDP数据包的主机(例如,路径上的攻击者或本地网络对手)都可以注入具有预期下一个块号的DATA/OACK/ERROR数据包。客户端将接受有效载荷(Curl_client_write),确认它,并将后续通信切换到攻击者的地址,允许内容注入或会话劫持。正确的TFTP行为是绑定到第一个服务器TID,并忽略或错误处理来自其他TID的数据包。

没有其他人报告的内存泄漏

大多数内存泄漏是在有人运行代码并注意到在某些特定情况下并非所有内容都被释放时报告的。我们当然一直在测试中检查泄漏,但为了在测试中看到它们,我们需要运行那个确切的案例,并且有许多代码路径在测试中很难遍历。

除了进行测试,您当然可以通过手动审查代码来发现泄漏,但历史和经验告诉我们这是一种容易出错的方法。

1
2
3
4
5
6
7
# GSSAPI安全消息:在无效令牌长度时泄漏`output_token`
* **证据:** `lib/vauth/krb5_gssapi.c:205--207`。简短引用:
    ```c
    if(output_token.length != 4) { ... return CURLE_BAD_CONTENT_ENCODING; }
    ```
    `gss_release_buffer(&unused_status, &output_token);`调用稍后在第215行发生,因此这个早期返回泄漏了来自`gss_unwrap`的缓冲区。
* **理由:** 可通过恶意对等端发送非4字节安全消息达到;重复握手可能导致无限制堆增长(DoS)。

这个特定的bug看起来很简单,事后看来很容易发现,但它以这种形式在代码中公开存在了十多年。

更多是进化而非革命

我想当我声明AI工具帮助我们找到了22、70然后100个bug等等时,我可能震惊了一些人。我怀疑人们通常没有意识到并且没有考虑我们在这个项目中处理的错误修复频率。每个版本修复几百个bug对我们来说是正常的速度。当然,这个周期我们可能会达到一个新的记录,但我仍然没有因此而喘不过气来。

我不认为这个新工具是一场革命。它并没有大规模或 drastically 地改变代码或我们的开发方式。然而,它是一个优秀的新项目助手。一个强大的工具,可以突出显示需要更多关注的代码区域。一个非常受赞赏的进化步骤。

我当然可能说得太早了。也许它会发展得更多,然后变成一场革命。

伦理和道德决策

AI引擎消耗森林资源,并且它们是通过吸收他人的代码和工作构建的。以这种方式使用AI来改进开源在道德和伦理上是否正确?这是一个需要纠结的问题,我相信讨论将会继续。至少这种AI的使用并没有为我们生成他人代码的副本供我们使用,但它肯定从他人的代码中吸取了教训并找到了模式。但我希望我们所有人都是这样做的。

从体面的状态开始

我可以想象curl是使用这种级别工具的一个相当好的源代码,因为curl是古老的、成熟的,并且所有的小问题和缺陷都已经被打磨掉了。这是一个我们有高标准的项目,并且我们希望将其提得更高。我们喜欢获得额外帮助并找出我们可能疏忽的地方的机会。然后修复那些并再次尝试。一遍又一遍,直到时间的尽头。

AIxCC

在2025年8月举行的DEF CON 33会议上,DARPA举办了一场名为AI Cyber Challenge或简称AIxCC的比赛。在这场比赛中,参赛团队使用AI工具在项目中寻找人为注入的漏洞——零人工干预。在决赛中团队寻找问题的项目之一是……curl!

我已经被承诺会收到该练习的报告或发现列表,因为据推测团队发现的东西不仅仅是假插入的问题。当那发生时,我会回来报告。

展望未来

我们还没有在任何AI驱动的代码分析器在我们的CI设置中,但我期待着添加这样的工具。也许不止一个。

我们可以要求GitHub copilot进行拉取请求审查,但根据我尝试copilot进行审查的少量经验,它与我从Joshua和Stanislav那里收到的报告远不可比,而且坦率地说,它大多令人失望。我们不使用它。当然,这可能会改变,并且它可能有一天会变成一个强大的工具。

我们现在与这两位报告者都建立了建设性的沟通设置,这应该为我们未来进一步改进curl奠定坚实的基础。

我个人在开发过程中仍然完全不使用任何AI——除了偶尔的小实验。部分是因为它们似乎都强迫我使用VS code,而我在那上面完全失去了所有生产力。部分是因为我在实验中没有发现它非常高效。

有趣的是,这种富有成效的AI开发几乎与我们同样看到的AI垃圾 avalanche 同时发生,证明一个AI不一定像另一个AI。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计