mirror of
https://github.com/reactos/syzkaller.git
synced 2024-12-04 09:43:38 +00:00
b5f6354179
Few managers recently crashed with: panic: syscall mknod$loop: per proc arg 'proc' has bad value '4294967295' panic: sync: unlock of unlocked mutex goroutine 35438 [running]: sync.(*Mutex).Unlock(0xc42166e0c8) sync/mutex.go:184 +0xc1 panic(0xb98980, 0xc448971aa0) runtime/panic.go:491 +0x283 main.(*Manager).Connect(0xc42166e000, 0xc42056d060, 0xc42038f000, 0x0, 0x0) syz-manager/manager.go:868 +0x11cc And a similar issue was reported on mailing list. It's unclear where these bogus programs come from. It seems that hub was somehow involved here. 4294967295 is (uint32)-1 which is trucated special value for proc types. The test did not uncover any bugs, bug since I wrote it and it looks like a useful test, let's commit it anyway.
178 lines
4.6 KiB
Go
178 lines
4.6 KiB
Go
// Copyright 2015 syzkaller project authors. All rights reserved.
|
|
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
|
|
|
package prog
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"math/rand"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
targetsPkg "github.com/google/syzkaller/sys/targets"
|
|
)
|
|
|
|
func TestGeneration(t *testing.T) {
|
|
target, rs, iters := initTest(t)
|
|
for i := 0; i < iters; i++ {
|
|
target.Generate(rs, 20, nil)
|
|
}
|
|
}
|
|
|
|
func TestDefault(t *testing.T) {
|
|
target, _, _ := initTest(t)
|
|
for _, meta := range target.SyscallMap {
|
|
for _, t := range meta.Args {
|
|
defaultArg(t)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDefaultCallArgs(t *testing.T) {
|
|
target, _, _ := initTest(t)
|
|
for _, meta := range target.SyscallMap {
|
|
// Ensure that we can restore all arguments of all calls.
|
|
prog := fmt.Sprintf("%v()", meta.Name)
|
|
p, err := target.Deserialize([]byte(prog))
|
|
if err != nil {
|
|
t.Fatalf("failed to restore default args in prog %q: %v", prog, err)
|
|
}
|
|
if len(p.Calls) != 1 || p.Calls[0].Meta.Name != meta.Name {
|
|
t.Fatalf("restored bad program from prog %q: %q", prog, p.Serialize())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSerialize(t *testing.T) {
|
|
target, rs, iters := initTest(t)
|
|
for i := 0; i < iters; i++ {
|
|
p := target.Generate(rs, 10, nil)
|
|
data := p.Serialize()
|
|
p1, err := target.Deserialize(data)
|
|
if err != nil {
|
|
t.Fatalf("failed to deserialize program: %v\n%s", err, data)
|
|
}
|
|
if p1 == nil {
|
|
t.Fatalf("deserialized nil program:\n%s", data)
|
|
}
|
|
data1 := p1.Serialize()
|
|
if len(p.Calls) != len(p1.Calls) {
|
|
t.Fatalf("different number of calls")
|
|
}
|
|
if !bytes.Equal(data, data1) {
|
|
t.Fatalf("program changed after serialize/deserialize\noriginal:\n%s\n\nnew:\n%s\n", data, data1)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestVmaType(t *testing.T) {
|
|
target, rs, iters := initRandomTargetTest(t, "test", "64")
|
|
meta := target.SyscallMap["syz_test$vma0"]
|
|
r := newRand(target, rs)
|
|
pageSize := target.PageSize
|
|
for i := 0; i < iters; i++ {
|
|
s := newState(target, nil)
|
|
calls := r.generateParticularCall(s, meta)
|
|
c := calls[len(calls)-1]
|
|
if c.Meta.Name != "syz_test$vma0" {
|
|
t.Fatalf("generated wrong call %v", c.Meta.Name)
|
|
}
|
|
if len(c.Args) != 6 {
|
|
t.Fatalf("generated wrong number of args %v", len(c.Args))
|
|
}
|
|
check := func(v, l Arg, min, max uint64) {
|
|
va, ok := v.(*PointerArg)
|
|
if !ok {
|
|
t.Fatalf("vma has bad type: %v", v)
|
|
}
|
|
la, ok := l.(*ConstArg)
|
|
if !ok {
|
|
t.Fatalf("len has bad type: %v", l)
|
|
}
|
|
if va.PagesNum < min || va.PagesNum > max {
|
|
t.Fatalf("vma has bad number of pages: %v, want [%v-%v]", va.PagesNum, min, max)
|
|
}
|
|
if la.Val/pageSize < min || la.Val/pageSize > max {
|
|
t.Fatalf("len has bad number of pages: %v, want [%v-%v]", la.Val/pageSize, min, max)
|
|
}
|
|
}
|
|
check(c.Args[0], c.Args[1], 1, 1e5)
|
|
check(c.Args[2], c.Args[3], 5, 5)
|
|
check(c.Args[4], c.Args[5], 7, 9)
|
|
}
|
|
}
|
|
|
|
// TestCrossTarget ensures that a program serialized for one arch can be
|
|
// deserialized for another arch. This happens when managers exchange
|
|
// programs via hub.
|
|
func TestCrossTarget(t *testing.T) {
|
|
for os, archs := range targetsPkg.List {
|
|
if len(archs) == 1 {
|
|
continue
|
|
}
|
|
if os != "linux" {
|
|
continue
|
|
}
|
|
for arch := range archs {
|
|
target, err := GetTarget(os, arch)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var crossTargets []*Target
|
|
for crossArch := range archs {
|
|
if crossArch == arch {
|
|
continue
|
|
}
|
|
crossTarget, err := GetTarget(os, crossArch)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
crossTargets = append(crossTargets, crossTarget)
|
|
}
|
|
t.Run(fmt.Sprintf("%v/%v", os, arch), func(t *testing.T) {
|
|
t.Parallel()
|
|
testCrossTarget(t, target, crossTargets)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func testCrossTarget(t *testing.T, target *Target, crossTargets []*Target) {
|
|
seed := int64(time.Now().UnixNano())
|
|
t.Logf("seed=%v", seed)
|
|
rs := rand.NewSource(seed)
|
|
iters := 100
|
|
if testing.Short() {
|
|
iters /= 10
|
|
}
|
|
for i := 0; i < iters; i++ {
|
|
p := target.Generate(rs, 20, nil)
|
|
testCrossArchProg(t, p, crossTargets)
|
|
p, err := target.Deserialize(p.Serialize())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
testCrossArchProg(t, p, crossTargets)
|
|
p.Mutate(rs, 20, nil, nil)
|
|
testCrossArchProg(t, p, crossTargets)
|
|
p, _ = Minimize(p, -1, func(*Prog, int) bool {
|
|
return rs.Int63()%2 == 0
|
|
}, false)
|
|
testCrossArchProg(t, p, crossTargets)
|
|
}
|
|
}
|
|
|
|
func testCrossArchProg(t *testing.T, p *Prog, crossTargets []*Target) {
|
|
serialized := p.Serialize()
|
|
for _, crossTarget := range crossTargets {
|
|
_, err := crossTarget.Deserialize(serialized)
|
|
if err == nil || strings.Contains(err.Error(), "unknown syscall") {
|
|
continue
|
|
}
|
|
t.Fatalf("failed to deserialize for %v/%v: %v\n%s",
|
|
crossTarget.OS, crossTarget.Arch, err, serialized)
|
|
}
|
|
}
|