如何设置模糊输入的约束



假设我有以下结构

type Hdr struct{
Src      uint16
Dst      uint16
Priotity byte
Pktcnt   byte
Opcode   byte
Ver      byte
}

我有两个函数MarshalUnmarshal,它们将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之类的东西会触发第二次更复杂的解析/审查。模糊化仍然可以在约束中找到非常有用的问题(IE:如果Prio0x00和Cnt0x2F辅助解析器将出错,因为分隔符是(。

编辑

我不确定Fuzzing是否适合这里。Fuzzing被设计用于发现意外输入:多字节UTF8输入(有效和无效(;负值;巨大的价值、长的长度等等;边缘";案例。

在您的情况下,您知道:

  • 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)
}
}

为了跳过不感兴趣的结果,请在模糊函数中调用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!")
}
})

最新更新