diff options
| author | Andrey Konovalov <andreyknvl@gmail.com> | 2017-01-18 19:37:40 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-01-18 19:37:40 +0100 |
| commit | 43383bd973203b4b70b2c4b4fa46f84dc003f560 (patch) | |
| tree | b2f244143ce9ecc11d20d47735e5044f4f4ef9e1 /prog | |
| parent | 1ac75f06add54089e4910ecb6a97198336155c63 (diff) | |
| parent | a370347640ba8b56360a092746dd6133a392792d (diff) | |
Merge pull request #108 from xairy/fix-align
Fix alignment and padding
Diffstat (limited to 'prog')
| -rw-r--r-- | prog/encodingexec.go | 57 | ||||
| -rw-r--r-- | prog/encodingexec_test.go | 76 | ||||
| -rw-r--r-- | prog/mutation.go | 11 | ||||
| -rw-r--r-- | prog/prog.go | 18 | ||||
| -rw-r--r-- | prog/validation.go | 7 |
5 files changed, 133 insertions, 36 deletions
diff --git a/prog/encodingexec.go b/prog/encodingexec.go index 57ff32eab..6dc8c88d2 100644 --- a/prog/encodingexec.go +++ b/prog/encodingexec.go @@ -38,47 +38,45 @@ func (p *Prog) SerializeForExec(pid int) []byte { w := &execContext{args: make(map[*Arg]*argInfo)} for _, c := range p.Calls { // Calculate arg offsets within structs. - foreachArg(c, func(arg, base *Arg, _ *[]*Arg) { - if base == nil || arg.Kind == ArgGroup || arg.Kind == ArgUnion { - return - } - if w.args[base] == nil { - w.args[base] = &argInfo{} - } - w.args[arg] = &argInfo{Offset: w.args[base].CurSize} - if arg.Type.BitfieldLength() == 0 || arg.Type.BitfieldLast() { - w.args[base].CurSize += arg.Size() - } - }) // Generate copyin instructions that fill in data into pointer arguments. foreachArg(c, func(arg, _ *Arg, _ *[]*Arg) { if arg.Kind == ArgPointer && arg.Res != nil { - var rec func(*Arg) - rec = func(arg1 *Arg) { + var rec func(*Arg, uintptr) uintptr + rec = func(arg1 *Arg, offset uintptr) uintptr { + w.args[arg1] = &argInfo{Offset: offset} if arg1.Kind == ArgGroup { + var totalSize uintptr for _, arg2 := range arg1.Inner { - rec(arg2) + size := rec(arg2, offset) + if arg2.Type.BitfieldLength() == 0 || arg2.Type.BitfieldLast() { + offset += size + totalSize += size + } + } + if totalSize > arg1.Size() { + panic(fmt.Sprintf("bad group arg size %v, should be <= %v for %+v", totalSize, arg1.Size(), arg1)) } - return + return arg1.Size() } if arg1.Kind == ArgUnion { - rec(arg1.Option) - return - } - if sys.IsPad(arg1.Type) { - return - } - if arg1.Kind == ArgData && len(arg1.Data) == 0 { - return + size := rec(arg1.Option, offset) + offset += size + if size > arg1.Size() { + panic(fmt.Sprintf("bad union arg size %v, should be <= %v for %+v", size, arg1.Size(), arg1)) + } + return arg1.Size() } - if arg1.Type.Dir() != sys.DirOut { + if !sys.IsPad(arg1.Type) && + !(arg1.Kind == ArgData && len(arg1.Data) == 0) && + arg1.Type.Dir() != sys.DirOut { w.write(ExecInstrCopyin) - w.write(physicalAddr(arg) + w.args[arg1].Offset) + w.write(physicalAddr(arg) + offset) w.writeArg(arg1, pid) instrSeq++ } + return arg1.Size() } - rec(arg.Res) + rec(arg.Res, 0) } }) // Generate the call itself. @@ -136,9 +134,8 @@ type execContext struct { } type argInfo struct { - Offset uintptr // from base pointer - CurSize uintptr - Idx uintptr // instruction index + Offset uintptr // from base pointer + Idx uintptr // instruction index } func (w *execContext) write(v uintptr) { diff --git a/prog/encodingexec_test.go b/prog/encodingexec_test.go index 25960b338..5ff80b698 100644 --- a/prog/encodingexec_test.go +++ b/prog/encodingexec_test.go @@ -91,6 +91,49 @@ func TestSerializeForExec(t *testing.T) { }, }, { + "syz_test$align2(&(0x7f0000000000)={0x42, {[0x43]}, {[0x44]}})", + []uint64{ + instrCopyin, dataOffset + 0, argConst, 1, 0x42, 0, 0, + instrCopyin, dataOffset + 1, argConst, 2, 0x43, 0, 0, + instrCopyin, dataOffset + 4, argConst, 2, 0x44, 0, 0, + callID("syz_test$align2"), 1, argConst, ptrSize, dataOffset, 0, 0, + instrEOF, + }, + }, + { + "syz_test$align3(&(0x7f0000000000)={0x42, {0x43}, {0x44}})", + []uint64{ + instrCopyin, dataOffset + 0, argConst, 1, 0x42, 0, 0, + instrCopyin, dataOffset + 1, argConst, 1, 0x43, 0, 0, + instrCopyin, dataOffset + 4, argConst, 1, 0x44, 0, 0, + callID("syz_test$align3"), 1, argConst, ptrSize, dataOffset, 0, 0, + instrEOF, + }, + }, + { + "syz_test$align4(&(0x7f0000000000)={{0x42, 0x43}, 0x44})", + []uint64{ + instrCopyin, dataOffset + 0, argConst, 1, 0x42, 0, 0, + instrCopyin, dataOffset + 1, argConst, 2, 0x43, 0, 0, + instrCopyin, dataOffset + 4, argConst, 1, 0x44, 0, 0, + callID("syz_test$align4"), 1, argConst, ptrSize, dataOffset, 0, 0, + instrEOF, + }, + }, + { + "syz_test$align5(&(0x7f0000000000)={{0x42, []}, {0x43, [0x44, 0x45, 0x46]}, 0x47})", + []uint64{ + instrCopyin, dataOffset + 0, argConst, 8, 0x42, 0, 0, + instrCopyin, dataOffset + 8, argConst, 8, 0x43, 0, 0, + instrCopyin, dataOffset + 16, argConst, 2, 0x44, 0, 0, + instrCopyin, dataOffset + 18, argConst, 2, 0x45, 0, 0, + instrCopyin, dataOffset + 20, argConst, 2, 0x46, 0, 0, + instrCopyin, dataOffset + 24, argConst, 1, 0x47, 0, 0, + callID("syz_test$align5"), 1, argConst, ptrSize, dataOffset, 0, 0, + instrEOF, + }, + }, + { "syz_test$union0(&(0x7f0000000000)={0x1, @f2=0x2})", []uint64{ instrCopyin, dataOffset + 0, argConst, 8, 1, 0, 0, @@ -100,6 +143,24 @@ func TestSerializeForExec(t *testing.T) { }, }, { + "syz_test$union1(&(0x7f0000000000)={@f1=0x42, 0x43})", + []uint64{ + instrCopyin, dataOffset + 0, argConst, 4, 0x42, 0, 0, + instrCopyin, dataOffset + 8, argConst, 1, 0x43, 0, 0, + callID("syz_test$union1"), 1, argConst, ptrSize, dataOffset, 0, 0, + instrEOF, + }, + }, + { + "syz_test$union2(&(0x7f0000000000)={@f1=0x42, 0x43})", + []uint64{ + instrCopyin, dataOffset + 0, argConst, 4, 0x42, 0, 0, + instrCopyin, dataOffset + 4, argConst, 1, 0x43, 0, 0, + callID("syz_test$union2"), 1, argConst, ptrSize, dataOffset, 0, 0, + instrEOF, + }, + }, + { "syz_test$array0(&(0x7f0000000000)={0x1, [@f0=0x2, @f1=0x3], 0x4})", []uint64{ instrCopyin, dataOffset + 0, argConst, 1, 1, 0, 0, @@ -152,7 +213,7 @@ func TestSerializeForExec(t *testing.T) { }, }, { - "syz_test$bf(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42})", + "syz_test$bf0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42})", []uint64{ instrCopyin, dataOffset + 0, argConst, 2, 0x42, 0, 10, instrCopyin, dataOffset + 8, argConst, 8, 0x42, 0, 0, @@ -162,7 +223,18 @@ func TestSerializeForExec(t *testing.T) { instrCopyin, dataOffset + 24, argConst, 2, 0x42, 0, 11, instrCopyin, dataOffset + 26, argConst, 2, 0x4200, 0, 11, instrCopyin, dataOffset + 28, argConst, 1, 0x42, 0, 0, - callID("syz_test$bf"), 1, argConst, ptrSize, dataOffset, 0, 0, + callID("syz_test$bf0"), 1, argConst, ptrSize, dataOffset, 0, 0, + instrEOF, + }, + }, + { + "syz_test$bf1(&(0x7f0000000000)={{0x42, 0x42, 0x42}, 0x42})", + []uint64{ + instrCopyin, dataOffset + 0, argConst, 4, 0x42, 0, 10, + instrCopyin, dataOffset + 0, argConst, 4, 0x42, 10, 10, + instrCopyin, dataOffset + 0, argConst, 4, 0x42, 20, 10, + instrCopyin, dataOffset + 4, argConst, 1, 0x42, 0, 0, + callID("syz_test$bf1"), 1, argConst, ptrSize, dataOffset, 0, 0, instrEOF, }, }, diff --git a/prog/mutation.go b/prog/mutation.go index 9a48bcf98..eacce8033 100644 --- a/prog/mutation.go +++ b/prog/mutation.go @@ -5,6 +5,7 @@ package prog import ( "fmt" + "math" "math/rand" "unsafe" @@ -88,7 +89,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro panic(fmt.Sprintf("bad arg kind for BufferType: %v", arg.Kind)) } minLen := int(0) - maxLen := ^int(0) + maxLen := math.MaxInt32 if a.Kind == sys.BufferBlobRange { minLen = int(a.RangeBegin) maxLen = int(a.RangeEnd) @@ -96,7 +97,13 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro arg.Data = mutateData(r, data, minLen, maxLen) case sys.BufferString: if r.bin() { - arg.Data = mutateData(r, append([]byte{}, arg.Data...), int(0), ^int(0)) + minLen := int(0) + maxLen := math.MaxInt32 + if a.Length != 0 { + minLen = int(a.Length) + maxLen = int(a.Length) + } + arg.Data = mutateData(r, append([]byte{}, arg.Data...), minLen, maxLen) } else { arg.Data = r.randString(s, a.Values, a.Dir()) } diff --git a/prog/prog.go b/prog/prog.go index cdc2dfe3c..cc45b1352 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -112,11 +112,25 @@ func (a *Arg) Size() uintptr { case *sys.StructType: var size uintptr for _, fld := range a.Inner { - size += fld.Size() + if fld.Type.BitfieldLength() == 0 || fld.Type.BitfieldLast() { + size += fld.Size() + } + } + align := typ.Align() + if size%align != 0 { + if typ.Varlen { + size += align - size%align + } else { + panic(fmt.Sprintf("struct %+v with type %+v has static size %v, which isn't aligned to %v", a, typ, size, align)) + } } return size case *sys.UnionType: - return a.Option.Size() + if !typ.Varlen { + return typ.Size() + } else { + return a.Option.Size() + } case *sys.ArrayType: var size uintptr for _, in := range a.Inner { diff --git a/prog/validation.go b/prog/validation.go index b2d539282..75d8e95a4 100644 --- a/prog/validation.go +++ b/prog/validation.go @@ -97,6 +97,13 @@ func (c *Call) validate(ctx *validCtx) error { if arg.Val >= uintptr(typ1.ValuesPerProc) { return fmt.Errorf("syscall %v: per proc arg '%v' has bad value '%v'", c.Meta.Name, typ.Name(), arg.Val) } + case *sys.BufferType: + switch typ1.Kind { + case sys.BufferString: + if typ1.Length != 0 && len(arg.Data) != int(typ1.Length) { + return fmt.Errorf("syscall %v: string arg '%v' has size %v, which should be %v", c.Meta.Name, len(arg.Data), typ1.Length) + } + } } switch arg.Kind { case ArgConst: |
