GoFuzz无法正常触发crash研究
2021-05-29

Abstract

在使用gofuzz测试的过程中。
遇到明明很有问题、肯定能触发panic的语料,却没有生成对应的crash。
怀疑自己的使用姿势不对,遂对其进行了研究。本文记录一下实验过程和结果。

为了方便测试,设计了自定义Fuzz函数如下:
panic测试
通过测试panic是否会崩溃,来检查panic和return值之间的相关性。

猜测1: Fuzz函数return值存在特殊含义

为了测试return值对fuzz过程的影响,我删去了panic的设计。
当改变return的返回值时,fuzz的exec(程序执行次数) corpus(进化出的语料) restarts(程序重启次数)发生了如下的变化。

return之间的影响 (无panic)
仅return1
exec+ corpus+ restarts+
仅return 0 
exec+ corpus+ restarts+
仅return -1
exec+ corpus1 restarts+

可以看出在gofuzz中,Fuzz函数的return值有特殊的含义。

  • return 1 : 表示这次测试的样例是好的,成功的,阳性的。请多多使用这个突变分支的样例来测试。
  • return 0 : 表示这次测试样例正常,挺好的。就继续测吧,对后续测试样例的使用没有影响。
  • return -1: 表示这次测试使用的样例不给力,成阴性。在以后的测试中,减少这个突变分支的测试样例。

由于我使用gofuzz测试的目的,就是为了找出让程序无法正常执行的输入样例。因此,这里会自然的想到使用panic 配合 return 1.来实现: 发现crash的同时,能让后面的fuzz过程找到更多 Panic样例。

猜测2: 不同return的值 和 panic组合,可能产生不同结果。导致不panic

我通过修改33line的那个return值,来测试panic函数无法正常崩溃 是否和 return的值相关。
测试结果如下

-1 不crash
0 不crash
1 不crash
  • 看来和return的值没有关系。

猜测3: 同一个block中,panic和return不能一起使用

首先编写一个简单的测试程序,代码如下:
crash的代码
其中第16line的panic理论上必然触发
测试后发现果然触发了crash

于是我们在panic后面17line的位置添加return true
不crash的代码
测试发现,没有报错。在同一个block中,panic后面不能有return

猜测4: panic和Fuzz函数默认return之间的影响

在Fuzz函数中,如果自定义了panic点。则Fuzz函数的默认返回值必须唯一。
为了证实这一点,做了如下实验。

func Fuzz(data []byte) int {
	err := receivedCorpus(data)
	fmt.Println(err)
	if err != false {
		panic("22")
	}
	return 0
}

通过改变return 的返回值,来检查该值和panic之间的关系。
实验结果如下:

默认return 0
不 crash
默认return 1
crash
默认return -1
不crash

总结

经过测试,在gofuzz中使用panic来触发崩溃时,

  • 不能在panic后面直接跟return。否则会没有crash。
  • 另外,Fuzz函数的默认返回值必须是1,否则不会崩溃。