prog: add arbitrary mutation of complex structs

Squash complex structs into flat byte array and mutate this array
with generic blob mutations. This allows to mutate what we currently
consider as paddings and add/remove paddings from structs, etc.
This commit is contained in:
Dmitry Vyukov 2018-02-24 14:33:36 +01:00
parent 2145057cb8
commit 9fe8aa42c5
26 changed files with 843 additions and 183 deletions

View File

@ -452,8 +452,8 @@ static uintptr_t syz_emit_ethernet(uintptr_t a0, uintptr_t a1, uintptr_t a2)
// syz_emit_ethernet(len len[packet], packet ptr[in, eth_packet], frags ptr[in, vnet_fragmentation, opt])
// vnet_fragmentation {
// full int32[0:1]
// count len[frags, int32]
// frags array[int32[0:4096], 1:4]
// count int32[1:4]
// frags array[int32[0:4096], 4]
// }
if (tunfd < 0)
return (uintptr_t)-1;

View File

@ -2,7 +2,7 @@
#if defined(__i386__) || 0
#define GOARCH "386"
#define SYZ_REVISION "7fa1dc861170866b93bcdf1919d822e8d0a07cec"
#define SYZ_REVISION "9ec0173f31cb1936a6a5913dd48542851e4e86c9"
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
@ -1599,7 +1599,7 @@ call_t syscalls[] = {
#if defined(__x86_64__) || 0
#define GOARCH "amd64"
#define SYZ_REVISION "f5d957ae165e714c54b67d39db5982187b5393ec"
#define SYZ_REVISION "3aed60c42df2cc7ef2ac7f3e16d21628ec0649c9"
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
@ -3249,7 +3249,7 @@ call_t syscalls[] = {
#if defined(__arm__) || 0
#define GOARCH "arm"
#define SYZ_REVISION "4b33f66a0aeae24040db5b4a35e18e6ff2977b10"
#define SYZ_REVISION "c4a0e4b5eaf2ba6525f3c7ccd07e35532c7cc41e"
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
@ -4854,7 +4854,7 @@ call_t syscalls[] = {
#if defined(__aarch64__) || 0
#define GOARCH "arm64"
#define SYZ_REVISION "95e5f9d1ee68c969b1db26d8fd6ef0fb8b329019"
#define SYZ_REVISION "757e10e8ba130d265ef537544c5defb8dc52c0b6"
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
@ -6433,7 +6433,7 @@ call_t syscalls[] = {
#if defined(__ppc64__) || defined(__PPC64__) || defined(__powerpc64__) || 0
#define GOARCH "ppc64le"
#define SYZ_REVISION "067ce945ca9c59814a9ba64002ae646a553e757c"
#define SYZ_REVISION "a6de45082b1273527d9bb9832f7f0abc2820c50a"
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912

View File

@ -2,12 +2,14 @@
#if 0
#define GOARCH "32"
#define SYZ_REVISION "8e3bfbc4dd1f6619b4895bcb80e0004ef4c96928"
#define SYZ_REVISION "0d78e9b1f441c9ae33361f9778195af0a245ffdd"
#define SYZ_PAGE_SIZE 8192
#define SYZ_NUM_PAGES 2048
#define SYZ_DATA_OFFSET 536870912
unsigned syscall_count = 88;
unsigned syscall_count = 90;
call_t syscalls[] = {
{"foo$any0", 0, (syscall_t)foo},
{"foo$anyres", 0, (syscall_t)foo},
{"mmap", 0, (syscall_t)mmap},
{"mutate0", 0, (syscall_t)mutate0},
{"mutate1", 0, (syscall_t)mutate1},
@ -102,12 +104,14 @@ call_t syscalls[] = {
#if 0
#define GOARCH "64"
#define SYZ_REVISION "4a4abb9774bf056d0952d60f2fffdfdc392353a2"
#define SYZ_REVISION "e361957ea430829459298bc20840e4edbd324930"
#define SYZ_PAGE_SIZE 4096
#define SYZ_NUM_PAGES 4096
#define SYZ_DATA_OFFSET 536870912
unsigned syscall_count = 88;
unsigned syscall_count = 90;
call_t syscalls[] = {
{"foo$any0", 0, (syscall_t)foo},
{"foo$anyres", 0, (syscall_t)foo},
{"mmap", 0, (syscall_t)mmap},
{"mutate0", 0, (syscall_t)mutate0},
{"mutate1", 0, (syscall_t)mutate1},

View File

@ -123,8 +123,8 @@ func foreachArgImpl(arg Arg, ctx ArgCtx, f func(Arg, *ArgCtx)) {
claimedSize := a.Size()
varlen := a.Type().Varlen()
if varlen && totalSize > claimedSize || !varlen && totalSize != claimedSize {
panic(fmt.Sprintf("bad group arg size %v, should be <= %v for %+v",
totalSize, claimedSize, a))
panic(fmt.Sprintf("bad group arg size %v, should be <= %v for %#v type %#v",
totalSize, claimedSize, a, a.Type()))
}
case *PointerArg:
if a.Res != nil {

303
prog/any.go Normal file
View File

@ -0,0 +1,303 @@
package prog
import (
"fmt"
)
type anyTypes struct {
anyUnion *UnionType
anyArray *ArrayType
anyBlob *BufferType
anyPtrPtr *PtrType
anyPtr64 *PtrType
anyRes32 *ResourceType
anyRes64 *ResourceType
}
// This generates type descriptions for:
//
// resource ANYRES32[int32]: 0xffffffffffffffff, 0
// resource ANYRES64[int64]: 0xffffffffffffffff, 0
// ANY [
// bin array[int8]
// ptr ptr[in, array[ANY], opt]
// ptr64 ptr64[in, array[ANY], opt]
// res32 ANYRES32
// res64 ANYRES64
// ] [varlen]
func initAnyTypes(target *Target) {
target.anyUnion = &UnionType{
FldName: "ANYUNION",
}
target.anyArray = &ArrayType{
TypeCommon: TypeCommon{
TypeName: "ANYARRAY",
FldName: "ANYARRAY",
IsVarlen: true,
},
Type: target.anyUnion,
}
target.anyPtrPtr = &PtrType{
TypeCommon: TypeCommon{
TypeName: "ptr",
FldName: "ANYPTR",
TypeSize: target.PtrSize,
IsOptional: true,
},
Type: target.anyArray,
}
target.anyPtr64 = &PtrType{
TypeCommon: TypeCommon{
TypeName: "ptr64",
FldName: "ANYPTR64",
TypeSize: 8,
IsOptional: true,
},
Type: target.anyArray,
}
target.anyBlob = &BufferType{
TypeCommon: TypeCommon{
TypeName: "ANYBLOB",
FldName: "ANYBLOB",
IsVarlen: true,
},
}
createResource := func(name, base string, size uint64) *ResourceType {
return &ResourceType{
TypeCommon: TypeCommon{
TypeName: name,
FldName: name,
ArgDir: DirIn,
TypeSize: size,
IsOptional: true,
},
Desc: &ResourceDesc{
Name: name,
Kind: []string{name},
Values: []uint64{^uint64(0), 0},
Type: &IntType{
IntTypeCommon: IntTypeCommon{
TypeCommon: TypeCommon{
TypeName: base,
TypeSize: size,
},
},
},
},
}
}
target.anyRes32 = createResource("ANYRES32", "int32", 4)
target.anyRes64 = createResource("ANYRES64", "int64", 8)
target.anyUnion.StructDesc = &StructDesc{
TypeCommon: TypeCommon{
TypeName: "ANYUNION",
FldName: "ANYUNION",
IsVarlen: true,
ArgDir: DirIn,
},
Fields: []Type{
target.anyBlob,
target.anyPtrPtr,
target.anyPtr64,
target.anyRes32,
target.anyRes64,
},
}
}
func (target *Target) makeAnyPtrType(size uint64, field string) *PtrType {
// We need to make a copy because type holds field name,
// and field names are used as len target.
var typ PtrType
if size == target.PtrSize {
typ = *target.anyPtrPtr
} else if size == 8 {
typ = *target.anyPtr64
} else {
panic(fmt.Sprintf("bad pointer size %v", size))
}
typ.TypeSize = size
if field != "" {
typ.FldName = field
}
return &typ
}
func (target *Target) isAnyPtr(typ Type) bool {
ptr, ok := typ.(*PtrType)
return ok && ptr.Type == target.anyArray
}
func (p *Prog) complexPtrs() (res []*PointerArg) {
for _, c := range p.Calls {
ForeachArg(c, func(arg Arg, ctx *ArgCtx) {
if ptrArg, ok := arg.(*PointerArg); ok && p.Target.isComplexPtr(ptrArg) {
res = append(res, ptrArg)
ctx.Stop = true
}
})
}
return
}
func (target *Target) isComplexPtr(arg *PointerArg) bool {
if arg.Res == nil || arg.Type().Dir() != DirIn {
return false
}
if target.isAnyPtr(arg.Type()) {
return true
}
res := false
ForeachSubArg(arg.Res, func(a1 Arg, ctx *ArgCtx) {
switch typ := a1.Type().(type) {
case *StructType:
if typ.Varlen() {
res = true
ctx.Stop = true
}
case *UnionType:
if typ.Varlen() && len(typ.Fields) > 5 {
res = true
ctx.Stop = true
}
case *PtrType:
if a1 != arg {
ctx.Stop = true
}
}
})
return res
}
func (target *Target) CallContainsAny(c *Call) (res bool) {
ForeachArg(c, func(arg Arg, ctx *ArgCtx) {
if target.isAnyPtr(arg.Type()) {
res = true
ctx.Stop = true
}
})
return
}
func (target *Target) ArgContainsAny(arg0 Arg) (res bool) {
ForeachSubArg(arg0, func(arg Arg, ctx *ArgCtx) {
if target.isAnyPtr(arg.Type()) {
res = true
ctx.Stop = true
}
})
return
}
func (target *Target) squashPtr(arg *PointerArg, preserveField bool) {
if arg.Res == nil || arg.VmaSize != 0 {
panic("bad ptr arg")
}
res0 := arg.Res
size0 := res0.Size()
var elems []Arg
target.squashPtrImpl(arg.Res, &elems)
field := ""
if preserveField {
field = arg.Type().FieldName()
}
arg.typ = target.makeAnyPtrType(arg.Type().Size(), field)
arg.Res = MakeGroupArg(arg.typ.(*PtrType).Type, elems)
if size := arg.Res.Size(); size != size0 {
panic(fmt.Sprintf("squash changed size %v->%v for %v", size0, size, res0.Type()))
}
}
func (target *Target) squashPtrImpl(a Arg, elems *[]Arg) {
if a.Type().BitfieldMiddle() {
panic("bitfield in squash")
}
var pad uint64
switch arg := a.(type) {
case *ConstArg:
if IsPad(arg.Type()) {
pad = arg.Size()
} else {
// Note: we need a constant value, but it depends on pid for proc.
v := arg.ValueForProc(0)
elem := target.ensureDataElem(elems)
for i := uint64(0); i < arg.Size(); i++ {
elem.data = append(elem.Data(), byte(v))
v >>= 8
}
}
case *ResultArg:
switch arg.Size() {
case 4:
arg.typ = target.anyRes32
case 8:
arg.typ = target.anyRes64
default:
panic("bad size")
}
*elems = append(*elems, MakeUnionArg(target.anyUnion, arg))
case *PointerArg:
if arg.Res != nil {
target.squashPtr(arg, false)
*elems = append(*elems, MakeUnionArg(target.anyUnion, arg))
} else {
elem := target.ensureDataElem(elems)
addr := target.PhysicalAddr(arg)
for i := uint64(0); i < arg.Size(); i++ {
elem.data = append(elem.Data(), byte(addr))
addr >>= 8
}
}
case *UnionArg:
if !arg.Type().Varlen() {
pad = arg.Size() - arg.Option.Size()
}
target.squashPtrImpl(arg.Option, elems)
case *DataArg:
if arg.Type().Dir() == DirOut {
pad = arg.Size()
} else {
elem := target.ensureDataElem(elems)
elem.data = append(elem.Data(), arg.Data()...)
}
case *GroupArg:
if typ, ok := arg.Type().(*StructType); ok && typ.Varlen() && typ.AlignAttr != 0 {
var fieldsSize uint64
for _, fld := range arg.Inner {
if !fld.Type().BitfieldMiddle() {
fieldsSize += fld.Size()
}
}
if fieldsSize%typ.AlignAttr != 0 {
pad = typ.AlignAttr - fieldsSize%typ.AlignAttr
}
}
for _, fld := range arg.Inner {
if fld.Type().BitfieldMiddle() {
// TODO(dvyukov): handle bitfields
continue
}
target.squashPtrImpl(fld, elems)
}
default:
panic("bad arg kind")
}
if pad != 0 {
elem := target.ensureDataElem(elems)
elem.data = append(elem.Data(), make([]byte, pad)...)
}
}
func (target *Target) ensureDataElem(elems *[]Arg) *DataArg {
if len(*elems) == 0 {
res := MakeDataArg(target.anyBlob, nil)
*elems = append(*elems, MakeUnionArg(target.anyUnion, res))
return res
}
res, ok := (*elems)[len(*elems)-1].(*UnionArg).Option.(*DataArg)
if !ok {
res = MakeDataArg(target.anyBlob, nil)
*elems = append(*elems, MakeUnionArg(target.anyUnion, res))
}
return res
}

74
prog/any_test.go Normal file
View File

@ -0,0 +1,74 @@
// Copyright 2018 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 (
"fmt"
"sort"
"strings"
"testing"
)
func TestIsComplexPtr(t *testing.T) {
target, rs, _ := initRandomTargetTest(t, "linux", "amd64")
r := newRand(target, rs)
compl := make(map[string]bool)
for _, meta := range target.Syscalls {
for i := 0; i < 10; i++ {
s := newState(target, nil)
calls := r.generateParticularCall(s, meta)
p := &Prog{Target: target, Calls: calls}
for _, arg := range p.complexPtrs() {
compl[arg.Res.Type().String()] = true
}
}
}
var arr []string
for id := range compl {
arr = append(arr, id)
}
sort.Strings(arr)
t.Log("complex types:\n" + strings.Join(arr, "\n"))
}
func TestSquash(t *testing.T) {
target := initTargetTest(t, "test", "64")
tests := []struct {
prog string
squashed string
}{
{
`foo$any0(&(0x7f0000000000)={0x11, 0x11223344, 0x2233, 0x1122334455667788, [{0x0, @res32=0x0, 0x0, @i8=0x44, "aabb"}, {0x0, @res64=0x1, 0x0, @i32=0x11223344, "1122334455667788"}]})`,
`foo$any0(&(0x7f0000000000)=ANY=[@ANYBLOB="1100000044332211223300000000000088776655443322110000000000000000", @ANYRES32, @ANYBLOB="00000000000000000000000044aabb000000000000000000", @ANYRES64=0x1, @ANYBLOB="0000000000000000443322111122334455667788"])`,
},
}
for i, test := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
p, err := target.Deserialize([]byte(test.prog))
if err != nil {
t.Fatalf("failed to deserialize prog: %v", err)
}
ptrArg := p.Calls[0].Args[0].(*PointerArg)
if !target.isComplexPtr(ptrArg) {
t.Fatalf("arg is not complex")
}
if target.ArgContainsAny(ptrArg) {
t.Fatalf("arg is already squashed")
}
target.squashPtr(ptrArg, true)
if !target.ArgContainsAny(ptrArg) {
t.Fatalf("arg is not squashed")
}
p1 := strings.TrimSpace(string(p.Serialize()))
target.squashPtr(ptrArg, true)
p2 := strings.TrimSpace(string(p.Serialize()))
if p1 != p2 {
t.Fatalf("double squash changed program:\n%v\nvs:\n%v", p1, p2)
}
if p1 != test.squashed {
t.Fatalf("bad squash result:\n%v\nwant:\n%v", p1, test.squashed)
}
})
}
}

View File

@ -72,8 +72,11 @@ func (target *Target) serialize(arg Arg, buf *bytes.Buffer, vars map[Arg]int, va
break
}
fmt.Fprintf(buf, "&%v", target.serializeAddr(a))
if a.Res == nil || !target.isDefaultArg(a.Res) {
if a.Res == nil || !target.isDefaultArg(a.Res) || target.isAnyPtr(a.Type()) {
fmt.Fprintf(buf, "=")
if target.isAnyPtr(a.Type()) {
fmt.Fprintf(buf, "ANY=")
}
target.serialize(a.Res, buf, vars, varSeq)
}
case *DataArg:
@ -296,6 +299,17 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e
var inner Arg
if p.Char() == '=' {
p.Parse('=')
if p.Char() == 'A' {
p.Parse('A')
p.Parse('N')
p.Parse('Y')
p.Parse('=')
if typ.Size() == 0 {
panic(fmt.Sprintf("TYPESIZE=0: %#v", typ))
}
typ = target.makeAnyPtrType(typ.Size(), typ.FieldName())
typ1 = target.anyArray
}
inner, err = target.parseArg(typ1, p, vars)
if err != nil {
return nil, err

View File

@ -112,6 +112,7 @@ func checkConstArg(arg *ConstArg, compMap CompMap, exec func()) {
}
func checkDataArg(arg *DataArg, compMap CompMap, exec func()) {
// TODO(dvyukov): we need big-endian match for ANYBLOBs.
bytes := make([]byte, 8)
data := arg.Data()
size := len(data)

View File

@ -19,6 +19,34 @@ outer:
for stop := false; !stop || retry; stop = r.oneOf(3) {
retry = false
switch {
case r.oneOf(5):
// Not all calls have anything squashable,
// so this has lower priority in reality.
complexPtrs := p.complexPtrs()
if len(complexPtrs) == 0 {
retry = true
continue
}
ptr := complexPtrs[r.Intn(len(complexPtrs))]
if !p.Target.isAnyPtr(ptr.Type()) {
p.Target.squashPtr(ptr, true)
}
var blobs []*DataArg
ForeachSubArg(ptr, func(arg Arg, _ *ArgCtx) {
if data, ok := arg.(*DataArg); ok && arg.Type().Dir() != DirOut {
blobs = append(blobs, data)
}
})
if len(blobs) == 0 {
retry = true
continue
}
// TODO(dvyukov): we probably want special mutation for ANY.
// E.g. merging adjacent ANYBLOBs (we don't create them,
// but they can appear in future); or replacing ANYRES
// with a blob (and merging it with adjacent blobs).
arg := blobs[r.Intn(len(blobs))]
arg.data = mutateData(r, arg.Data(), 0, maxBlobLen)
case r.nOutOf(1, 100):
// Splice with another prog from corpus.
if len(corpus) == 0 || len(p.Calls) == 0 {
@ -311,31 +339,9 @@ func mutateData(r *randGen, data []byte, minLen, maxLen uint64) []byte {
loop:
for stop := false; !stop || retry; stop = r.oneOf(3) {
retry = false
switch r.Intn(14) {
// TODO(dvyukov): duplicate part of data.
switch r.Intn(7) {
case 0:
// Append byte.
if uint64(len(data)) >= maxLen {
retry = true
continue loop
}
data = append(data, byte(r.rand(256)))
case 1:
// Remove byte.
if len(data) == 0 || uint64(len(data)) <= minLen {
retry = true
continue loop
}
i := r.Intn(len(data))
copy(data[i:], data[i+1:])
data = data[:len(data)-1]
case 2:
// Replace byte with random value.
if len(data) == 0 {
retry = true
continue loop
}
data[r.Intn(len(data))] = byte(r.rand(256))
case 3:
// Flip bit in byte.
if len(data) == 0 {
retry = true
@ -344,122 +350,49 @@ loop:
byt := r.Intn(len(data))
bit := r.Intn(8)
data[byt] ^= 1 << uint(bit)
case 4:
// Swap two bytes.
if len(data) < 2 {
case 1:
// Insert random bytes.
if len(data) == 0 || uint64(len(data)) >= maxLen {
retry = true
continue loop
}
i1 := r.Intn(len(data))
i2 := r.Intn(len(data))
data[i1], data[i2] = data[i2], data[i1]
case 5:
// Add / subtract from a byte.
if len(data) == 0 {
retry = true
continue loop
n := r.Intn(16) + 1
if r := int(maxLen) - len(data); n > r {
n = r
}
i := r.Intn(len(data))
delta := byte(r.rand(2*maxInc+1) - maxInc)
if delta == 0 {
delta = 1
pos := r.Intn(len(data))
for i := 0; i < n; i++ {
data = append(data, 0)
}
data[i] += delta
case 6:
// Add / subtract from a uint16.
if len(data) < 2 {
retry = true
continue loop
}
i := r.Intn(len(data) - 1)
p := (*uint16)(unsafe.Pointer(&data[i]))
delta := uint16(r.rand(2*maxInc+1) - maxInc)
if delta == 0 {
delta = 1
copy(data[pos+n:], data[pos:])
for i := 0; i < n; i++ {
data[pos+i] = byte(r.Int31())
}
if r.bin() {
*p += delta
} else {
*p = swap16(swap16(*p) + delta)
data = data[:len(data)-n] // preserve original length
}
case 7:
// Add / subtract from a uint32.
if len(data) < 4 {
case 2:
// Remove bytes.
if uint64(len(data)) <= minLen {
retry = true
continue loop
}
i := r.Intn(len(data) - 3)
p := (*uint32)(unsafe.Pointer(&data[i]))
delta := uint32(r.rand(2*maxInc+1) - maxInc)
if delta == 0 {
delta = 1
n := r.Intn(16) + 1
if n > len(data) {
n = len(data)
}
pos := 0
if n < len(data) {
pos = r.Intn(len(data) - n)
}
copy(data[pos:], data[pos+n:])
data = data[:len(data)-n]
if r.bin() {
*p += delta
} else {
*p = swap32(swap32(*p) + delta)
for i := 0; i < n; i++ {
data = append(data, 0) // preserve original length
}
}
case 8:
// Add / subtract from a uint64.
if len(data) < 8 {
retry = true
continue loop
}
i := r.Intn(len(data) - 7)
p := (*uint64)(unsafe.Pointer(&data[i]))
delta := r.rand(2*maxInc+1) - maxInc
if delta == 0 {
delta = 1
}
if r.bin() {
*p += delta
} else {
*p = swap64(swap64(*p) + delta)
}
case 9:
// Set byte to an interesting value.
if len(data) == 0 {
retry = true
continue loop
}
data[r.Intn(len(data))] = byte(r.randInt())
case 10:
// Set uint16 to an interesting value.
if len(data) < 2 {
retry = true
continue loop
}
i := r.Intn(len(data) - 1)
value := uint16(r.randInt())
if r.bin() {
value = swap16(value)
}
*(*uint16)(unsafe.Pointer(&data[i])) = value
case 11:
// Set uint32 to an interesting value.
if len(data) < 4 {
retry = true
continue loop
}
i := r.Intn(len(data) - 3)
value := uint32(r.randInt())
if r.bin() {
value = swap32(value)
}
*(*uint32)(unsafe.Pointer(&data[i])) = value
case 12:
// Set uint64 to an interesting value.
if len(data) < 8 {
retry = true
continue loop
}
i := r.Intn(len(data) - 7)
value := r.randInt()
if r.bin() {
value = swap64(value)
}
*(*uint64)(unsafe.Pointer(&data[i])) = value
case 13:
case 3:
// Append a bunch of bytes.
if uint64(len(data)) >= maxLen {
retry = true
@ -473,6 +406,146 @@ loop:
for i := 0; i < n; i++ {
data = append(data, byte(r.rand(256)))
}
case 4:
// Replace int8/int16/int32/int64 with a random value.
switch r.Intn(4) {
case 0: // int8
if len(data) == 0 {
retry = true
continue loop
}
data[r.Intn(len(data))] = byte(r.rand(1 << 8))
case 1: // int16
if len(data) < 2 {
retry = true
continue loop
}
i := r.Intn(len(data) - 1)
p := (*uint16)(unsafe.Pointer(&data[i]))
*p = uint16(r.rand(1 << 16))
case 2: // int32
if len(data) < 4 {
retry = true
continue loop
}
i := r.Intn(len(data) - 3)
p := (*uint32)(unsafe.Pointer(&data[i]))
*p = uint32(r.rand(1 << 32))
case 3: // int64
if len(data) < 8 {
retry = true
continue loop
}
i := r.Intn(len(data) - 7)
p := (*uint64)(unsafe.Pointer(&data[i]))
*p = r.Uint64()
}
case 5:
// Add/subtract from an int8/int16/int32/int64.
switch r.Intn(4) {
case 0: // int8
if len(data) == 0 {
retry = true
continue loop
}
i := r.Intn(len(data))
delta := byte(r.rand(2*maxInc+1) - maxInc)
if delta == 0 {
delta = 1
}
data[i] += delta
case 1: // int16
if len(data) < 2 {
retry = true
continue loop
}
i := r.Intn(len(data) - 1)
p := (*uint16)(unsafe.Pointer(&data[i]))
delta := uint16(r.rand(2*maxInc+1) - maxInc)
if delta == 0 {
delta = 1
}
if r.oneOf(10) {
*p = swap16(swap16(*p) + delta)
} else {
*p += delta
}
case 2: // int32
if len(data) < 4 {
retry = true
continue loop
}
i := r.Intn(len(data) - 3)
p := (*uint32)(unsafe.Pointer(&data[i]))
delta := uint32(r.rand(2*maxInc+1) - maxInc)
if delta == 0 {
delta = 1
}
if r.oneOf(10) {
*p = swap32(swap32(*p) + delta)
} else {
*p += delta
}
case 3: // int64
if len(data) < 8 {
retry = true
continue loop
}
i := r.Intn(len(data) - 7)
p := (*uint64)(unsafe.Pointer(&data[i]))
delta := r.rand(2*maxInc+1) - maxInc
if delta == 0 {
delta = 1
}
if r.oneOf(10) {
*p = swap64(swap64(*p) + delta)
} else {
*p += delta
}
}
case 6:
// Set int8/int16/int32/int64 to an interesting value.
switch r.Intn(4) {
case 0: // int8
if len(data) == 0 {
retry = true
continue loop
}
data[r.Intn(len(data))] = byte(r.randInt())
case 1: // int16
if len(data) < 2 {
retry = true
continue loop
}
i := r.Intn(len(data) - 1)
value := uint16(r.randInt())
if r.oneOf(10) {
value = swap16(value)
}
*(*uint16)(unsafe.Pointer(&data[i])) = value
case 2: // int32
if len(data) < 4 {
retry = true
continue loop
}
i := r.Intn(len(data) - 3)
value := uint32(r.randInt())
if r.oneOf(10) {
value = swap32(value)
}
*(*uint32)(unsafe.Pointer(&data[i])) = value
case 3: // int64
if len(data) < 8 {
retry = true
continue loop
}
i := r.Intn(len(data) - 7)
value := r.randInt()
if r.oneOf(10) {
value = swap64(value)
}
*(*uint64)(unsafe.Pointer(&data[i])) = value
}
default:
panic("bad")
}

View File

@ -90,6 +90,24 @@ func (arg *ConstArg) Value() (uint64, uint64, bool) {
}
}
func (arg *ConstArg) ValueForProc(pid uint64) uint64 {
v, stride, be := arg.Value()
v += stride * pid
if be {
switch arg.Size() {
case 2:
v = uint64(swap16(uint16(v)))
case 4:
v = uint64(swap32(uint32(v)))
case 8:
v = swap64(v)
default:
panic(fmt.Sprintf("bad const size %v", arg.Size()))
}
}
return v
}
// Used for PtrType and VmaType.
type PointerArg struct {
ArgCommon

View File

@ -469,15 +469,17 @@ func (r *randGen) generateArgImpl(s *state, typ Type, ignoreSpecial bool) (arg A
// Allow infinite recursion for optional pointers.
if pt, ok := typ.(*PtrType); ok && typ.Optional() {
if str, ok := pt.Type.(*StructType); ok {
r.recDepth[str.Name()] += 1
switch pt.Type.(type) {
case *StructType, *ArrayType, *UnionType:
name := pt.Type.Name()
r.recDepth[name] += 1
defer func() {
r.recDepth[str.Name()] -= 1
if r.recDepth[str.Name()] == 0 {
delete(r.recDepth, str.Name())
r.recDepth[name] -= 1
if r.recDepth[name] == 0 {
delete(r.recDepth, name)
}
}()
if r.recDepth[str.Name()] >= 3 {
if r.recDepth[name] >= 3 {
return MakeNullPointerArg(typ), nil
}
}

View File

@ -33,6 +33,9 @@ func (target *Target) calcResourceCtors(kind []string, precise bool) []*Syscall
// isCompatibleResource returns true if resource of kind src can be passed as an argument of kind dst.
func (target *Target) isCompatibleResource(dst, src string) bool {
if dst == target.anyRes32.TypeName || dst == target.anyRes64.TypeName {
return true
}
dstRes := target.resourceMap[dst]
if dstRes == nil {
panic(fmt.Sprintf("unknown resource '%v'", dst))

View File

@ -52,6 +52,7 @@ type Target struct {
resourceMap map[string]*ResourceDesc
// Maps resource name to a list of calls that can create the resource.
resourceCtors map[string][]*Syscall
anyTypes
}
var targets = make(map[string]*Target)
@ -148,6 +149,7 @@ func (target *Target) initTarget() {
for _, res := range target.Resources {
target.resourceCtors[res.Name] = target.calcResourceCtors(res.Kind, false)
}
initAnyTypes(target)
}
type Gen struct {

View File

@ -24,7 +24,21 @@ const (
DirInOut
)
func (dir Dir) String() string {
switch dir {
case DirIn:
return "in"
case DirOut:
return "out"
case DirInOut:
return "inout"
default:
panic("unknown dir")
}
}
type Type interface {
String() string
Name() string
FieldName() string
Dir() Dir
@ -108,6 +122,10 @@ type ResourceType struct {
Desc *ResourceDesc
}
func (t *ResourceType) String() string {
return t.Name()
}
func (t *ResourceType) Default() uint64 {
return t.Desc.Values[0]
}
@ -124,6 +142,10 @@ type IntTypeCommon struct {
BitfieldMdl bool
}
func (t *IntTypeCommon) String() string {
return t.Name()
}
func (t *IntTypeCommon) BitfieldOffset() uint64 {
return t.BitfieldOff
}
@ -142,6 +164,13 @@ type ConstType struct {
IsPad bool
}
func (t *ConstType) String() string {
if t.IsPad {
return fmt.Sprintf("pad[%v]", t.Size())
}
return fmt.Sprintf("const[%v, %v]", t.Val, t.IntTypeCommon.String())
}
type IntKind int
const (
@ -193,12 +222,20 @@ type CsumType struct {
Protocol uint64 // for CsumPseudo
}
func (t *CsumType) String() string {
return "csum"
}
type VmaType struct {
TypeCommon
RangeBegin uint64 // in pages
RangeEnd uint64
}
func (t *VmaType) String() string {
return "vma"
}
type BufferKind int
const (
@ -230,6 +267,10 @@ type BufferType struct {
NoZ bool // non-zero terminated BufferString
}
func (t *BufferType) String() string {
return "buffer"
}
type ArrayKind int
const (
@ -245,17 +286,29 @@ type ArrayType struct {
RangeEnd uint64
}
func (t *ArrayType) String() string {
return fmt.Sprintf("array[%v]", t.Type.String())
}
type PtrType struct {
TypeCommon
Type Type
}
func (t *PtrType) String() string {
return fmt.Sprintf("ptr[%v, %v]", t.Dir(), t.Type.String())
}
type StructType struct {
Key StructKey
FldName string
*StructDesc
}
func (t *StructType) String() string {
return t.Name()
}
func (t *StructType) FieldName() string {
return t.FldName
}
@ -266,6 +319,10 @@ type UnionType struct {
*StructDesc
}
func (t *UnionType) String() string {
return t.Name()
}
func (t *UnionType) FieldName() string {
return t.FldName
}

View File

@ -9996,10 +9996,10 @@ var structDescs_386 = []*KeyedStruct{
&UnionType{Key: StructKey{Name: "vmaddr_cid"}, FldName: "cid"},
&ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "const", FldName: "pad", TypeSize: 4}}},
}, AlignAttr: 8}},
{Key: StructKey{Name: "vnet_fragmentation"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vnet_fragmentation", IsVarlen: true}, Fields: []Type{
{Key: StructKey{Name: "vnet_fragmentation"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vnet_fragmentation", TypeSize: 24}, Fields: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "full", TypeSize: 4}}, Kind: 2, RangeEnd: 1},
&LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "count", TypeSize: 4}}, Buf: "frags"},
&ArrayType{TypeCommon: TypeCommon{TypeName: "array", FldName: "frags", IsVarlen: true}, Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}, Kind: 2, RangeEnd: 4096}, Kind: 1, RangeBegin: 1, RangeEnd: 4},
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "count", TypeSize: 4}}, Kind: 2, RangeBegin: 1, RangeEnd: 4},
&ArrayType{TypeCommon: TypeCommon{TypeName: "array", FldName: "frags", TypeSize: 16}, Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}, Kind: 2, RangeEnd: 4096}, Kind: 1, RangeBegin: 4, RangeEnd: 4},
}}},
{Key: StructKey{Name: "vt_consize"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vt_consize", TypeSize: 12}, Fields: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int16", FldName: "rows", TypeSize: 2}}},
@ -25032,4 +25032,4 @@ var consts_386 = []ConstValue{
{Name: "bpf_insn_load_imm_dw", Value: 24},
}
const revision_386 = "7fa1dc861170866b93bcdf1919d822e8d0a07cec"
const revision_386 = "9ec0173f31cb1936a6a5913dd48542851e4e86c9"

View File

@ -10231,10 +10231,10 @@ var structDescs_amd64 = []*KeyedStruct{
&UnionType{Key: StructKey{Name: "vmaddr_cid"}, FldName: "cid"},
&ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "const", FldName: "pad", TypeSize: 4}}},
}, AlignAttr: 8}},
{Key: StructKey{Name: "vnet_fragmentation"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vnet_fragmentation", IsVarlen: true}, Fields: []Type{
{Key: StructKey{Name: "vnet_fragmentation"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vnet_fragmentation", TypeSize: 24}, Fields: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "full", TypeSize: 4}}, Kind: 2, RangeEnd: 1},
&LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "count", TypeSize: 4}}, Buf: "frags"},
&ArrayType{TypeCommon: TypeCommon{TypeName: "array", FldName: "frags", IsVarlen: true}, Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}, Kind: 2, RangeEnd: 4096}, Kind: 1, RangeBegin: 1, RangeEnd: 4},
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "count", TypeSize: 4}}, Kind: 2, RangeBegin: 1, RangeEnd: 4},
&ArrayType{TypeCommon: TypeCommon{TypeName: "array", FldName: "frags", TypeSize: 16}, Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}, Kind: 2, RangeEnd: 4096}, Kind: 1, RangeBegin: 4, RangeEnd: 4},
}}},
{Key: StructKey{Name: "vt_consize"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vt_consize", TypeSize: 12}, Fields: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int16", FldName: "rows", TypeSize: 2}}},
@ -25633,4 +25633,4 @@ var consts_amd64 = []ConstValue{
{Name: "bpf_insn_load_imm_dw", Value: 24},
}
const revision_amd64 = "f5d957ae165e714c54b67d39db5982187b5393ec"
const revision_amd64 = "3aed60c42df2cc7ef2ac7f3e16d21628ec0649c9"

View File

@ -9845,10 +9845,10 @@ var structDescs_arm = []*KeyedStruct{
&UnionType{Key: StructKey{Name: "vmaddr_cid"}, FldName: "cid"},
&ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "const", FldName: "pad", TypeSize: 4}}},
}, AlignAttr: 8}},
{Key: StructKey{Name: "vnet_fragmentation"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vnet_fragmentation", IsVarlen: true}, Fields: []Type{
{Key: StructKey{Name: "vnet_fragmentation"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vnet_fragmentation", TypeSize: 24}, Fields: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "full", TypeSize: 4}}, Kind: 2, RangeEnd: 1},
&LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "count", TypeSize: 4}}, Buf: "frags"},
&ArrayType{TypeCommon: TypeCommon{TypeName: "array", FldName: "frags", IsVarlen: true}, Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}, Kind: 2, RangeEnd: 4096}, Kind: 1, RangeBegin: 1, RangeEnd: 4},
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "count", TypeSize: 4}}, Kind: 2, RangeBegin: 1, RangeEnd: 4},
&ArrayType{TypeCommon: TypeCommon{TypeName: "array", FldName: "frags", TypeSize: 16}, Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}, Kind: 2, RangeEnd: 4096}, Kind: 1, RangeBegin: 4, RangeEnd: 4},
}}},
{Key: StructKey{Name: "vt_consize"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vt_consize", TypeSize: 12}, Fields: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int16", FldName: "rows", TypeSize: 2}}},
@ -24871,4 +24871,4 @@ var consts_arm = []ConstValue{
{Name: "bpf_insn_load_imm_dw", Value: 24},
}
const revision_arm = "4b33f66a0aeae24040db5b4a35e18e6ff2977b10"
const revision_arm = "c4a0e4b5eaf2ba6525f3c7ccd07e35532c7cc41e"

