diff --git a/prog/encoding.go b/prog/encoding.go index bb366ea..47addb5 100644 --- a/prog/encoding.go +++ b/prog/encoding.go @@ -43,6 +43,9 @@ func (p *Prog) Serialize() []byte { } fmt.Fprintf(buf, "%v(", c.Meta.Name) for i, a := range c.Args { + if sys.IsPad(a.Type) { + continue + } if i != 0 { fmt.Fprintf(buf, ", ") } @@ -59,7 +62,7 @@ func (a *Arg) serialize(buf io.Writer, vars map[*Arg]int, varSeq *int) { return } if len(a.Uses) != 0 { - fmt.Fprintf(buf, "[r%v=]", *varSeq) + fmt.Fprintf(buf, "", *varSeq) vars[a] = *varSeq *varSeq++ } @@ -86,14 +89,26 @@ func (a *Arg) serialize(buf io.Writer, vars map[*Arg]int, varSeq *int) { case ArgData: fmt.Fprintf(buf, "\"%v\"", hex.EncodeToString(a.Data)) case ArgGroup: - fmt.Fprintf(buf, "{") + var delims []byte + switch a.Type.(type) { + case sys.StructType: + delims = []byte{'{', '}'} + case sys.ArrayType: + delims = []byte{'[', ']'} + default: + panic("unknown group type") + } + buf.Write([]byte{delims[0]}) for i, a1 := range a.Inner { + if a1 != nil && sys.IsPad(a1.Type) { + continue + } if i != 0 { fmt.Fprintf(buf, ", ") } a1.serialize(buf, vars, varSeq) } - fmt.Fprintf(buf, "}") + buf.Write([]byte{delims[1]}) default: panic("unknown arg kind") } @@ -123,7 +138,14 @@ func Deserialize(data []byte) (prog *Prog, err error) { prog.Calls = append(prog.Calls, c) p.Parse('(') for i := 0; p.Char() != ')'; i++ { - arg, err := parseArg(p, vars) + if i >= len(meta.Args) { + return nil, fmt.Errorf("wrong call arg count: %v, want %v", i+1, len(meta.Args)) + } + typ := meta.Args[i] + if sys.IsPad(typ) { + return nil, fmt.Errorf("padding in syscall %v arguments", name) + } + arg, err := parseArg(typ, p, vars) if err != nil { return nil, err } @@ -155,13 +177,13 @@ func Deserialize(data []byte) (prog *Prog, err error) { return } -func parseArg(p *parser, vars map[string]*Arg) (*Arg, error) { +func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { r := "" - if p.Char() == '[' { - p.Parse('[') + if p.Char() == '<' { + p.Parse('<') r = p.Ident() p.Parse('=') - p.Parse(']') + p.Parse('>') } var arg *Arg switch p.Char() { @@ -198,13 +220,21 @@ func parseArg(p *parser, vars map[string]*Arg) (*Arg, error) { arg.OpAdd = uintptr(v) } case '&': + var typ1 sys.Type + switch t1 := typ.(type) { + case sys.PtrType: + typ1 = t1.Type + case sys.VmaType: + default: + return nil, fmt.Errorf("& arg is not a pointer: %#v", typ) + } p.Parse('&') page, off, err := parseAddr(p, true) if err != nil { return nil, err } p.Parse('=') - inner, err := parseArg(p, vars) + inner, err := parseArg(typ1, p, vars) if err != nil { return nil, err } @@ -228,19 +258,53 @@ func parseArg(p *parser, vars map[string]*Arg) (*Arg, error) { } arg = dataArg(data) case '{': + t1, ok := typ.(sys.StructType) + if !ok { + return nil, fmt.Errorf("'{' arg is not a struct: %#v", typ) + } p.Parse('{') var inner []*Arg - for p.Char() != '}' { - arg, err := parseArg(p, vars) + for i := 0; p.Char() != '}'; i++ { + if i >= len(t1.Fields) { + return nil, fmt.Errorf("wrong struct arg count: %v, want %v", i+1, len(t1.Fields)) + } + fld := t1.Fields[i] + if sys.IsPad(fld) { + inner = append(inner, constArg(0)) + } else { + arg, err := parseArg(fld, p, vars) + if err != nil { + return nil, err + } + inner = append(inner, arg) + if p.Char() != '}' { + p.Parse(',') + } + } + } + p.Parse('}') + if sys.IsPad(t1.Fields[len(t1.Fields)-1]) { + inner = append(inner, constArg(0)) + } + arg = groupArg(inner) + case '[': + t1, ok := typ.(sys.ArrayType) + if !ok { + return nil, fmt.Errorf("'[' arg is not an array: %#v", typ) + } + p.Parse('[') + var inner []*Arg + for i := 0; p.Char() != ']'; i++ { + arg, err := parseArg(t1.Type, p, vars) if err != nil { return nil, err } inner = append(inner, arg) - if p.Char() != '}' { + if p.Char() != ']' { p.Parse(',') } } - p.Parse('}') + p.Parse(']') arg = groupArg(inner) case 'n': p.Parse('n') diff --git a/prog/encodingexec.go b/prog/encodingexec.go index 3b0d4c2..3b68f6c 100644 --- a/prog/encodingexec.go +++ b/prog/encodingexec.go @@ -8,6 +8,8 @@ package prog import ( "fmt" + + "github.com/google/syzkaller/sys" ) const ( @@ -57,7 +59,7 @@ func (p *Prog) SerializeForExec() []byte { } return } - if pad, _ := arg1.IsPad(); pad { + if sys.IsPad(arg1.Type) { return } if arg1.Kind == ArgData && len(arg1.Data) == 0 { diff --git a/prog/mutation_test.go b/prog/mutation_test.go index 37db7cd..53acba0 100644 --- a/prog/mutation_test.go +++ b/prog/mutation_test.go @@ -212,7 +212,7 @@ func TestMinimize(t *testing.T) { // Remove a call and replace results. { "mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" + - "pipe2(&(0x7f0000000000)={[r0=]0x0, 0x0}, 0x0)\n" + + "pipe2(&(0x7f0000000000)={0x0, 0x0}, 0x0)\n" + "write(r0, &(0x7f0000000000)=\"1155\", 0x2)\n" + "sched_yield()\n", 3, @@ -259,7 +259,7 @@ func TestMinimize(t *testing.T) { for ti, test := range tests { p, err := Deserialize([]byte(test.orig)) if err != nil { - t.Fatalf("failed to deserialize original program: %v", err) + t.Fatalf("failed to deserialize original program #%v: %v", ti, err) } p1, ci := Minimize(p, test.callIndex, test.pred) res := p1.Serialize() diff --git a/prog/prog.go b/prog/prog.go index 8bc8d67..e4c1c72 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -79,13 +79,6 @@ func (a *Arg) Size(typ sys.Type) uintptr { } } -func (a *Arg) IsPad() (bool, uintptr) { - if ct, ok := a.Type.(sys.ConstType); ok && ct.Val == 0 && ct.Name() == "pad" { - return true, ct.TypeSize - } - return false, 0 -} - func constArg(v uintptr) *Arg { return &Arg{Kind: ArgConst, Val: v} } diff --git a/prog/rand.go b/prog/rand.go index 0042a5d..962f9f8 100644 --- a/prog/rand.go +++ b/prog/rand.go @@ -462,7 +462,7 @@ func (r *randGen) createResource(s *state, res sys.ResourceType) (arg *Arg, call // Generate one of them. meta := metas[r.Intn(len(metas))] calls := r.generateParticularCall(s, meta) - assignTypeAndDir(calls[len(calls)-1]) + //assignTypeAndDir(calls[len(calls)-1]) s1 := newState(s.ct) s1.analyze(calls[len(calls)-1]) // Now see if we have what we want. diff --git a/prog/validation.go b/prog/validation.go index a06f98d..cc6d1ae 100644 --- a/prog/validation.go +++ b/prog/validation.go @@ -18,12 +18,6 @@ func (p *Prog) validate() error { ctx := &validCtx{make(map[*Arg]bool), make(map[*Arg]*Arg)} for _, c := range p.Calls { if err := c.validate(ctx); err != nil { - - fmt.Printf("PROGRAM:\n") - for _, c := range p.Calls { - fmt.Printf(" %v: %+v %p\n", c.Meta.Name, c.Args, c.Ret) - } - return err } } @@ -36,6 +30,9 @@ func (p *Prog) validate() error { } func (c *Call) validate(ctx *validCtx) error { + if c.Meta == nil { + return fmt.Errorf("call does not have meta information") + } if len(c.Args) != len(c.Meta.Args) { return fmt.Errorf("syscall %v: wrong number of arguments, want %v, got %v", c.Meta.Name, len(c.Meta.Args), len(c.Args)) } diff --git a/sys/decl.go b/sys/decl.go index 82f1871..af3202a 100644 --- a/sys/decl.go +++ b/sys/decl.go @@ -23,6 +23,13 @@ type Type interface { Align() uintptr } +func IsPad(t Type) bool { + if ct, ok := t.(ConstType); ok && ct.IsPad { + return true + } + return false +} + type TypeCommon struct { TypeName string IsOptional bool @@ -313,6 +320,7 @@ type ConstType struct { TypeCommon TypeSize uintptr Val uintptr + IsPad bool } func (t ConstType) Size() uintptr { @@ -654,5 +662,6 @@ func makePad(sz uintptr) Type { TypeCommon: TypeCommon{TypeName: "pad", IsOptional: false}, TypeSize: sz, Val: 0, + IsPad: true, } }