作者介绍:David Andersen, 美国宾西法尼亚州卡内基梅隆大学的计算机科学教授,居住于美国加州帕罗奥多市。热衷于计算机科学,关注机器学习中的各个领域。平时他也是一名极客,转轮和登山者爱好者,狂热的素食主义者。 摘要: 作者从自己的过往经历带领读者了解模糊测试在软件漏洞检测中的作用,并具体到最近火热的TensorFlow中的实际运用。给希望从事机器学习程序开发的人们,在相关的软件测试领域起到了很好的抛砖引玉的作用。 用LibFuzzer提高TensorFlow的稳定性 在过去的一年中,我一直在研究如何提高TensorFlow的稳定性。 正如我之前的文章提到过的,我在Google期间目标之一是挖掘编写优质代码的行业最佳实践。 在Google,编写良好的代码是从每个普通程序员开始的,需要在一个良好的内部测试环境下进行测试,并且能通过代码审查进行改进,同时还要使用一些出色的代码质量工具。 最近越来越多的人开始关注基于模糊测试的漏洞检查工具(在程序或程序库中输入随机值,以试图导致它们崩溃)在软件测试中的作用。John Regehr,是一位非常杰出的漏洞检查工具编译员。(?spm=5176.100239.blogcont72025.16.E5QtlY链接里是他对模糊测试类型的阐述。)Google的Zero项目在过去4年里对FreeType库进行了持续的漏洞检查测试,并在各种程序中发现了大量的安全漏洞。 (基于模糊测试的漏洞检查并不是一个全新的概念 - 它已经被软件安全研究人员使用了多年。它是由Barton Miller在1988年发明的。而在1997年,那时还不了解模糊测试的我使用了一个随机输入生成器,通过使用这种方法我在一个ISP终端服务器中发现了一个错误。我记得当时我为此非常开心)。 当下,模糊测试工具,如AFL和libFuzzer并不是完全随机的,而是可以被引导的:它们以一个输入样本(我们称为“语料库”)开始,然后对其进行不停的替换。这些工具使用编译器和二进制重写来进行替换从而追求代码覆盖的最大化。 有了良好的起始语料库和覆盖引导这两个要素,就能达到令人满意的测试结果。 我在Google期间,Chris Olah,Dario Amodei和DanMané发表了人工智能安全中的具体问题研究报告。 在文中他们讨论的问题和解决方案大都在机器学习领域,而我则对这些案例中所涉及的系统方面的问题感兴趣,例如奖励函数的缓冲溢出。传统的隔离方法,如沙盒测试,atv直播,并不能有效的防止这类奖励函数的问题 (它表现为一种逻辑错误,而不是系统运行错误)。 虽然基于模糊测试的漏洞检测并不能说是一个完整的解决方案,但它却启发了我去挖掘把它运用到TensorFlow中的价值。 所以,在Kostya Serebryany鼓励下,我决定为libFuzzer写一些针对TensorFlow内核的适配器。 有些人可能会指出这类错误并不会出现在那些强类型编程语言,但高性能的机器学习软件对性能,准确率, 和灵活性都有非常高的期望值。同时实现这三个目标是极具挑战的。我希望新的XLA编译器框架可以让这些目标更容易实现,但这个框架还在开发中, 最终的效果还有待观察。 如何开始? 所有libFuzzer测试都是从编写一个测试库调用或函数调用开始的,就像这样: 当编译后的漏洞检测机器码被执行时,它用在Data变量中提供的“随机”(已替换的)数据重复地调用该函数。如何将随机数据的Blob映射到对应用程序的调用,就是漏洞检测适配器程序员要做的。 当进行漏洞检测时,二进制代码通常使用LLVM的内存检测器进行编译,它会检测几个常见的内存错误,例如数组越界访问,并将其转换为程序崩溃。 libFuzzer驱动程序检测到崩溃并保存导致它的示例。 输出可能如下所示: 然后,保存为一个可以用来重现程序崩溃的文件。 等错误修复以后,我们通常会将此文件添加到Fuzz种子集,以备之后的回归测试使用。 TensorFlow中的运用 TensorFlow处理的大部分是数字信息,因此在这些操作中发现错误就变得很重要 - 例如,在尝试调试某个模型为什么不工作时,它可以大大减轻工作量。 但是测试数值结果需要一个正确的参考或规范。 在对TensorFlow的XLA编译器进行测试时一般会做这些,例如,通过使用CPU版本作为参考,并确保XLA版本产生相同的结果。 这是确保XLA正确性的一个重要测试,但是当我开始编写我的版本时,我没有这么做,也不想尝试为每个操作编写规范。 (责任编辑:本港台直播) |