View File

@ -10007,10 +10007,10 @@ var structDescs_arm64 = []*KeyedStruct{
&UnionType{Key: StructKey{Name: "vmaddr_cid"}, FldName: "cid"},
&ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "const", FldName: "pad", TypeSize: 4}}},
}, AlignAttr: 8}},
{Key: StructKey{Name: "vnet_fragmentation"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vnet_fragmentation", IsVarlen: true}, Fields: []Type{
{Key: StructKey{Name: "vnet_fragmentation"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vnet_fragmentation", TypeSize: 24}, Fields: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "full", TypeSize: 4}}, Kind: 2, RangeEnd: 1},
&LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "count", TypeSize: 4}}, Buf: "frags"},
&ArrayType{TypeCommon: TypeCommon{TypeName: "array", FldName: "frags", IsVarlen: true}, Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}, Kind: 2, RangeEnd: 4096}, Kind: 1, RangeBegin: 1, RangeEnd: 4},
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "count", TypeSize: 4}}, Kind: 2, RangeBegin: 1, RangeEnd: 4},
&ArrayType{TypeCommon: TypeCommon{TypeName: "array", FldName: "frags", TypeSize: 16}, Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}, Kind: 2, RangeEnd: 4096}, Kind: 1, RangeBegin: 4, RangeEnd: 4},
}}},
{Key: StructKey{Name: "vt_consize"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vt_consize", TypeSize: 12}, Fields: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int16", FldName: "rows", TypeSize: 2}}},
@ -25015,4 +25015,4 @@ var consts_arm64 = []ConstValue{
{Name: "bpf_insn_load_imm_dw", Value: 24},
}
const revision_arm64 = "95e5f9d1ee68c969b1db26d8fd6ef0fb8b329019"
const revision_arm64 = "757e10e8ba130d265ef537544c5defb8dc52c0b6"

View File

@ -117,6 +117,9 @@ func (arch *arch) generateEbtables(g *prog.Gen, typ prog.Type, old prog.Arg) (
arg = old
calls = g.MutateArg(arg)
}
if g.Target().ArgContainsAny(arg) {
return
}
hooksField, entriesField := 4, 7
if g.Target().PtrSize == 8 {
// Account for paddings.
@ -155,6 +158,7 @@ func (arch *arch) generateEbtables(g *prog.Gen, typ prog.Type, old prog.Arg) (
}
hookArg.Val = addr
}
// TODO(dvyukov): assign jump targets for targets.
return
}

View File

@ -9887,10 +9887,10 @@ var structDescs_ppc64le = []*KeyedStruct{
&UnionType{Key: StructKey{Name: "vmaddr_cid"}, FldName: "cid"},
&ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "const", FldName: "pad", TypeSize: 4}}},
}, AlignAttr: 8}},
{Key: StructKey{Name: "vnet_fragmentation"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vnet_fragmentation", IsVarlen: true}, Fields: []Type{
{Key: StructKey{Name: "vnet_fragmentation"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vnet_fragmentation", TypeSize: 24}, Fields: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "full", TypeSize: 4}}, Kind: 2, RangeEnd: 1},
&LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "count", TypeSize: 4}}, Buf: "frags"},
&ArrayType{TypeCommon: TypeCommon{TypeName: "array", FldName: "frags", IsVarlen: true}, Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}, Kind: 2, RangeEnd: 4096}, Kind: 1, RangeBegin: 1, RangeEnd: 4},
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "count", TypeSize: 4}}, Kind: 2, RangeBegin: 1, RangeEnd: 4},
&ArrayType{TypeCommon: TypeCommon{TypeName: "array", FldName: "frags", TypeSize: 16}, Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}, Kind: 2, RangeEnd: 4096}, Kind: 1, RangeBegin: 4, RangeEnd: 4},
}}},
{Key: StructKey{Name: "vt_consize"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "vt_consize", TypeSize: 12}, Fields: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int16", FldName: "rows", TypeSize: 2}}},
@ -24777,4 +24777,4 @@ var consts_ppc64le = []ConstValue{
{Name: "bpf_insn_load_imm_dw", Value: 24},
}
const revision_ppc64le = "067ce945ca9c59814a9ba64002ae646a553e757c"
const revision_ppc64le = "a6de45082b1273527d9bb9832f7f0abc2820c50a"

View File

@ -10,8 +10,8 @@ vnet_fragmentation {
# If set and we have remaining data after fragmentation, it is written in an additional fragment.
# If not set, data remaining after fragmentation is discarded.
full int32[0:1]
count len[frags, int32]
frags array[int32[0:4096], 1:4]
count int32[1:4]
frags array[int32[0:4096], 4]
}
resource tcp_seq_num[int32]: 0x42424242

View File

@ -8,12 +8,38 @@ func init() {
}
var resources_32 = []*ResourceDesc{
{Name: "anyres32", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"anyres32"}, Values: []uint64{0}},
{Name: "anyres64", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int64", TypeSize: 8}}}, Kind: []string{"anyres64"}, Values: []uint64{0}},
{Name: "fd", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"fd"}, Values: []uint64{18446744073709551615}},
{Name: "syz_missing_const_res", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"syz_missing_const_res"}, Values: []uint64{1}},
{Name: "syz_res", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"syz_res"}, Values: []uint64{65535}},
}
var structDescs_32 = []*KeyedStruct{
{Key: StructKey{Name: "any0"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "any0", IsVarlen: true}, Fields: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", FldName: "f1", TypeSize: 1}}},
&ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 3}}, IsPad: true},
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "f2", TypeSize: 4}}},
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int16be", FldName: "f3", TypeSize: 2}, BigEndian: true}},
&ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 6}}, IsPad: true},
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int64", FldName: "f4", TypeSize: 8}}},
&ArrayType{TypeCommon: TypeCommon{TypeName: "array", FldName: "f5", IsVarlen: true}, Type: &StructType{Key: StructKey{Name: "any1"}}},
}, AlignAttr: 8}},
{Key: StructKey{Name: "any1"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "any1", IsVarlen: true}, Fields: []Type{
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "f1", TypeSize: 4, IsOptional: true}, Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", TypeSize: 1}}}},
&UnionType{Key: StructKey{Name: "anyunion0"}, FldName: "f2"},
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr64", FldName: "f3", TypeSize: 8, IsOptional: true}, Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", TypeSize: 1}}}},
&UnionType{Key: StructKey{Name: "anyunion1"}, FldName: "f4"},
&BufferType{TypeCommon: TypeCommon{TypeName: "array", FldName: "f5", IsVarlen: true}},
}, AlignAttr: 2}},
{Key: StructKey{Name: "anyunion0"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "anyunion0", TypeSize: 8}, Fields: []Type{
&ResourceType{TypeCommon: TypeCommon{TypeName: "anyres32", FldName: "res32", TypeSize: 4}},
&ResourceType{TypeCommon: TypeCommon{TypeName: "anyres64", FldName: "res64", TypeSize: 8}},
}}},
{Key: StructKey{Name: "anyunion1"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "anyunion1", IsVarlen: true}, Fields: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", FldName: "i8", TypeSize: 1}}},
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "i32", TypeSize: 4}}},
}}},
{Key: StructKey{Name: "len_nontemp4"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "len_nontemp4", TypeSize: 4}, Fields: []Type{
&LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "f1", TypeSize: 4}}, Buf: "len_temp3"},
}}},
@ -444,6 +470,13 @@ var structDescs_32 = []*KeyedStruct{
}
var syscalls_32 = []*Syscall{
{Name: "foo$any0", CallName: "foo", Args: []Type{
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a", TypeSize: 4}, Type: &StructType{Key: StructKey{Name: "any0"}}},
}},
{Name: "foo$anyres", CallName: "foo", Args: []Type{
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 4}, Type: &ResourceType{TypeCommon: TypeCommon{TypeName: "anyres32", TypeSize: 4, ArgDir: 1}}},
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a1", TypeSize: 4}, Type: &ResourceType{TypeCommon: TypeCommon{TypeName: "anyres64", TypeSize: 8, ArgDir: 1}}},
}},
{Name: "mmap", CallName: "mmap", Args: []Type{
&VmaType{TypeCommon: TypeCommon{TypeName: "vma", FldName: "addr", TypeSize: 4}},
&LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "len", TypeSize: 4}}, Buf: "addr"},
@ -739,4 +772,4 @@ var consts_32 = []ConstValue{
{Name: "ONLY_32BITS_CONST", Value: 1},
}
const revision_32 = "8e3bfbc4dd1f6619b4895bcb80e0004ef4c96928"
const revision_32 = "0d78e9b1f441c9ae33361f9778195af0a245ffdd"

View File

@ -8,12 +8,38 @@ func init() {
}
var resources_64 = []*ResourceDesc{
{Name: "anyres32", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"anyres32"}, Values: []uint64{0}},
{Name: "anyres64", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int64", TypeSize: 8}}}, Kind: []string{"anyres64"}, Values: []uint64{0}},
{Name: "fd", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"fd"}, Values: []uint64{18446744073709551615}},
{Name: "syz_missing_const_res", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"syz_missing_const_res"}, Values: []uint64{0}},
{Name: "syz_res", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", TypeSize: 4}}}, Kind: []string{"syz_res"}, Values: []uint64{65535}},
}
var structDescs_64 = []*KeyedStruct{
{Key: StructKey{Name: "any0"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "any0", IsVarlen: true}, Fields: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", FldName: "f1", TypeSize: 1}}},
&ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 3}}, IsPad: true},
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "f2", TypeSize: 4}}},
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int16be", FldName: "f3", TypeSize: 2}, BigEndian: true}},
&ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 6}}, IsPad: true},
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int64", FldName: "f4", TypeSize: 8}}},
&ArrayType{TypeCommon: TypeCommon{TypeName: "array", FldName: "f5", IsVarlen: true}, Type: &StructType{Key: StructKey{Name: "any1"}}},
}, AlignAttr: 8}},
{Key: StructKey{Name: "any1"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "any1", IsVarlen: true}, Fields: []Type{
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "f1", TypeSize: 8, IsOptional: true}, Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", TypeSize: 1}}}},
&UnionType{Key: StructKey{Name: "anyunion0"}, FldName: "f2"},
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr64", FldName: "f3", TypeSize: 8, IsOptional: true}, Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", TypeSize: 1}}}},
&UnionType{Key: StructKey{Name: "anyunion1"}, FldName: "f4"},
&BufferType{TypeCommon: TypeCommon{TypeName: "array", FldName: "f5", IsVarlen: true}},
}, AlignAttr: 2}},
{Key: StructKey{Name: "anyunion0"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "anyunion0", TypeSize: 8}, Fields: []Type{
&ResourceType{TypeCommon: TypeCommon{TypeName: "anyres32", FldName: "res32", TypeSize: 4}},
&ResourceType{TypeCommon: TypeCommon{TypeName: "anyres64", FldName: "res64", TypeSize: 8}},
}}},
{Key: StructKey{Name: "anyunion1"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "anyunion1", IsVarlen: true}, Fields: []Type{
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int8", FldName: "i8", TypeSize: 1}}},
&IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "i32", TypeSize: 4}}},
}}},
{Key: StructKey{Name: "len_nontemp4"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "len_nontemp4", TypeSize: 4}, Fields: []Type{
&LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "f1", TypeSize: 4}}, Buf: "len_temp3"},
}}},
@ -443,6 +469,13 @@ var structDescs_64 = []*KeyedStruct{
}
var syscalls_64 = []*Syscall{
{Name: "foo$any0", CallName: "foo", Args: []Type{
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a", TypeSize: 8}, Type: &StructType{Key: StructKey{Name: "any0"}}},
}},
{Name: "foo$anyres", CallName: "foo", Args: []Type{
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a0", TypeSize: 8}, Type: &ResourceType{TypeCommon: TypeCommon{TypeName: "anyres32", TypeSize: 4, ArgDir: 1}}},
&PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "a1", TypeSize: 8}, Type: &ResourceType{TypeCommon: TypeCommon{TypeName: "anyres64", TypeSize: 8, ArgDir: 1}}},
}},
{Name: "mmap", CallName: "mmap", Args: []Type{
&VmaType{TypeCommon: TypeCommon{TypeName: "vma", FldName: "addr", TypeSize: 8}},
&LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "len", TypeSize: 8}}, Buf: "addr"},
@ -737,4 +770,4 @@ var consts_64 = []ConstValue{
{Name: "IPPROTO_UDP", Value: 17},
}
const revision_64 = "4a4abb9774bf056d0952d60f2fffdfdc392353a2"
const revision_64 = "e361957ea430829459298bc20840e4edbd324930"

