aboutsummaryrefslogtreecommitdiffstats
path: root/prog/mutation.go
diff options
context:
space:
mode:
authorHrutvik Kanabar <hrutvik@google.com>2022-10-25 10:13:51 +0000
committerAleksandr Nogikh <wp32pw@gmail.com>2022-11-21 11:06:14 +0100
commitd0405298b24db0e2a6b2abfdc8c7e5ebbe49d1a0 (patch)
treec022669ce377e0c09376d60b45a01584c67c0989 /prog/mutation.go
parent7954d07c228dd9ce63b7ebd13239b4d1f2c35233 (diff)
prog, pkg/compiler: add `BufferCompressed` buffer type & `compressed_image` builtin
Create the `BufferCompressed` kind of `BufferType`, which will be used to represent compressed data. Create the corresponding `compressed_image` syzlang builtin, which is backed by `BufferCompressed`. For now, no syscalls use this feature - this will be introduced in future commits. We have to be careful to decompress the data before mutating, and re-compress before storing. We make sure that any deserialised `BufferCompressed` data is valid too. `BufferCompressed` arguments are mutated using a generic heatmap. In future, we could add variants of `BufferCompressed` or populate the `BufferType` sub-kind, using it to choose different kinds of heatmap for different uncompressed data formats. Various operations on compressed data must be forbidden, so we check for `BufferCompressed` in key places. We also have to ensure `compressed_image` can only be used in syscalls that are marked `no_{generate,minimize}`. Therefore, we add a generic compiler check which allows type descriptions to require attributes on the syscalls which use them.
Diffstat (limited to 'prog/mutation.go')
-rw-r--r--prog/mutation.go28
1 files changed, 28 insertions, 0 deletions
diff --git a/prog/mutation.go b/prog/mutation.go
index ca53b1c7b..147f75ac1 100644
--- a/prog/mutation.go
+++ b/prog/mutation.go
@@ -374,6 +374,30 @@ func (t *BufferType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []
case BufferText:
data := append([]byte{}, a.Data()...)
a.data = r.mutateText(t.Text, data)
+ case BufferCompressed:
+ data := a.Data()
+ if len(data) == 0 {
+ return
+ }
+ data, err := Decompress(data)
+ if err != nil {
+ panic(fmt.Sprintf("could not decompress data: %v", err))
+ }
+ if len(data) == 0 {
+ return // Do not mutate empty data.
+ }
+ hm := MakeGenericHeatmap(data)
+ // At least two mutations, up to about one mutation every 128 KB of heatmap size.
+ numMutations := r.Intn(hm.Size()/(1<<17)+1) + 2
+ for i := 0; i < numMutations; i++ {
+ index := hm.ChooseLocation(r.Rand)
+ width := 1 << uint(r.Intn(4))
+ if index+width > len(data) {
+ width = 1
+ }
+ storeInt(data[index:], r.Uint64(), width)
+ }
+ a.data = Compress(data)
default:
panic("unknown buffer kind")
}
@@ -663,6 +687,10 @@ func (t *BufferType) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool
// These are effectively consts (and frequently file names).
return dontMutate, false
}
+ if t.Kind == BufferCompressed {
+ // Prioritise mutation of compressed buffers, e.g. disk images (`compressed_image`).
+ return maxPriority, false
+ }
return 0.8 * maxPriority, false
}