diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2022-11-24 15:31:23 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2022-12-22 10:11:08 +0100 |
| commit | fb1fed72556fcc8fbe60d75a7e70a188f373aa19 (patch) | |
| tree | 82f5e20db255c76ff1ce806022de9bf582e7fdbd /prog/hints_test.go | |
| parent | 15722cf868a7299046186afe60e99edf938699f8 (diff) | |
prog: mutate compressed images with hints
Images are very large so the generic algorithm for data arguments
can produce too many mutants. For images we consider only
4/8-byte aligned ints. This is enough to handle all magic
numbers and checksums. We also ignore 0 and ^uint64(0) source bytes,
because there are too many of these in lots of images.
With this change the fuzzer was able to get past magic checks
in all of the following functions with our fake images:
- in fs/befs/super.c befs_check_sb()
- in fs/freevxfs/vxfs_super.c vxfs_fill_super()
- in fs/hpfs/super.c hpfs_fill_super()
- in fs/omfs/inode.c omfs_fill_super()
- in fs/qnx6/inode.c qnx6_check_first_superblock()
- in fs/ufs/super.c ufs_fill_super()
And even successfully mounted sysv filesystem and triggered
"sleeping function called from invalid context in __getblk_gfp"
when opening a file in the mounted filesystem.
Diffstat (limited to 'prog/hints_test.go')
| -rw-r--r-- | prog/hints_test.go | 96 |
1 files changed, 95 insertions, 1 deletions
diff --git a/prog/hints_test.go b/prog/hints_test.go index 5eec2724e..b01ac0204 100644 --- a/prog/hints_test.go +++ b/prog/hints_test.go @@ -10,6 +10,9 @@ import ( "reflect" "sort" "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/syzkaller/pkg/image" ) type ConstArgTest struct { @@ -318,6 +321,97 @@ func TestHintsCheckDataArg(t *testing.T) { } } +func TestHintsCompressedImage(t *testing.T) { + target := initTargetTest(t, "test", "64") + type Test struct { + input string + comps CompMap + output []string + } + var tests = []Test{ + { + "\x00\x11\x22\x33\x44\x55\x66\x77", + CompMap{ + // 1/2-bytes must not be replaced. + 0x00: compSet(0xaa), + 0x11: compSet(0xaa), + 0x1122: compSet(0xaabb), + 0x4455: compSet(0xaabb), + // Aligned 4-byte values are replaced in both little/big endian. + 0x00112233: compSet(0xaabbccdd), + 0x33221100: compSet(0xaabbccdd), + 0x44556677: compSet(0xaabbccdd), + 0x77665544: compSet(0xaabbccdd), + // Same for 8-byte values. + 0x0011223344556677: compSet(0xaabbccddeeff9988), + 0x7766554433221100: compSet(0xaabbccddeeff9988), + // Unaligned 4-bytes are not replaced. + 0x11223344: compSet(0xaabbccdd), + 0x22334455: compSet(0xaabbccdd), + }, + []string{ + // Mutants for 4-byte values. + "\xaa\xbb\xcc\xdd\x44\x55\x66\x77", + "\xdd\xcc\xbb\xaa\x44\x55\x66\x77", + "\x00\x11\x22\x33\xaa\xbb\xcc\xdd", + "\x00\x11\x22\x33\xdd\xcc\xbb\xaa", + // Mutants for 8-byte values. + "\xaa\xbb\xcc\xdd\xee\xff\x99\x88", + "\x88\x99\xff\xee\xdd\xcc\xbb\xaa", + }, + }, + { + "\x00\x11\x22\x33\x44\x55\x66\x77", + CompMap{ + // Special values are used as replacers. + 0x00112233: compSet(0, 0xffffffff), + }, + []string{ + // Mutants for 4-byte values. + "\x00\x00\x00\x00\x44\x55\x66\x77", + "\xff\xff\xff\xff\x44\x55\x66\x77", + }, + }, + { + // All 0s and 0xff must not be replaced. + "\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00", + CompMap{ + 0: compSet(0xaabbccdd), + 0xffffffffffffffff: compSet(0xaabbccddaabbccdd), + }, + nil, + }, + } + typ := target.SyscallMap["serialize3"].Args[0].Type.(*PtrType).Elem.(*BufferType) + if typ.Kind != BufferCompressed { + panic("wrong arg type") + } + for i, test := range tests { + t.Run(fmt.Sprintf("%v", i), func(t *testing.T) { + var res []string + arg := MakeDataArg(typ, DirIn, image.Compress([]byte(test.input))) + generateHints(test.comps, arg, func() { + res = append(res, string(arg.Data())) + }) + for i, compressed := range res { + data, dtor := image.MustDecompress([]byte(compressed)) + res[i] = string(data) + dtor() + } + sort.Strings(res) + sort.Strings(test.output) + if diff := cmp.Diff(test.output, res); diff != "" { + t.Fatalf("got wrong mutants: %v", diff) + } + data, dtor := image.MustDecompress(arg.Data()) + defer dtor() + if diff := cmp.Diff(test.input, string(data)); diff != "" { + t.Fatalf("argument got changed afterwards: %v", diff) + } + }) + } +} + func TestHintsShrinkExpand(t *testing.T) { t.Parallel() // Naming conventions: @@ -470,7 +564,7 @@ func TestHintsShrinkExpand(t *testing.T) { } for _, test := range tests { t.Run(fmt.Sprintf("%v", test.name), func(t *testing.T) { - res := shrinkExpand(test.in, test.comps, 64) + res := shrinkExpand(test.in, test.comps, 64, false) if !reflect.DeepEqual(res, test.res) { t.Fatalf("\ngot : %v\nwant: %v", res, test.res) } |
