运用DeepState对API举行隐约测试(下) | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

运用DeepState对API举行隐约测试(下)

申博_新闻事件 申博 396次浏览 已收录 0个评论

运用DeepState对API举行隐约测试

前言 DeepState是一个框架,它为C和c++开发人员提供了一个公共接口,用于各种符号执行和模糊引擎。用户可以使用类似于Google Test的API编写一个测试工具,然后使用多个后端执行它,而不必了解底层引擎的复杂性。它支持编写单元测试和API

变异测试

变异测试(Mutation Testing)(偶然也叫做“变异剖析”)是一种在细节方面革新顺序源代码的软件测试要领。这些所谓的变异,是基于优越界说的变异操纵,这些操纵或许是模仿典范运用毛病(比方:运用毛病的操纵符或许变量名字),或许是强迫发作有效地测试(比方使得每一个表达式都即是0)。目的是资助测试者发明有效的测试,或许定位测试数据的缺点,或许是在实行中很少(或从不)运用的代码的缺点。

在上一篇文章中,我已手动引入了一个破绽,就是轻易举行变异测试。如今有很多可用于变异测试的工具,个中大局部是用Java编写的。一般而言,用C代码编写的工具都不太稳固,或很不好用。为此,我和其他同事还特地编写了一个工具,即universalmutator,这是一个地道基于正则表达式指定的代码行重写来天生变异的工具,允很多种言语的变异,包孕C和C ++和Swift,Solidity,Rust等很多之前没有变异测试工具的其他言语。我将在本文中运用universalmutator来检察隐约器在检测人工红黑树破绽方面的显现。除通例检测以外,universalmutator的一个长处是它能够发作很多新的变异工具,包孕那些常常同等但偶然会发作玄妙的行动差别的变异工具。也就是说,这些玄妙的变异工具极能够就是某个难以被检测到的破绽。别的,如今大多数变异体系都不支撑这些变异工具。

装置universalmutator并天生一些变异工具很轻易:

pip install universalmutator
mkdir mutants
mutate red_black_tree.c --mutantDir mutants

这将发作大批的变异工具,个中大多数不会编译(universalmutator不会剖析C代码,以是绝不新鲜它的很多变异工具都不是有效的C),我能够经由历程对变异工具运转“变异剖析”来剖析变异工具。

analyze_mutants red_black_tree.c "make clean; make" --mutantDir mutants

这将天生两个文件:killed.txt,包罗没有经由编译的变异工具,和notkilled.txt,包罗现实编译的1120个变异工具。为了检察变异某个工具是不是被禁用,剖析工具只是一定引号中的敕令是返回非零退出代码照样超时便可。默许超时为30秒,除非你的装备运转速率很慢,不然30秒最够用了。

若是我将包罗有效(编译)变异工具的notkilled.txt文件复制到另一个文件,我就能够举行一些真正的变异测试:

cp notkilled.txt compile.txt
analyze_mutants red_black_tree.c "make clean; make fuzz_rb; ./fuzz_rb" --mutantDir mutants --verbose --timeout 120--fromFile compile.txt

输出内容以下所示:

ANALYZING red_black_tree.c
COMMAND: ** ['make clean; make fuzz_rb; ./fuzz_rb'] **
#1: [0.0s 0.0% DONE]
  mutants/red_black_tree.mutant.2132.c NOT KILLED
  RUNNING SCORE: 0.0
...
Assertion failed: (left_black_cnt == right_black_cnt), function checkRepHelper, file red_black_tree.c, line 702.
/bin/sh: line 1: 30015 Abort trap: 6           ./fuzz_rb
#2: [62.23s 0.09% DONE]
  mutants/red_black_tree.mutant.1628.c KILLED IN 1.78541398048
  RUNNING SCORE: 0.5
  ...

