aboutsummaryrefslogtreecommitdiffstats
path: root/prog
diff options
context:
space:
mode:
authorAndrey Konovalov <andreyknvl@gmail.com>2017-01-18 19:37:40 +0100
committerGitHub <noreply@github.com>2017-01-18 19:37:40 +0100
commit43383bd973203b4b70b2c4b4fa46f84dc003f560 (patch)
treeb2f244143ce9ecc11d20d47735e5044f4f4ef9e1 /prog
parent1ac75f06add54089e4910ecb6a97198336155c63 (diff)
parenta370347640ba8b56360a092746dd6133a392792d (diff)
Merge pull request #108 from xairy/fix-align
Fix alignment and padding
Diffstat (limited to 'prog')
-rw-r--r--prog/encodingexec.go57
-rw-r--r--prog/encodingexec_test.go76
-rw-r--r--prog/mutation.go11
-rw-r--r--prog/prog.go18
-rw-r--r--prog/validation.go7
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: