如何对模糊测试的输入设置约束?

Lia*_*lly 6 go fuzzing

假设我有以下结构

type Hdr struct{
  Src      uint16
  Dst      uint16
  Priotity byte
  Pktcnt   byte
  Opcode   byte
  Ver      byte
}
Run Code Online (Sandbox Code Playgroud)

我有两个函数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  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Run Code Online (Sandbox Code Playgroud)

我想使用 Go Fuzz 来生成随机、有效的Hdr实例,Marshal然后转换为二进制,Unmarshal并确保输出与原始输入匹配。

我遇到的主要问题是我不知道如何告诉 Go Fuzz 这样的字段Priotity不能大于 15,否则它们在编组时会被截断(只有 4 位)。我如何设置这个约束?

更新

这只是一个玩具盒。很多时候,像上面这样的协议opcode会触发二次更复杂的解析/审查。模糊测试仍然可以在约束内发现非常有用的问题(即:如果 Prio0x00和 Cnt0x2F辅助解析器将出错,因为分隔符是\)。

col*_*tor 3

编辑

我不确定模糊测试是否适合这里。模糊测试旨在查找意外输入:多字节 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
}
Run Code Online (Sandbox Code Playgroud)

在您的测试中 - 可以测试强制值 - 或跳过(如 @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)
    }
}
Run Code Online (Sandbox Code Playgroud)