类似的敕令将在DeepState 隐约器和libFuzzer上运转变异测试。只需把 make fuzz_rb; ./fuzz_rb改酿成make ds_rb; ./ds_rb –fuzz –timeout 60 –exit_on_fail,然后将其内置到DeepState 隐约器。关于libFuzzer,因为libFuzzer的冗杂输出会滋扰现实的变异结果的输出,为了加速测试速率,我要将情况变量LIBFUZZER_EXIT_ON_FAIL设置为TRUE,并将输出管道设置为/dev/null。

export LIBFUZZER_EXIT_ON_FAIL=TRUE
analyze_mutants red_black_tree.c "make clean; make ds_rb_lf; ./ds_rb_lf -use_value_profile=1 -detect_leaks=0 -max_total_time=60 >& /dev/null" --mutantDir mutants --verbose --timeout 120 --fromFile compile.txt

该工具会天生2602个变异工具,但现实编译的只要1120个。经由历程60秒的测试预算来剖析这些变异工具,我能够更好的相识隐约测试的质量。DeepState的BF(Brute-Force)算法隐约器禁用了个中的797个变异工具(71.16%),而John的原始隐约器则禁用了822(73.39%)个变异工具。接着,再花60秒隐约那些没有被这些隐约器禁用的变异体,我发明它们照样不会被禁用。libFuzzer的机能居然和DeepState惊人地类似,60秒内禁用797个变异体。这说明,变异工具是一样的。

可见,DeepState的隐约器在前期的隐约结果不如John的隐约器。这实在不新鲜,因为在隐约测试中,速率是霸道。因为DeepState正在剖析字撙节,为了生存瓦解而分叉,并天生大批的、用户掌握的日记纪录,因而它不克不及够像John的隐约器一样疾速的天生和实行测试。

而libFuzzer的速率以至更慢,除DeepState隐约器供应的一切效劳((除瓦解分岔,瓦解分岔由libFuzzer本身处置惩罚)以外,libFuzzer还一定代码掩盖率,并为每一个测试盘算值提要文件,并实行基于这些输入质量评价的将来测试所需的盘算。

这就是John的隐约器禁用25个变异工具的缘由,那DeepState就完全不禁用这些变异工具吗?不完全是。若是我搜检别的25个变异工具,就会发明每一个变异工具都触及到将指针上的等式对照酿成不等式。比方:

<   if ( (y == tree->root) ||
---
>   if ( (y <= tree->root) ||

DeepState隐约器没有找到这些变异工具,因为它在fork中运转每一个测试。别的,因为大多数分派都在fork中,代码没有分派充足的时候来运用充足的地点空间来对这些特定的搜检举行测试。从理论上讲,libFuzzer不应当涌现这类状况,它运转时没有分叉。固然,若是我们给迟缓而稳固的libFuzzer 5分钟而不是60秒,它也会捕捉到一切这些变异工具。再多的隐约处置惩罚也不克不及资助DeepState隐约器,在这类状况下,这个破绽就显得异常新鲜,而且不太轻易被疏忽。题目不在于隐约器的速率,也不在于测试的质量,而是分歧的隐约测试情况在我现实运转的测试中发作纤细差别。

要处理这个题目,就只要在DeepState中增加了一个选项,使接纳BF(Brute-Force)算法的隐约器以非分叉形式运转:–no_fork。不幸的是,这不是一个完全的处理方案。虽然我如今能够检测到这些破绽,但我没法为它们天生一个好的生存测试用例,因为失利取决于已发出的一切malloc,和某些指针的确实地点。然则,事实证实–no_fork有一个更主要的优点:它大大加速了mac OS上的隐约测试和测试重放速率。不外我在示例中省略了它,因为它使剖析失利缘由变得复杂,但你应当将其用于mac OS上的大多数隐约测试和测试重放。

如今,我能够确实的说,关于大多数隐约测试的企图和目的,DeepState与John的隐约器一样壮大,且DeepState易于完成,而且更便于调试和回归测试。

变异工具的检测

以上我胜利的处理了分歧隐约器上所禁用的那些变异工具之间的差别,接下来,我就来说一说那些剩下的没有被禁用的变异工具。

运用任何一种隐约器举行五分钟的隐约测试,都没有禁用剩下的变异工具。它们在测试中是不是显现破绽?如今,有多种要领能够检测等效的变异工具(现实上不会转变顺序语义的变异工具,因而不克不及够被禁用),比方对照优化编译器天生的二进制文件。为了本文的解说轻易,我将只搜检298个未被禁用的变异工具的随机样本,以一定最少大多数未被禁用的变异工具都是无意义的。

第一个变异工具变动解释中的<=,我们不克不及够禁用它。对照编译后的二进制文件就能够证实这一点。

第二个变异工具修改了InorderTreePrint函数中的代码,隐约器会明白挑选不测试该工具。经由历程对照二进制文件没法检测到这一变异,若是我的隐约器从未掩盖过这段代码,则它不克不及很好地检测代码中的破绽。

第三个变异工具在RBTreeCreate函数中将赋值变动为第44行的temp->key,因而赋值为1而不是0。若是我依照代码的发起并检察标头文件中关于root和nil的解释,我能够看到它们被用作标记。或许root和nil中的确实数据值可有可无,因为我只经由历程指针对照来检测它们。

第四个变异工具删除在第35行的赋值newTree-> PrintKey = PrintFunc,再说一遍,因为我从来没有打印过树,以是这是检测不到的。

第五个变异工具在批评中,第六个变异工具变动断言中的指针对照。

686c686
<     assert (node->right->parent == node);
---
>     assert (node->right->parent >= node);

若是假定我对原始代码始终保持断言,那末将==变动为更宽松的>=显着也是能够的。

第七个变异工具在批评中,第八个变异工具删除一个断言。一样,删除断言是不会致使先前通报的测试发作失利,除非断言涌现题目!

————————————-

申博网络安全巴士站

申博-网络安全巴士站是一个专注于网络安全、系统安全、互联网安全、信息安全,全新视界的互联网安全新媒体。

————————————-

第九个变异工具转变了一个赤色赋值:

243c243
<       x->parent->parent->red=1;
---
>       x->parent->parent->red=-1;

因为我没有搜检赤色字段的确实值,而是运用它举行分支(因而一切非零值都是雷同的),以是如许做没有题目。

第十个变异工具再次位于InorderTreePrint函数中。

此时,若是我真的要把这个红黑树作为症结代码,我能够会举行以下操纵:

1. 建立一个工具(好比一个10行Python剧本)来删除解释、InorderTreePrint函数内部的一切变体,或许直接删除断言。

2.编译一切变异工具并对照二进制文件和原始文件,以删除显着的等效变异工具和冗余变异工具。这一步能够有点耗时,因为编译时天生的时候戳,编译器实在不老是天生等效的二进制文件,这就是我在上面的议论中跳过它的缘由。

3.仔细搜检盈余的变异工具(也许200个摆布),以确保我没有脱漏任何东西。

(1)制造一个测试天生器;

(2)运用变异测试;

(3)视察现实盈余的变异工具,并运用它们革新我们的测试,这个历程能够被认为是一个变异驱动的测试历程。关于异常症结的小段代码,这多是构建有效的隐约机制的异常有效的要领。它曾资助过Paul E. McKenney发明了Linux内核RCU模块中真正破绽。

优化隐约测试过

除举行变异工具的隐约测试外,你还能够隐约代码。若是我真的将红黑树作为症结代码测试,须要的时候能够会凌驾五分钟。

哪一个隐约器最合适隐约代码呢?虽然我很难一定,但公道的要领是起首运用libFuzzer天生一个大型的测试语料库,从而在未变异的红黑树上完成高掩盖率。然后,我能够实验对每一个变异工具举行更长时候的隐约测试,运用测试语料库来确保我不会消费大局部时候在“进修”红黑树API上。

在原始代码上天生语料库一小时后,我从该语料库最先运转libFuzzer,运转时候为十分钟。以这类体式格局天生的测试能够在这里找到,这会禁用多少个分外的变异工具?在我的3%样本中,这个数目会少于30个。如上所述,经由历程删除解释变异、打印函数变异和删除断言,一个简朴的剧本能够将须要剖析的有意义的、未禁用的变异的数目削减到174个。事实上,这类更具侵略性(也更耗时)的隐约处置惩罚会在一分钟内禁用John的隐约器并在五分钟内禁用libFuzzer。纵然是长达一小时的libFuzzer运转一小时的语料库也只会禁用别的三个变异工具,而这些变异工具并非很有意义。禁用了一个free挪用,内存走漏会终究禁用libFuzzer。

标记实行

注重:标记实行这局部如今在Mac体系上不起作用,除非你晓得充足的交织编译学问,而且能够运用二进制剖析工具。我是在Docker中的Linux上运转标记实行的。

DeepState还支撑标记实行,依据某些界说,标记实行只是另一种隐约测试(白盒隐约测试)。不幸的是,如今无论是Manticore照样angr(我善于的两个二进制剖析引擎)都没法扩展到搜刮深度为100完全的红黑树或文件体系示例。这实在不新鲜,因为工具正在实验天生代码中一切能够的途径!然则,仅仅将深度降低到一个更公道的数字也是不敷的。纵然在深度为3时,也能够涌现求解器超时毛病。以是,我运用了symex.cpp,它实行更简朴的插进去或删除形式,且一连实行三次。

clang -c red_black_tree.c container.c stack.c misc.c
clang++ -o symex symex.cpp -ldeepstate red_black_tree.o stack.o misc.o container.o -static -Wl,--allow-multiple-definition,--no-export-dynamic
deepstate-manticore ./symex --log_level 1

结果将是掩盖代码中一切途径的测试,生存在out目次中。这能够须要相称长的时候才能运转,因为每条途径能够须要一两分钟才能天生。若是deepstate-manticore太慢,请实验deepstate-angr。分歧的代码合适分歧的标记实行引擎。 

INFO:deepstate.mcore:Running 1 tests across 1 workers
TRACE:deepstate:Running RBTree_TinySymex from symex.cpp(65)
TRACE:deepstate:symex.cpp(80): 0: INSERT:0 0x0000000000000000
TRACE:deepstate:symex.cpp(85): 0: DELETE:0
TRACE:deepstate:symex.cpp(80): 1: INSERT:0 0x0000000000000000
TRACE:deepstate:symex.cpp(85): 1: DELETE:0
TRACE:deepstate:symex.cpp(80): 2: INSERT:0 0x0000000000000000
TRACE:deepstate:symex.cpp(85): 2: DELETE:-2147483648
TRACE:deepstate:Passed: RBTree_TinySymex
TRACE:deepstate:Input: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...
TRACE:deepstate:Saved test case in file out/symex.cpp/RBTree_TinySymex/89b9a0aba0287935fa5055d8cb402b37.pass
TRACE:deepstate:Running RBTree_TinySymex from symex.cpp(65)
TRACE:deepstate:symex.cpp(80): 0: INSERT:0 0x0000000000000000
TRACE:deepstate:symex.cpp(85): 0: DELETE:0
TRACE:deepstate:symex.cpp(80): 1: INSERT:0 0x0000000000000000
TRACE:deepstate:symex.cpp(85): 1: DELETE:0
TRACE:deepstate:symex.cpp(80): 2: INSERT:0 0x0000000000000000
TRACE:deepstate:symex.cpp(85): 2: DELETE:0
TRACE:deepstate:Passed: RBTree_TinySymex
...

能够看到583个天生的测试像之前一样举行变异剖析,这是因为我只是在重放测试,而不是实行标记实行。以是如今我能够在checkRep和RBTreeVerify搜检中增加已删除的搜检,经由历程运用-DREPLAY编译symex.cpp来加速标记实行。天生的测试能够在不到一秒的时候内(在准确的red_black_tree.c上运转)禁用428个变异工具(38.21%)。这比隐约测试要低很多,而且比libFuzzer一小时在语料库中禁用的797(71.16%)更差。然则,个中五个被禁用的变异工具是未被我的任何隐约器禁用的变异工具,纵然是放在libFuzzer中运转十分钟。

703c703
<   return left_black_cnt + (node->red ? 0 : 1);
---
>   return left_black_cnt / (node->red ? 0 : 1);
703c703
<   return left_black_cnt + (node->red ? 0 : 1);
---
>   return left_black_cnt % (node->red ? 0 : 1);
703c703
<   return left_black_cnt + (node->red ? 0 : 1);
---
>   /*return left_black_cnt + (node->red ? 0 : 1);*/
701c701
<   right_black_cnt = checkRepHelper (node->right, t);
---
>   /*right_black_cnt = checkRepHelper (node->right, t);*/
700c700
<   left_black_cnt = checkRepHelper (node->left, t);
---
>   /*left_black_cnt = checkRepHelper (node->left, t);*/

这些破绽都在checkRep代码本身中,以至不是标记实行的目的。虽然这些破绽不触及现实的红黑树破绽,但这也间接注解我的隐约器能够许可将纤细的破绽引入红黑树的工具中以搜检其本身的有效性。在现实的操纵情况中,这些多是严峻的破绽,而且在基于隐约的测试中一定显现出一个破绽。为了相识检测这些破绽的难度,我实验在每一个变异工具上运用libFuzzer,我用一小时的语料库作为隐约测试的工具,再对每一个变异工具举行一次隐约测试。它依然没法检测到这些变异工具。

虽然运用标记实行天生测试须要更多的盘算才能,而且能够须要更多的人力,然则结果的异常完全(若是局限有限)测试能够检测纵然是攻击性隐约测试能够会错过的破绽。进修运用DeepState会使测试中夹杂隐约和标记实行变得轻易。纵然你须要一个用于标记实行工作的新工具,它也能够与大多数基于隐约的测试同享代码。DeepState的终究目的是运用不依赖于底层引擎的高等战略来进步API序列测试的标记实行的可伸缩性。

有关怎样运用标记实行的更多信息,请参阅DeepState申报。

代码掩盖率

我没有在我的隐约测试中检察代码掩盖率,缘由很简朴,若是我情愿运用变异测试,并搜检一切未被禁用的变异工具,那末检察代码掩盖率就没有意义了。实在,libFuzzer和标记实行引擎的目的是最大限制地进步掩盖率,但就我本文的目的而言,变异工具才是重点。究竟结果,若是我不掩盖变异的代码,就很难禁用它。固然,在隐约器应用开辟的初期阶段,测试代码掩盖率是异常有效的。这是因为变异测试是异常高贵的,而你只是想晓得你是不是已完成了大局部代码。然则关于专业的测试,不只须要测试代码掩盖率,还必须测试它的功用。事实上,如今,关于代码掩盖有效性的大多数科学证据都依赖于变异测试。

总结

有关运用DeepState测试API的更多示例,请参阅TestFs示例,该示例测试了用户级的、类似ext3的文件体系,或许对照谷歌的leveldb和Facebook的rocksdb项目。有关DeepState的更多详细信息,请参阅我的NDSS 2018二进制剖析研究研讨会论文。

运用DeepState对API举行隐约测试

前言 DeepState是一个框架,它为C和c++开发人员提供了一个公共接口,用于各种符号执行和模糊引擎。用户可以使用类似于Google Test的API编写一个测试工具,然后使用多个后端执行它,而不必了解底层引擎的复杂性。它支持编写单元测试和API


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明运用DeepState对API举行隐约测试(下)
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址