github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/prog/prog_test.go (about) 1 // Copyright 2015 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 "bytes" 8 "fmt" 9 "math/rand" 10 "strings" 11 "testing" 12 13 "github.com/google/syzkaller/pkg/testutil" 14 ) 15 16 func TestGeneration(t *testing.T) { 17 target, rs, iters := initTest(t) 18 ct := target.DefaultChoiceTable() 19 for i := 0; i < iters; i++ { 20 target.Generate(rs, 20, ct) 21 } 22 } 23 24 func TestDefault(t *testing.T) { 25 target, _, _ := initTest(t) 26 ForeachType(target.Syscalls, func(typ Type, ctx *TypeCtx) { 27 arg := typ.DefaultArg(ctx.Dir) 28 if !isDefault(arg) { 29 t.Errorf("default arg is not default: %s\ntype: %#v\narg: %#v", 30 typ, typ, arg) 31 } 32 }) 33 } 34 35 func TestDefaultCallArgs(t *testing.T) { 36 testEachTarget(t, func(t *testing.T, target *Target) { 37 for _, meta := range target.SyscallMap { 38 if meta.Attrs.Disabled { 39 continue 40 } 41 // Ensure that we can restore all arguments of all calls. 42 prog := fmt.Sprintf("%v()", meta.Name) 43 p, err := target.Deserialize([]byte(prog), NonStrict) 44 if err != nil { 45 t.Fatalf("failed to restore default args in prog %q: %v", prog, err) 46 } 47 if len(p.Calls) != 1 || p.Calls[0].Meta.Name != meta.Name { 48 t.Fatalf("restored bad program from prog %q: %q", prog, p.Serialize()) 49 } 50 s0 := string(p.Serialize()) 51 p.sanitizeFix() 52 s1 := string(p.Serialize()) 53 if s0 != s1 { 54 t.Fatalf("non-sanitized program or non-idempotent sanitize\nwas: %v\ngot: %v", s0, s1) 55 } 56 } 57 }) 58 } 59 60 func testSerialize(t *testing.T, verbose bool) { 61 target, rs, iters := initTest(t) 62 ct := target.DefaultChoiceTable() 63 for i := 0; i < iters; i++ { 64 p := target.Generate(rs, 10, ct) 65 var data []byte 66 mode := NonStrict 67 if verbose { 68 data = p.SerializeVerbose() 69 mode = Strict 70 } else { 71 data = p.Serialize() 72 } 73 p1, err := target.Deserialize(data, mode) 74 if err != nil { 75 t.Fatalf("failed to deserialize program: %v\n%s", err, data) 76 } 77 if p1 == nil { 78 t.Fatalf("deserialized nil program:\n%s", data) 79 } 80 var data1 []byte 81 if verbose { 82 data1 = p1.SerializeVerbose() 83 } else { 84 data1 = p1.Serialize() 85 } 86 if len(p.Calls) != len(p1.Calls) { 87 t.Fatalf("different number of calls") 88 } 89 if !bytes.Equal(data, data1) { 90 t.Fatalf("program changed after serialize/deserialize\noriginal:\n%s\n\nnew:\n%s", data, data1) 91 } 92 } 93 } 94 95 func TestSerialize(t *testing.T) { 96 testSerialize(t, false) 97 } 98 99 func TestSerializeVerbose(t *testing.T) { 100 testSerialize(t, true) 101 } 102 103 func TestVmaType(t *testing.T) { 104 target, rs, iters := initRandomTargetTest(t, "test", "64") 105 ct := target.DefaultChoiceTable() 106 meta := target.SyscallMap["test$vma0"] 107 r := newRand(target, rs) 108 pageSize := target.PageSize 109 for i := 0; i < iters; i++ { 110 s := newState(target, ct, nil) 111 calls := r.generateParticularCall(s, meta) 112 c := calls[len(calls)-1] 113 if c.Meta.Name != "test$vma0" { 114 t.Fatalf("generated wrong call %v", c.Meta.Name) 115 } 116 if len(c.Args) != 6 { 117 t.Fatalf("generated wrong number of args %v", len(c.Args)) 118 } 119 check := func(v, l Arg, min, max uint64) { 120 va, ok := v.(*PointerArg) 121 if !ok { 122 t.Fatalf("vma has bad type: %v", v) 123 } 124 la, ok := l.(*ConstArg) 125 if !ok { 126 t.Fatalf("len has bad type: %v", l) 127 } 128 if va.VmaSize < min || va.VmaSize > max { 129 t.Fatalf("vma has bad size: %v, want [%v-%v]", 130 va.VmaSize, min, max) 131 } 132 if la.Val < min || la.Val > max { 133 t.Fatalf("len has bad value: %v, want [%v-%v]", 134 la.Val, min, max) 135 } 136 } 137 check(c.Args[0], c.Args[1], 1*pageSize, 1e5*pageSize) 138 check(c.Args[2], c.Args[3], 5*pageSize, 5*pageSize) 139 check(c.Args[4], c.Args[5], 7*pageSize, 9*pageSize) 140 } 141 } 142 143 func TestFsckAttr(t *testing.T) { 144 target, err := GetTarget("test", "64") 145 if err != nil { 146 t.Fatal(err) 147 } 148 149 syscall := target.SyscallMap["test$fsck_attr"] 150 if syscall == nil { 151 t.Fatal("could not find test$fsck_attr in sys/test") 152 } 153 154 if syscall.Attrs.Fsck != "fsck.test -n" { 155 t.Fatalf("unexpected fsck command %s", syscall.Attrs.Fsck) 156 } 157 } 158 159 // TestCrossTarget ensures that a program serialized for one arch can be 160 // deserialized for another arch. This happens when managers exchange 161 // programs via hub. 162 func TestCrossTarget(t *testing.T) { 163 if testutil.RaceEnabled { 164 t.Skip("skipping in race mode, too slow") 165 } 166 t.Parallel() 167 const OS = "linux" 168 var archs []string 169 for _, target := range AllTargets() { 170 if target.OS == OS { 171 archs = append(archs, target.Arch) 172 } 173 } 174 for _, arch := range archs { 175 target, err := GetTarget(OS, arch) 176 if err != nil { 177 t.Fatal(err) 178 } 179 var crossTargets []*Target 180 for _, crossArch := range archs { 181 if crossArch == arch { 182 continue 183 } 184 crossTarget, err := GetTarget(OS, crossArch) 185 if err != nil { 186 t.Fatal(err) 187 } 188 crossTargets = append(crossTargets, crossTarget) 189 } 190 t.Run(fmt.Sprintf("%v/%v", OS, arch), func(t *testing.T) { 191 t.Parallel() 192 testCrossTarget(t, target, crossTargets) 193 }) 194 } 195 } 196 197 func testCrossTarget(t *testing.T, target *Target, crossTargets []*Target) { 198 ct := target.DefaultChoiceTable() 199 rs := testutil.RandSource(t) 200 iters := 100 201 if testing.Short() { 202 iters /= 10 203 } 204 for i := 0; i < iters; i++ { 205 p := target.Generate(rs, 20, ct) 206 testCrossArchProg(t, p, crossTargets) 207 p, err := target.Deserialize(p.Serialize(), NonStrict) 208 if err != nil { 209 t.Fatal(err) 210 } 211 testCrossArchProg(t, p, crossTargets) 212 p.Mutate(rs, 20, ct, nil, nil) 213 testCrossArchProg(t, p, crossTargets) 214 p, _ = Minimize(p, -1, MinimizeCorpus, func(*Prog, int) bool { 215 return rs.Int63()%2 == 0 216 }) 217 testCrossArchProg(t, p, crossTargets) 218 } 219 } 220 221 func testCrossArchProg(t *testing.T, p *Prog, crossTargets []*Target) { 222 serialized := p.Serialize() 223 for _, crossTarget := range crossTargets { 224 _, err := crossTarget.Deserialize(serialized, NonStrict) 225 if err == nil || strings.Contains(err.Error(), "unknown syscall") { 226 continue 227 } 228 t.Fatalf("failed to deserialize for %v/%v: %v\n%s", 229 crossTarget.OS, crossTarget.Arch, err, serialized) 230 } 231 } 232 233 func TestSpecialStructs(t *testing.T) { 234 testEachTargetRandom(t, func(t *testing.T, target *Target, rs rand.Source, iters int) { 235 _ = target.GenerateAllSyzProg(rs) 236 ct := target.DefaultChoiceTable() 237 for special, gen := range target.SpecialTypes { 238 t.Run(special, func(t *testing.T) { 239 var typ Type 240 for i := 0; i < len(target.Syscalls) && typ == nil; i++ { 241 ForeachCallType(target.Syscalls[i], func(t Type, ctx *TypeCtx) { 242 if ctx.Dir == DirOut { 243 return 244 } 245 if s, ok := t.(*StructType); ok && s.Name() == special { 246 typ = s 247 } 248 if s, ok := t.(*UnionType); ok && s.Name() == special { 249 typ = s 250 } 251 }) 252 } 253 if typ == nil { 254 t.Fatal("can't find struct description") 255 } 256 g := &Gen{newRand(target, rs), newState(target, ct, nil)} 257 for i := 0; i < iters/len(target.SpecialTypes); i++ { 258 var arg Arg 259 for i := 0; i < 2; i++ { 260 arg, _ = gen(g, typ, DirInOut, arg) 261 if arg.Dir() != DirInOut { 262 t.Fatalf("got wrong arg dir %v", arg.Dir()) 263 } 264 } 265 } 266 }) 267 } 268 }) 269 } 270 271 func TestEscapingPaths(t *testing.T) { 272 paths := map[string]bool{ 273 "/": true, 274 "/\x00": true, 275 "/file/..": true, 276 "/file/../..": true, 277 "./..": true, 278 "..": true, 279 "file/../../file": true, 280 "../file": true, 281 "./file/../../file/file": true, 282 "": false, 283 ".": false, 284 "file": false, 285 "./file": false, 286 "./file/..": false, 287 } 288 for path, want := range paths { 289 got := escapingFilename(path) 290 if got != want { 291 t.Errorf("path %q: got %v, want %v", path, got, want) 292 } 293 } 294 } 295 296 func TestFallbackSignal(t *testing.T) { 297 type desc struct { 298 prog string 299 info []CallInfo 300 } 301 tests := []desc{ 302 // Test restored errno values and that non-executed syscalls don't get fallback signal. 303 { 304 ` 305 fallback$0() 306 fallback$0() 307 fallback$0() 308 `, 309 []CallInfo{ 310 { 311 Flags: CallExecuted, 312 Errno: 0, 313 Signal: make([]uint64, 1), 314 }, 315 { 316 Flags: CallExecuted, 317 Errno: 42, 318 Signal: make([]uint64, 1), 319 }, 320 {}, 321 }, 322 }, 323 // Test different cases of argument-dependent signal and that unsuccessful calls don't get it. 324 { 325 ` 326 r0 = fallback$0() 327 fallback$1(r0) 328 fallback$1(r0) 329 fallback$1(0xffffffffffffffff) 330 fallback$1(0x0) 331 fallback$1(0x0) 332 `, 333 []CallInfo{ 334 { 335 Flags: CallExecuted, 336 Errno: 0, 337 Signal: make([]uint64, 1), 338 }, 339 { 340 Flags: CallExecuted, 341 Errno: 1, 342 Signal: make([]uint64, 1), 343 }, 344 { 345 Flags: CallExecuted, 346 Errno: 0, 347 Signal: make([]uint64, 2), 348 }, 349 { 350 Flags: CallExecuted, 351 Errno: 0, 352 Signal: make([]uint64, 1), 353 }, 354 { 355 Flags: CallExecuted, 356 Errno: 0, 357 Signal: make([]uint64, 2), 358 }, 359 { 360 Flags: CallExecuted, 361 Errno: 2, 362 Signal: make([]uint64, 1), 363 }, 364 }, 365 }, 366 // Test that calls get no signal after a successful seccomp. 367 { 368 ` 369 fallback$0() 370 fallback$0() 371 breaks_returns() 372 fallback$0() 373 breaks_returns() 374 fallback$0() 375 fallback$0() 376 `, 377 []CallInfo{ 378 { 379 Flags: CallExecuted, 380 Errno: 0, 381 Signal: make([]uint64, 1), 382 }, 383 { 384 Flags: CallExecuted, 385 Errno: 0, 386 Signal: make([]uint64, 1), 387 }, 388 { 389 Flags: CallExecuted, 390 Errno: 1, 391 Signal: make([]uint64, 1), 392 }, 393 { 394 Flags: CallExecuted, 395 Errno: 0, 396 }, 397 { 398 Flags: CallExecuted, 399 Errno: 0, 400 }, 401 { 402 Flags: CallExecuted, 403 }, 404 { 405 Flags: CallExecuted, 406 }, 407 }, 408 }, 409 { 410 ` 411 fallback$0() 412 breaks_returns() 413 fallback$0() 414 breaks_returns() 415 fallback$0() 416 `, 417 []CallInfo{ 418 { 419 Flags: CallExecuted, 420 Errno: 0, 421 Signal: make([]uint64, 1), 422 }, 423 { 424 Flags: CallExecuted, 425 Errno: 1, 426 Signal: make([]uint64, 1), 427 }, 428 { 429 Flags: CallExecuted, 430 Errno: 0, 431 }, 432 { 433 Flags: CallExecuted, 434 Errno: 0, 435 }, 436 { 437 Flags: CallExecuted, 438 }, 439 }, 440 }, 441 } 442 target, err := GetTarget("test", "64") 443 if err != nil { 444 t.Fatal(err) 445 } 446 for i, test := range tests { 447 t.Run(fmt.Sprint(i), func(t *testing.T) { 448 p, err := target.Deserialize([]byte(test.prog), Strict) 449 if err != nil { 450 t.Fatal(err) 451 } 452 if len(p.Calls) != len(test.info) { 453 t.Fatalf("call=%v info=%v", len(p.Calls), len(test.info)) 454 } 455 wantSignal := make([]int, len(test.info)) 456 for i := range test.info { 457 wantSignal[i] = len(test.info[i].Signal) 458 test.info[i].Signal = nil 459 } 460 p.FallbackSignal(test.info) 461 for i := range test.info { 462 if len(test.info[i].Signal) != wantSignal[i] { 463 t.Errorf("call %v: signal=%v want=%v", i, len(test.info[i].Signal), wantSignal[i]) 464 } 465 for _, sig := range test.info[i].Signal { 466 call, errno := DecodeFallbackSignal(sig) 467 if call != p.Calls[i].Meta.ID { 468 t.Errorf("call %v: sig=%x id=%v want=%v", i, sig, call, p.Calls[i].Meta.ID) 469 } 470 if errno != test.info[i].Errno { 471 t.Errorf("call %v: sig=%x errno=%v want=%v", i, sig, errno, test.info[i].Errno) 472 } 473 } 474 } 475 }) 476 } 477 } 478 479 func TestSanitizeRandom(t *testing.T) { 480 testEachTargetRandom(t, func(t *testing.T, target *Target, rs rand.Source, iters int) { 481 ct := target.DefaultChoiceTable() 482 for i := 0; i < iters; i++ { 483 p := target.Generate(rs, 10, ct) 484 s0 := string(p.Serialize()) 485 p.sanitizeFix() 486 s1 := string(p.Serialize()) 487 if s0 != s1 { 488 t.Fatalf("non-sanitized program or non-idempotent sanitize\nwas: %v\ngot: %v", s0, s1) 489 } 490 } 491 }) 492 }