如何为模糊测试设置输入约束?
How to set constraint on input for fuzzing?
假设我有以下结构
type Hdr struct{
Src uint16
Dst uint16
Priotity byte
Pktcnt byte
Opcode byte
Ver byte
}
我有两个函数 Marshal
和 Unmarshal
将 Hdr
编码为二进制格式:
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Src |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Dst |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Prio | Cnt | Opcode| Ver |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
我想使用 Go Fuzz 生成随机、有效的 Hdr
个实例,Marshal
然后是二进制,Unmarshal
二进制并确保输出与原始输入匹配.
我遇到的主要问题是我不知道如何告诉 Go Fuzz 像 Priotity
这样的字段不能大于 15,否则它们在编组时会被截断(只有 4 位)。如何设置此约束?
更新
这只是一个玩具箱。像上面这样的协议有很多次,其中 opcode
之类的东西会触发更复杂的次要 parsing/vetting。模糊测试仍然可以在约束内找到非常有用的问题(即:如果 Prio 0x00
和 Cnt 0x2F
辅助解析器将出错,因为分隔符是 \
)。
为了跳过无趣的结果,请在您的模糊测试函数中调用 t.Skip
。像这样:
f.Fuzz(func(t *testing.T, b []byte) {
a, err := Unmarshal(b)
if err != nil {
t.Skip()
return
}
c, err := Marshal(a)
if err != nil || !bytes.Equal(b, c) {
t.Errorf("Eek!")
}
})
编辑
我不确定模糊测试是否适合这里。模糊测试旨在发现意外输入:multi-byte UTF8 输入(有效且 non-valid);负值;巨大的价值,很长的长度等。这些将试图捕捉“边缘”情况。
在你这里,你知道:
Unmarshal
输入负载必须为 6 个字节(否则会出错)
- 你很清楚自己的内在“优势”
所以普通 testing.T
测试可能更适合这里。
保持简单。
如果您不想“浪费”一个 Fuzz 输入并且您知道代码的输入限制,您可以尝试这样的事情:
func coerce(h *Hdr) (skip bool) {
h.Priotity &= 0x0f // ensure priority is 0-15
h.OpCode %= 20 // ensure opcode is 0-19
return false // optionally skip this test
}
并且在您的测试中 - 可以测试强制值 - 或跳过(如@jch 所示):
import "github.com/google/go-cmp/cmp"
f.Fuzz(func(t *testing.T, src, dst uint16, pri, count, op, ver byte) {
h := Hdr{src, dst, pri, count, op, ver}
if coerce(&h) {
t.Skip()
return
}
bs, err := Marshal(h) // check err
h2, err := Unmarhsal(bs) // check err
if !cmp.Equal(h, h2) {
t.Errorf("Marshal/Unmarshal validation failed for: %+v", h)
}
}
假设我有以下结构
type Hdr struct{
Src uint16
Dst uint16
Priotity byte
Pktcnt byte
Opcode byte
Ver byte
}
我有两个函数 Marshal
和 Unmarshal
将 Hdr
编码为二进制格式:
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Src |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Dst |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Prio | Cnt | Opcode| Ver |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
我想使用 Go Fuzz 生成随机、有效的 Hdr
个实例,Marshal
然后是二进制,Unmarshal
二进制并确保输出与原始输入匹配.
我遇到的主要问题是我不知道如何告诉 Go Fuzz 像 Priotity
这样的字段不能大于 15,否则它们在编组时会被截断(只有 4 位)。如何设置此约束?
更新
这只是一个玩具箱。像上面这样的协议有很多次,其中 opcode
之类的东西会触发更复杂的次要 parsing/vetting。模糊测试仍然可以在约束内找到非常有用的问题(即:如果 Prio 0x00
和 Cnt 0x2F
辅助解析器将出错,因为分隔符是 \
)。
为了跳过无趣的结果,请在您的模糊测试函数中调用 t.Skip
。像这样:
f.Fuzz(func(t *testing.T, b []byte) {
a, err := Unmarshal(b)
if err != nil {
t.Skip()
return
}
c, err := Marshal(a)
if err != nil || !bytes.Equal(b, c) {
t.Errorf("Eek!")
}
})
编辑
我不确定模糊测试是否适合这里。模糊测试旨在发现意外输入:multi-byte UTF8 输入(有效且 non-valid);负值;巨大的价值,很长的长度等。这些将试图捕捉“边缘”情况。
在你这里,你知道:
Unmarshal
输入负载必须为 6 个字节(否则会出错)- 你很清楚自己的内在“优势”
所以普通 testing.T
测试可能更适合这里。
保持简单。
如果您不想“浪费”一个 Fuzz 输入并且您知道代码的输入限制,您可以尝试这样的事情:
func coerce(h *Hdr) (skip bool) {
h.Priotity &= 0x0f // ensure priority is 0-15
h.OpCode %= 20 // ensure opcode is 0-19
return false // optionally skip this test
}
并且在您的测试中 - 可以测试强制值 - 或跳过(如@jch 所示):
import "github.com/google/go-cmp/cmp"
f.Fuzz(func(t *testing.T, src, dst uint16, pri, count, op, ver byte) {
h := Hdr{src, dst, pri, count, op, ver}
if coerce(&h) {
t.Skip()
return
}
bs, err := Marshal(h) // check err
h2, err := Unmarhsal(bs) // check err
if !cmp.Equal(h, h2) {
t.Errorf("Marshal/Unmarshal validation failed for: %+v", h)
}
}