From d0405298b24db0e2a6b2abfdc8c7e5ebbe49d1a0 Mon Sep 17 00:00:00 2001 From: Hrutvik Kanabar Date: Tue, 25 Oct 2022 10:13:51 +0000 Subject: 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. --- prog/mutation.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'prog/mutation.go') 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 } -- cgit mrf-deployment