github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/prog/collide_test.go (about) 1 // Copyright 2021 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package prog 5 6 import ( 7 "math/rand" 8 "testing" 9 10 "github.com/stretchr/testify/assert" 11 ) 12 13 func TestAssignRandomAsync(t *testing.T) { 14 tests := []struct { 15 os string 16 arch string 17 orig string 18 check func(*Prog) bool 19 }{ 20 { 21 "linux", "amd64", 22 `r0 = openat(0xffffffffffffff9c, &AUTO='./file1\x00', 0x42, 0x1ff) 23 write(r0, &AUTO="01010101", 0x4) 24 read(r0, &AUTO=""/4, 0x4) 25 close(r0) 26 `, 27 func(p *Prog) bool { 28 return !p.Calls[0].Props.Async 29 }, 30 }, 31 { 32 "linux", "amd64", 33 `r0 = openat(0xffffffffffffff9c, &AUTO='./file1\x00', 0x42, 0x1ff) 34 nanosleep(&AUTO={0x0,0x4C4B40}, &AUTO={0,0}) 35 write(r0, &AUTO="01010101", 0x4) 36 read(r0, &AUTO=""/4, 0x4) 37 close(r0) 38 `, 39 func(p *Prog) bool { 40 return !p.Calls[0].Props.Async || !p.Calls[1].Props.Async 41 }, 42 }, 43 { 44 "linux", "amd64", 45 `r0 = openat(0xffffffffffffff9c, &AUTO='./file1\x00', 0x42, 0x1ff) 46 r1 = dup(r0) 47 r2 = dup(r1) 48 r3 = dup(r2) 49 r4 = dup(r3) 50 `, 51 func(p *Prog) bool { 52 for _, call := range p.Calls[0 : len(p.Calls)-1] { 53 if call.Props.Async { 54 return false 55 } 56 } 57 return true 58 }, 59 }, 60 } 61 _, rs, iters := initTest(t) 62 r := rand.New(rs) 63 anyAsync := false 64 for _, test := range tests { 65 target, err := GetTarget(test.os, test.arch) 66 if err != nil { 67 t.Fatal(err) 68 } 69 p, err := target.Deserialize([]byte(test.orig), Strict) 70 if err != nil { 71 t.Fatal(err) 72 } 73 for i := 0; i < iters; i++ { 74 collided := AssignRandomAsync(p, r) 75 if !test.check(collided) { 76 t.Fatalf("bad async assignment:\n%s", collided.Serialize()) 77 } 78 for _, call := range collided.Calls { 79 anyAsync = anyAsync || call.Props.Async 80 } 81 } 82 } 83 if !anyAsync { 84 t.Fatalf("not a single async was assigned") 85 } 86 } 87 88 func TestDoubleExecCollide(t *testing.T) { 89 tests := []struct { 90 os string 91 arch string 92 orig string 93 duplicated string 94 shouldFail bool 95 }{ 96 { 97 "linux", "amd64", 98 `r0 = openat(0xffffffffffffff9c, &AUTO='./file1\x00', 0x42, 0x1ff) 99 r1 = dup(r0) 100 r2 = dup(r1) 101 r3 = dup(r2) 102 r4 = dup(r2) 103 r5 = dup(r3) 104 `, 105 `r0 = openat(0xffffffffffffff9c, &(0x7f0000000040)='./file1\x00', 0x42, 0x1ff) 106 r1 = dup(r0) 107 r2 = dup(r1) 108 r3 = dup(r2) 109 dup(r2) 110 dup(r3) 111 openat(0xffffffffffffff9c, &(0x7f0000000040)='./file1\x00', 0x42, 0x1ff) 112 dup(r0) 113 dup(r1) 114 dup(r2) 115 dup(r2) 116 dup(r3) 117 `, 118 false, 119 }, 120 } 121 _, rs, iters := initTest(t) 122 r := rand.New(rs) 123 for _, test := range tests { 124 target, err := GetTarget(test.os, test.arch) 125 if err != nil { 126 t.Fatal(err) 127 } 128 p, err := target.Deserialize([]byte(test.orig), Strict) 129 if err != nil { 130 t.Fatal(err) 131 } 132 for i := 0; i < iters; i++ { 133 collided, err := DoubleExecCollide(p, r) 134 if test.shouldFail && err == nil { 135 t.Fatalf("expected to fail, but it hasn't") 136 } else if !test.shouldFail && err != nil { 137 t.Fatalf("unexpected error: %s", err) 138 } 139 if test.duplicated != "" { 140 woProps := collided.Clone() 141 for _, c := range woProps.Calls { 142 c.Props = CallProps{} 143 } 144 serialized := string(woProps.Serialize()) 145 if serialized != test.duplicated { 146 t.Fatalf("expected:%s\ngot:%s", test.duplicated, serialized) 147 } 148 } 149 // TODO: also test the `async` assignment. 150 } 151 } 152 } 153 154 func TestDupCallCollide(t *testing.T) { 155 tests := []struct { 156 os string 157 arch string 158 orig string 159 rets []string 160 }{ 161 { 162 "linux", "amd64", 163 `r0 = openat(0xffffffffffffff9c, &AUTO='./file1\x00', 0x42, 0x1ff) 164 r1 = dup(r0) 165 r2 = dup(r1) 166 dup(r2) 167 `, 168 []string{ 169 `r0 = openat(0xffffffffffffff9c, &(0x7f0000000040)='./file1\x00', 0x42, 0x1ff) 170 dup(r0) (async) 171 r1 = dup(r0) 172 r2 = dup(r1) 173 dup(r2) 174 `, 175 `r0 = openat(0xffffffffffffff9c, &(0x7f0000000040)='./file1\x00', 0x42, 0x1ff) 176 r1 = dup(r0) 177 r2 = dup(r1) 178 dup(r2) (async) 179 dup(r2) 180 `, 181 }, 182 }, 183 } 184 _, rs, iters := initTest(t) 185 if iters > 100 { 186 // Let's save resources -- we don't need that many for these small tests. 187 iters = 100 188 } 189 r := rand.New(rs) 190 for _, test := range tests { 191 target, err := GetTarget(test.os, test.arch) 192 if err != nil { 193 t.Fatal(err) 194 } 195 p, err := target.Deserialize([]byte(test.orig), Strict) 196 if err != nil { 197 t.Fatal(err) 198 } 199 detected := map[string]struct{}{} 200 for i := 0; i < iters; i++ { 201 collided, err := DupCallCollide(p, r) 202 assert.NoError(t, err) 203 detected[string(collided.Serialize())] = struct{}{} 204 } 205 for _, variant := range test.rets { 206 _, exists := detected[variant] 207 assert.True(t, exists) 208 } 209 } 210 }