35
sys/test/any.txt Normal file
View File

@ -0,0 +1,35 @@
# Copyright 2018 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.
resource anyres32[int32]
resource anyres64[int64]
foo$anyres(a0 ptr[out, anyres32], a1 ptr[out, anyres64])
foo$any0(a ptr[in, any0])
any0 {
f1 int8
f2 int32
f3 int16be
f4 int64
f5 array[any1]
} [align_8]
any1 {
f1 ptr[in, int8, opt]
f2 anyunion0
f3 ptr64[in, int8, opt]
f4 anyunion1
f5 array[int8]
} [packed, align_2]
anyunion0 [
res32 anyres32
res64 anyres64
]
anyunion1 [
i8 int8
i32 int32
] [varlen]

View File

@ -478,11 +478,11 @@ func (fuzzer *Fuzzer) corpusSignalDiff(sign signal.Signal) signal.Signal {
return fuzzer.corpusSignal.Diff(sign)
}
func (fuzzer *Fuzzer) checkNewSignal(info []ipc.CallInfo) (calls []int) {
func (fuzzer *Fuzzer) checkNewSignal(p *prog.Prog, info []ipc.CallInfo) (calls []int) {
fuzzer.signalMu.RLock()
defer fuzzer.signalMu.RUnlock()
for i, inf := range info {
diff := fuzzer.maxSignal.DiffRaw(inf.Signal, signalPrio(&inf))
diff := fuzzer.maxSignal.DiffRaw(inf.Signal, signalPrio(p.Target, p.Calls[i], &inf))
if diff.Empty() {
continue
}
@ -497,11 +497,14 @@ func (fuzzer *Fuzzer) checkNewSignal(info []ipc.CallInfo) (calls []int) {
return
}
func signalPrio(ci *ipc.CallInfo) uint8 {
func signalPrio(target *prog.Target, c *prog.Call, ci *ipc.CallInfo) (prio uint8) {
if ci.Errno == 0 {
return 1
prio |= 1 << 1
}
return 0
if !target.CallContainsAny(c) {
prio |= 1 << 0
}
return
}
func (fuzzer *Fuzzer) leakCheckCallback() {

View File

@ -103,13 +103,13 @@ func (proc *Proc) triageInput(item *WorkTriage) {
panic("should not be called when coverage is disabled")
}
inputSignal := signal.FromRaw(item.info.Signal, signalPrio(&item.info))
call := item.p.Calls[item.call]
inputSignal := signal.FromRaw(item.info.Signal, signalPrio(item.p.Target, call, &item.info))
newSignal := proc.fuzzer.corpusSignalDiff(inputSignal)
if newSignal.Empty() {
return
}
call := item.p.Calls[item.call].Meta
Logf(3, "triaging input for %v (new signal=%v)", call.CallName, newSignal.Len())
Logf(3, "triaging input for %v (new signal=%v)", call.Meta.CallName, newSignal.Len())
var inputCover cover.Cover
const (
signalRuns = 3
@ -128,7 +128,7 @@ func (proc *Proc) triageInput(item *WorkTriage) {
continue
}
inf := info[item.call]
thisSignal := signal.FromRaw(inf.Signal, signalPrio(&inf))
thisSignal := signal.FromRaw(inf.Signal, signalPrio(item.p.Target, call, &inf))
newSignal = newSignal.Intersection(thisSignal)
// Without !minimized check manager starts losing some considerable amount
// of coverage after each restart. Mechanics of this are not completely clear.
@ -151,7 +151,8 @@ func (proc *Proc) triageInput(item *WorkTriage) {
// Successful calls are much more valuable.
return false
}
thisSignal := signal.FromRaw(inf.Signal, signalPrio(&inf))
prio := signalPrio(p1.Target, p1.Calls[call1], &inf)
thisSignal := signal.FromRaw(inf.Signal, prio)
if newSignal.Intersection(thisSignal).Len() == newSignal.Len() {
return true
}
@ -163,9 +164,9 @@ func (proc *Proc) triageInput(item *WorkTriage) {
data := item.p.Serialize()
sig := hash.Hash(data)
Logf(2, "added new input for %v to corpus:\n%s", call.CallName, data)
Logf(2, "added new input for %v to corpus:\n%s", call.Meta.CallName, data)
proc.fuzzer.sendInputToManager(RpcInput{
Call: call.CallName,
Call: call.Meta.CallName,
Prog: data,
Signal: inputSignal.Serialize(),
Cover: inputCover.Serialize(),
@ -227,7 +228,7 @@ func (proc *Proc) executeHintSeed(p *prog.Prog, call int) {
func (proc *Proc) execute(execOpts *ipc.ExecOpts, p *prog.Prog, flags ProgTypes, stat Stat) []ipc.CallInfo {
info := proc.executeRaw(execOpts, p, stat)
for _, callIndex := range proc.fuzzer.checkNewSignal(info) {
for _, callIndex := range proc.fuzzer.checkNewSignal(p, info) {
info := info[callIndex]
// info.Signal points to the output shmem region, detach it before queueing.
info.Signal = append([]uint32{}, info.Signal...)