diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2016-11-11 14:44:01 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-11-11 14:44:01 -0800 |
| commit | 89abacc228e60afe1df0b01d36dc7fe886ca7bcc (patch) | |
| tree | f0ca6508ab6f3b6ea78e6260c28dd09f37c9d48c | |
| parent | 85f78e771dced807e5e09b8012ec38333e442bb7 (diff) | |
| parent | 3a65453870b12f5c42739c27d99df8fc58358f88 (diff) | |
Merge pull request #86 from google/sys_ptrs
A bunch of changes to sys/prog package
| -rw-r--r-- | host/host.go | 32 | ||||
| -rw-r--r-- | prog/analysis.go | 202 | ||||
| -rw-r--r-- | prog/clone.go | 1 | ||||
| -rw-r--r-- | prog/encoding.go | 38 | ||||
| -rw-r--r-- | prog/encodingexec.go | 16 | ||||
| -rw-r--r-- | prog/mutation.go | 86 | ||||
| -rw-r--r-- | prog/prio.go | 68 | ||||
| -rw-r--r-- | prog/prog.go | 120 | ||||
| -rw-r--r-- | prog/rand.go | 323 | ||||
| -rw-r--r-- | prog/size_test.go | 3 | ||||
| -rw-r--r-- | prog/validation.go | 35 | ||||
| -rw-r--r-- | sys/README.md | 16 | ||||
| -rw-r--r-- | sys/align.go | 10 | ||||
| -rw-r--r-- | sys/bpf.txt | 2 | ||||
| -rw-r--r-- | sys/decl.go | 331 | ||||
| -rw-r--r-- | sys/dri.txt | 6 | ||||
| -rw-r--r-- | sys/input.txt | 6 | ||||
| -rw-r--r-- | sys/kdbus.txt | 2 | ||||
| -rw-r--r-- | sys/key.txt | 8 | ||||
| -rw-r--r-- | sys/kvm.txt | 4 | ||||
| -rw-r--r-- | sys/perf.txt | 2 | ||||
| -rwxr-xr-x | sys/random.txt | 4 | ||||
| -rw-r--r-- | sys/sndcontrol.txt | 4 | ||||
| -rw-r--r-- | sys/sndseq.txt | 2 | ||||
| -rw-r--r-- | sys/sndtimer.txt | 2 | ||||
| -rw-r--r-- | sys/socket.txt | 9 | ||||
| -rw-r--r-- | sys/sys.txt | 163 | ||||
| -rw-r--r-- | sys/tlk_device.txt | 2 | ||||
| -rw-r--r-- | sys/tty.txt | 2 | ||||
| -rwxr-xr-x | sys/tun.txt | 2 | ||||
| -rw-r--r-- | sysgen/sysgen.go | 173 | ||||
| -rw-r--r-- | sysparser/lexer.go | 26 | ||||
| -rw-r--r-- | sysparser/parser.go | 3 |
33 files changed, 710 insertions, 993 deletions
diff --git a/host/host.go b/host/host.go index 220f8aaf6..a58964e8c 100644 --- a/host/host.go +++ b/host/host.go @@ -60,11 +60,7 @@ func isSupportedSyzkall(c *sys.Call) bool { case "syz_test": return false case "syz_open_dev": - ptr, ok := c.Args[0].(sys.PtrType) - if !ok { - return true - } - fname, ok := ptr.Type.(sys.StrConstType) + fname, ok := extractStringConst(c.Args[0]) if !ok { panic("first open arg is not a pointer to string const") } @@ -84,7 +80,7 @@ func isSupportedSyzkall(c *sys.Call) bool { } return false } - return check(fname.Val[:len(fname.Val)-1]) + return check(fname) case "syz_open_pts": return true case "syz_fuse_mount": @@ -99,7 +95,7 @@ func isSupportedSyzkall(c *sys.Call) bool { } func isSupportedSocket(c *sys.Call) bool { - af, ok := c.Args[0].(sys.ConstType) + af, ok := c.Args[0].(*sys.ConstType) if !ok { println(c.Name) panic("socket family is not const") @@ -112,17 +108,27 @@ func isSupportedSocket(c *sys.Call) bool { } func isSupportedOpen(c *sys.Call) bool { - ptr, ok := c.Args[0].(sys.PtrType) - if !ok { - panic("first open arg is not a pointer") - } - fname, ok := ptr.Type.(sys.StrConstType) + fname, ok := extractStringConst(c.Args[0]) if !ok { return true } - fd, err := syscall.Open(fname.Val[:len(fname.Val)-1], syscall.O_RDONLY, 0) + fd, err := syscall.Open(fname, syscall.O_RDONLY, 0) if fd != -1 { syscall.Close(fd) } return err == nil } + +func extractStringConst(typ sys.Type) (string, bool) { + ptr, ok := typ.(*sys.PtrType) + if !ok { + panic("first open arg is not a pointer to string const") + } + str, ok := ptr.Type.(*sys.BufferType) + if !ok || str.Kind != sys.BufferString || len(str.Values) != 1 { + return "", false + } + v := str.Values[0] + v = v[:len(v)-1] // string terminating \x00 + return v, true +} diff --git a/prog/analysis.go b/prog/analysis.go index baf87fbb5..4bf6506f1 100644 --- a/prog/analysis.go +++ b/prog/analysis.go @@ -51,18 +51,19 @@ func newState(ct *ChoiceTable) *state { func (s *state) analyze(c *Call) { foreachArgArray(&c.Args, c.Ret, func(arg, base *Arg, _ *[]*Arg) { switch typ := arg.Type.(type) { - case sys.FilenameType: - if arg.Kind == ArgData && arg.Dir != DirOut { - s.files[string(arg.Data)] = true - } - case sys.ResourceType: - if arg.Dir != DirIn { + case *sys.ResourceType: + if arg.Type.Dir() != sys.DirIn { s.resources[typ.Desc.Name] = append(s.resources[typ.Desc.Name], arg) // TODO: negative PIDs and add them as well (that's process groups). } - case sys.BufferType: - if typ.Kind == sys.BufferString && arg.Kind == ArgData && len(arg.Data) != 0 { - s.strings[string(arg.Data)] = true + case *sys.BufferType: + if arg.Type.Dir() != sys.DirOut && arg.Kind == ArgData && len(arg.Data) != 0 { + switch typ.Kind { + case sys.BufferString: + s.strings[string(arg.Data)] = true + case sys.BufferFilename: + s.files[string(arg.Data)] = true + } } } }) @@ -149,186 +150,67 @@ func foreachArg(c *Call, f func(arg, base *Arg, parent *[]*Arg)) { foreachArgArray(&c.Args, nil, f) } -func assignTypeAndDir(c *Call) error { - var rec func(arg *Arg, typ sys.Type, dir ArgDir) error - rec = func(arg *Arg, typ sys.Type, dir ArgDir) error { - if arg.Call != nil && arg.Call != c { - panic(fmt.Sprintf("different call is already assigned: %p %p %v %v", arg.Call, c, arg.Call.Meta.Name, c.Meta.Name)) - } - arg.Call = c - if arg.Type != nil && arg.Type.Name() != typ.Name() { - panic("different type is already assigned: " + arg.Type.Name() + " vs " + typ.Name()) - } - arg.Type = typ - switch arg.Kind { - case ArgPointer: - arg.Dir = DirIn - switch typ1 := typ.(type) { - case sys.PtrType: - if arg.Res != nil { - if err := rec(arg.Res, typ1.Type, ArgDir(typ1.Dir)); err != nil { - return err - } - } - } - case ArgGroup: - arg.Dir = dir - switch typ1 := typ.(type) { - case *sys.StructType: - if len(arg.Inner) != len(typ1.Fields) { - return fmt.Errorf("wrong struct field count: %v, want %v", len(arg.Inner), len(typ1.Fields)) - } - for i, arg1 := range arg.Inner { - if err := rec(arg1, typ1.Fields[i], dir); err != nil { - return err - } - } - case sys.ArrayType: - for _, arg1 := range arg.Inner { - if err := rec(arg1, typ1.Type, dir); err != nil { - return err - } - } - } - case ArgUnion: - arg.Dir = dir - if err := rec(arg.Option, arg.OptionType, dir); err != nil { - return err - } - default: - arg.Dir = dir - } - return nil - } - for i, arg := range c.Args { - if c.Meta == nil { - panic("nil meta") - } - if err := rec(arg, c.Meta.Args[i], DirIn); err != nil { - return err - } - } - if c.Ret == nil { - c.Ret = returnArg() - c.Ret.Call = c - c.Ret.Type = c.Meta.Ret - c.Ret.Dir = DirOut - } - return nil -} - -func generateSize(typ sys.Type, arg *Arg, lenType sys.LenType) *Arg { +func generateSize(arg *Arg, lenType *sys.LenType) *Arg { if arg == nil { // Arg is an optional pointer, set size to 0. - return constArg(0) + return constArg(lenType, 0) } - switch typ.(type) { - case sys.VmaType: - return pageSizeArg(arg.AddrPagesNum, 0) - case sys.ArrayType: + switch arg.Type.(type) { + case *sys.VmaType: + return pageSizeArg(lenType, arg.AddrPagesNum, 0) + case *sys.ArrayType: if lenType.ByteSize { - return constArg(arg.Size(typ)) + return constArg(lenType, arg.Size()) } else { - return constArg(uintptr(len(arg.Inner))) + return constArg(lenType, uintptr(len(arg.Inner))) } default: - return constArg(arg.Size(typ)) + return constArg(lenType, arg.Size()) } } -func assignSizes(types []sys.Type, args []*Arg) { +func assignSizes(args []*Arg) { + // Create a map of args and calculate size of the whole struct. argsMap := make(map[string]*Arg) - typesMap := make(map[string]sys.Type) - - // Create a map of args and types. - for i, typ := range types { - if sys.IsPad(typ) { + var parentSize uintptr + for _, arg := range args { + parentSize += arg.Size() + if sys.IsPad(arg.Type) { continue } - if typ.Name() == "parent" { - panic("parent is reserved len name") - } - - innerArg := args[i].InnerArg(typ) - innerType := typ.InnerType() - - if _, ok := argsMap[typ.Name()]; ok { - panic(fmt.Sprintf("mutiple args with the same name '%v', types: %+v, args: %+v", typ.Name(), types, args)) - } - argsMap[typ.Name()] = innerArg - typesMap[typ.Name()] = innerType - } - - // Calculate size of the whole struct. - var parentSize uintptr - for i, typ := range types { - parentSize += args[i].Size(typ) + argsMap[arg.Type.Name()] = arg } // Fill in size arguments. - for i, typ := range types { - if lenType, ok := typ.InnerType().(sys.LenType); ok { - lenArg := args[i].InnerArg(typ) - if lenArg == nil { - // Pointer to optional len field, no need to fill in value. - continue - } - - if lenType.Buf == "parent" { - *lenArg = *constArg(parentSize) + for _, arg := range args { + if arg = arg.InnerArg(); arg == nil { + continue // Pointer to optional len field, no need to fill in value. + } + if typ, ok := arg.Type.(*sys.LenType); ok { + if typ.Buf == "parent" { + arg.Val = parentSize continue } - arg, ok := argsMap[lenType.Buf] + buf, ok := argsMap[typ.Buf] if !ok { - panic(fmt.Sprintf("len field '%v' references non existent field '%v', argsMap: %+v, typesMap: %+v", - lenType.Name(), lenType.Buf, argsMap, typesMap)) + panic(fmt.Sprintf("len field '%v' references non existent field '%v', argsMap: %+v", + typ.Name(), typ.Buf, argsMap)) } - typ := typesMap[lenType.Buf] - *lenArg = *generateSize(typ, arg, lenType) + *arg = *generateSize(buf.InnerArg(), typ) } } } func assignSizesCall(c *Call) { - var rec func(arg *Arg, typ sys.Type) - rec = func(arg *Arg, typ sys.Type) { - switch arg.Kind { - case ArgPointer: - switch typ1 := typ.(type) { - case sys.PtrType: - if arg.Res != nil { - rec(arg.Res, typ1.Type) - } - } - case ArgGroup: - switch typ1 := typ.(type) { - case *sys.StructType: - if len(arg.Inner) != len(typ1.Fields) { - panic(fmt.Sprintf("wrong struct field count: %v, want %v", len(arg.Inner), len(typ1.Fields))) - } - for i, arg1 := range arg.Inner { - rec(arg1, typ1.Fields[i]) - } - assignSizes(typ1.Fields, arg.Inner) - case sys.ArrayType: - for _, arg1 := range arg.Inner { - rec(arg1, typ1.Type) - } - } - case ArgUnion: - rec(arg.Option, arg.OptionType) + assignSizes(c.Args) + foreachArg(c, func(arg, base *Arg, parent *[]*Arg) { + if _, ok := arg.Type.(*sys.StructType); ok { + assignSizes(arg.Inner) } - } - if c.Meta == nil { - panic("nil meta") - } - for i, arg := range c.Args { - rec(arg, c.Meta.Args[i]) - } - assignSizes(c.Meta.Args, c.Args) + }) } func sanitizeCall(c *Call) { diff --git a/prog/clone.go b/prog/clone.go index 14f9db759..69a54cd4e 100644 --- a/prog/clone.go +++ b/prog/clone.go @@ -24,7 +24,6 @@ func (p *Prog) Clone() *Prog { func (arg *Arg) clone(c *Call, newargs map[*Arg]*Arg) *Arg { arg1 := new(Arg) *arg1 = *arg - arg1.Call = c arg1.Data = append([]byte{}, arg.Data...) switch arg.Kind { case ArgPointer: diff --git a/prog/encoding.go b/prog/encoding.go index 01438f5b9..7afe218be 100644 --- a/prog/encoding.go +++ b/prog/encoding.go @@ -93,7 +93,7 @@ func (a *Arg) serialize(buf io.Writer, vars map[*Arg]int, varSeq *int) { switch a.Type.(type) { case *sys.StructType: delims = []byte{'{', '}'} - case sys.ArrayType: + case *sys.ArrayType: delims = []byte{'[', ']'} default: panic("unknown group type") @@ -137,7 +137,10 @@ func Deserialize(data []byte) (prog *Prog, err error) { if meta == nil { return nil, fmt.Errorf("unknown syscall %v", name) } - c := &Call{Meta: meta} + c := &Call{ + Meta: meta, + Ret: returnArg(meta.Ret), + } prog.Calls = append(prog.Calls, c) p.Parse('(') for i := 0; p.Char() != ')'; i++ { @@ -164,9 +167,6 @@ func Deserialize(data []byte) (prog *Prog, err error) { if len(c.Args) != len(meta.Args) { return nil, fmt.Errorf("wrong call arg count: %v, want %v", len(c.Args), len(meta.Args)) } - if err := assignTypeAndDir(c); err != nil { - return nil, err - } if r != "" { vars[r] = c.Ret } @@ -196,14 +196,14 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { if err != nil { return nil, fmt.Errorf("wrong arg value '%v': %v", val, err) } - arg = constArg(uintptr(v)) + arg = constArg(typ, uintptr(v)) case 'r': id := p.Ident() v, ok := vars[id] if !ok || v == nil { return nil, fmt.Errorf("result %v references unknown variable (vars=%+v)", id, vars) } - arg = resultArg(v) + arg = resultArg(typ, v) if p.Char() == '/' { p.Parse('/') op := p.Ident() @@ -225,9 +225,9 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { case '&': var typ1 sys.Type switch t1 := typ.(type) { - case sys.PtrType: + case *sys.PtrType: typ1 = t1.Type - case sys.VmaType: + case *sys.VmaType: default: return nil, fmt.Errorf("& arg is not a pointer: %#v", typ) } @@ -241,13 +241,13 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { if err != nil { return nil, err } - arg = pointerArg(page, off, size, inner) + arg = pointerArg(typ, page, off, size, inner) case '(': page, off, _, err := parseAddr(p, false) if err != nil { return nil, err } - arg = pageSizeArg(page, off) + arg = pageSizeArg(typ, page, off) case '"': p.Parse('"') val := "" @@ -259,7 +259,7 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { if err != nil { return nil, fmt.Errorf("data arg has bad value '%v'", val) } - arg = dataArg(data) + arg = dataArg(typ, data) case '{': t1, ok := typ.(*sys.StructType) if !ok { @@ -273,7 +273,7 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { } fld := t1.Fields[i] if sys.IsPad(fld) { - inner = append(inner, constArg(0)) + inner = append(inner, constArg(fld, 0)) } else { arg, err := parseArg(fld, p, vars) if err != nil { @@ -286,12 +286,12 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { } } p.Parse('}') - if sys.IsPad(t1.Fields[len(t1.Fields)-1]) { - inner = append(inner, constArg(0)) + if last := t1.Fields[len(t1.Fields)-1]; sys.IsPad(last) { + inner = append(inner, constArg(last, 0)) } - arg = groupArg(inner) + arg = groupArg(typ, inner) case '[': - t1, ok := typ.(sys.ArrayType) + t1, ok := typ.(*sys.ArrayType) if !ok { return nil, fmt.Errorf("'[' arg is not an array: %#v", typ) } @@ -308,7 +308,7 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { } } p.Parse(']') - arg = groupArg(inner) + arg = groupArg(typ, inner) case '@': t1, ok := typ.(*sys.UnionType) if !ok { @@ -331,7 +331,7 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { if err != nil { return nil, err } - arg = unionArg(opt, optType) + arg = unionArg(typ, opt, optType) case 'n': p.Parse('n') p.Parse('i') diff --git a/prog/encodingexec.go b/prog/encodingexec.go index 239ef3514..4c2cd2524 100644 --- a/prog/encodingexec.go +++ b/prog/encodingexec.go @@ -46,7 +46,7 @@ func (p *Prog) SerializeForExec() []byte { w.args[base] = &argInfo{} } w.args[arg] = &argInfo{Offset: w.args[base].CurSize} - w.args[base].CurSize += arg.Size(arg.Type) + w.args[base].CurSize += arg.Size() }) // Generate copyin instructions that fill in data into pointer arguments. foreachArg(c, func(arg, _ *Arg, _ *[]*Arg) { @@ -69,7 +69,7 @@ func (p *Prog) SerializeForExec() []byte { if arg1.Kind == ArgData && len(arg1.Data) == 0 { return } - if arg1.Dir != DirOut { + if arg1.Type.Dir() != sys.DirOut { w.write(ExecInstrCopyin) w.write(physicalAddr(arg) + w.args[arg1].Offset) w.writeArg(arg1) @@ -105,7 +105,7 @@ func (p *Prog) SerializeForExec() []byte { instrSeq++ w.write(ExecInstrCopyout) w.write(physicalAddr(base) + info.Offset) - w.write(arg.Size(arg.Type)) + w.write(arg.Size()) default: panic("bad arg kind in copyout") } @@ -147,21 +147,21 @@ func (w *execContext) writeArg(arg *Arg) { switch arg.Kind { case ArgConst: w.write(ExecArgConst) - w.write(arg.Size(arg.Type)) - w.write(arg.Value(arg.Type)) + w.write(arg.Size()) + w.write(arg.Value()) case ArgResult: w.write(ExecArgResult) - w.write(arg.Size(arg.Type)) + w.write(arg.Size()) w.write(w.args[arg.Res].Idx) w.write(arg.OpDiv) w.write(arg.OpAdd) case ArgPointer: w.write(ExecArgConst) - w.write(arg.Size(arg.Type)) + w.write(arg.Size()) w.write(physicalAddr(arg)) case ArgPageSize: w.write(ExecArgConst) - w.write(arg.Size(arg.Type)) + w.write(arg.Size()) w.write(arg.AddrPage * pageSize) case ArgData: w.write(ExecArgData) diff --git a/prog/mutation.go b/prog/mutation.go index 577e24796..8d5fa36a4 100644 --- a/prog/mutation.go +++ b/prog/mutation.go @@ -57,13 +57,13 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { if base.Kind != ArgPointer || base.Res == nil { panic("bad base arg") } - baseSize = base.Res.Size(base.Res.Type) + baseSize = base.Res.Size() } switch a := arg.Type.(type) { - case sys.IntType, sys.FlagsType, sys.FileoffType, sys.ResourceType, sys.VmaType: - arg1, calls1 := r.generateArg(s, arg.Type, arg.Dir) - p.replaceArg(arg, arg1, calls1) - case sys.BufferType: + case *sys.IntType, *sys.FlagsType, *sys.ResourceType, *sys.VmaType: + arg1, calls1 := r.generateArg(s, arg.Type) + p.replaceArg(c, arg, arg1, calls1) + case *sys.BufferType: switch a.Kind { case sys.BufferBlobRand, sys.BufferBlobRange: var data []byte @@ -89,23 +89,16 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { if r.bin() { arg.Data = mutateData(r, append([]byte{}, arg.Data...), int(0), ^int(0)) } else { - arg.Data = r.randString(s) + arg.Data = r.randString(s, a.Values, a.Dir()) } - case sys.BufferFilesystem: - arg.Data = r.filesystem(s) + case sys.BufferFilename: + arg.Data = []byte(r.filename(s)) case sys.BufferSockaddr: arg.Data = r.sockaddr(s) - case sys.BufferAlgType: - arg.Data = r.algType(s) - case sys.BufferAlgName: - arg.Data = r.algName(s) default: panic("unknown buffer kind") } - case sys.FilenameType: - filename := r.filename(s) - arg.Data = []byte(filename) - case sys.ArrayType: + case *sys.ArrayType: count := uintptr(0) switch a.Kind { case sys.ArrayRandLen: @@ -123,7 +116,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { if count > uintptr(len(arg.Inner)) { var calls []*Call for count > uintptr(len(arg.Inner)) { - arg1, calls1 := r.generateArg(s, a.Type, arg.Dir) + arg1, calls1 := r.generateArg(s, a.Type) arg.Inner = append(arg.Inner, arg1) for _, c1 := range calls1 { calls = append(calls, c1) @@ -131,27 +124,25 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { } } for _, c1 := range calls { - assignTypeAndDir(c1) sanitizeCall(c1) } - assignTypeAndDir(c) sanitizeCall(c) p.insertBefore(c, calls) } else if count < uintptr(len(arg.Inner)) { for _, arg := range arg.Inner[count:] { - p.removeArg(arg) + p.removeArg(c, arg) } arg.Inner = arg.Inner[:count] } // TODO: swap elements of the array - case sys.PtrType: + case *sys.PtrType: // TODO: we don't know size for out args size := uintptr(1) if arg.Res != nil { - size = arg.Res.Size(arg.Res.Type) + size = arg.Res.Size() } - arg1, calls1 := r.addr(s, size, arg.Res) - p.replaceArg(arg, arg1, calls1) + arg1, calls1 := r.addr(s, a, size, arg.Res) + p.replaceArg(c, arg, arg1, calls1) case *sys.StructType: ctor := isSpecialStruct(a) if ctor == nil { @@ -159,7 +150,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { } arg1, calls1 := ctor(r, s) for i, f := range arg1.Inner { - p.replaceArg(arg.Inner[i], f, calls1) + p.replaceArg(c, arg.Inner[i], f, calls1) calls1 = nil } case *sys.UnionType: @@ -167,23 +158,22 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { for optType.Name() == arg.OptionType.Name() { optType = a.Options[r.Intn(len(a.Options))] } - p.removeArg(arg.Option) - opt, calls := r.generateArg(s, optType, arg.Dir) - arg1 := unionArg(opt, optType) - p.replaceArg(arg, arg1, calls) - case sys.LenType: + p.removeArg(c, arg.Option) + opt, calls := r.generateArg(s, optType) + arg1 := unionArg(a, opt, optType) + p.replaceArg(c, arg, arg1, calls) + case *sys.LenType: panic("bad arg returned by mutationArgs: LenType") - case sys.ConstType, sys.StrConstType: + case *sys.ConstType: panic("bad arg returned by mutationArgs: ConstType") default: panic(fmt.Sprintf("bad arg returned by mutationArgs: %#v, type=%#v", *arg, arg.Type)) } // Update base pointer if size has increased. - if base != nil && baseSize < base.Res.Size(base.Res.Type) { - arg1, calls1 := r.addr(s, base.Res.Size(base.Res.Type), base.Res) + if base != nil && baseSize < base.Res.Size() { + arg1, calls1 := r.addr(s, base.Type, base.Res.Size(), base.Res) for _, c1 := range calls1 { - assignTypeAndDir(c1) sanitizeCall(c1) } p.insertBefore(c, calls1) @@ -194,8 +184,6 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { // Update all len fields. assignSizesCall(c) - // Assign Arg.Type fields for newly created len args. - assignTypeAndDir(c) } }, 1, func() { @@ -210,7 +198,6 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { ) } for _, c := range p.Calls { - assignTypeAndDir(c) sanitizeCall(c) } if err := p.validate(); err != nil { @@ -254,18 +241,7 @@ func Minimize(p0 *Prog, callIndex0 int, pred func(*Prog, int) bool) (*Prog, int) } } // Prepend uber-mmap. - mmap := &Call{ - Meta: sys.CallMap["mmap"], - Args: []*Arg{ - pointerArg(0, 0, uintptr(hi)+1, nil), - pageSizeArg(uintptr(hi)+1, 0), - constArg(sys.PROT_READ | sys.PROT_WRITE), - constArg(sys.MAP_ANONYMOUS | sys.MAP_PRIVATE | sys.MAP_FIXED), - constArg(sys.InvalidFD), - constArg(0), - }, - } - assignTypeAndDir(mmap) + mmap := createMmapCall(0, uintptr(hi)+1) p.Calls = append([]*Call{mmap}, p.Calls...) if callIndex != -1 { callIndex++ @@ -332,19 +308,23 @@ func mutationArgs(c *Call) (args, bases []*Arg) { return } // These special structs are mutated as a whole. - case sys.ArrayType: + case *sys.ArrayType: // Don't mutate fixed-size arrays. if typ.Kind == sys.ArrayRangeLen && typ.RangeBegin == typ.RangeEnd { return } - case sys.LenType: + case *sys.LenType: // Size is updated when the size-of arg change. return - case sys.ConstType, sys.StrConstType: + case *sys.ConstType: // Well, this is const. return + case *sys.BufferType: + if typ.Kind == sys.BufferString && len(typ.Values) == 1 { + return // string const + } } - if arg.Dir == DirOut { + if arg.Type.Dir() == sys.DirOut { return } if base != nil { diff --git a/prog/prio.go b/prog/prio.go index 8983c1c92..59a205a5d 100644 --- a/prog/prio.go +++ b/prog/prio.go @@ -50,9 +50,9 @@ func calcStaticPriorities() [][]float32 { uses[id][c.ID] = weight } } - foreachArgType(c, func(t sys.Type, d ArgDir) { + sys.ForeachType(c, func(t sys.Type) { switch a := t.(type) { - case sys.ResourceType: + case *sys.ResourceType: if a.Desc.Name == "pid" || a.Desc.Name == "uid" || a.Desc.Name == "gid" { // Pid/uid/gid usually play auxiliary role, // but massively happen in some structs. @@ -68,34 +68,35 @@ func calcStaticPriorities() [][]float32 { noteUsage(float32(w), str) } } - case sys.PtrType: + case *sys.PtrType: if _, ok := a.Type.(*sys.StructType); ok { noteUsage(1.0, "ptrto-%v", a.Type.Name()) } if _, ok := a.Type.(*sys.UnionType); ok { noteUsage(1.0, "ptrto-%v", a.Type.Name()) } - if arr, ok := a.Type.(sys.ArrayType); ok { + if arr, ok := a.Type.(*sys.ArrayType); ok { noteUsage(1.0, "ptrto-%v", arr.Type.Name()) } - case sys.BufferType: + case *sys.BufferType: switch a.Kind { - case sys.BufferBlobRand, sys.BufferBlobRange, sys.BufferFilesystem, sys.BufferAlgType, sys.BufferAlgName: + case sys.BufferBlobRand, sys.BufferBlobRange: case sys.BufferString: - noteUsage(0.2, "str") + if a.SubKind != "" { + noteUsage(0.2, fmt.Sprintf("str-%v", a.SubKind)) + } case sys.BufferSockaddr: noteUsage(1.0, "sockaddr") + case sys.BufferFilename: + noteUsage(1.0, "filename") default: panic("unknown buffer kind") } - case sys.VmaType: + case *sys.VmaType: noteUsage(0.5, "vma") - case sys.FilenameType: - noteUsage(1.0, "filename") - case sys.IntType: + case *sys.IntType: switch a.Kind { - case sys.IntPlain: - case sys.IntRange: + case sys.IntPlain, sys.IntFileoff, sys.IntRange: case sys.IntSignalno: noteUsage(1.0, "signalno") case sys.IntInaddr: @@ -196,47 +197,6 @@ func normalizePrio(prios [][]float32) { } } -func foreachArgType(meta *sys.Call, f func(sys.Type, ArgDir)) { - seen := make(map[sys.Type]bool) - var rec func(t sys.Type, dir ArgDir) - rec = func(t sys.Type, d ArgDir) { - f(t, d) - switch a := t.(type) { - case sys.ArrayType: - rec(a.Type, d) - case sys.PtrType: - rec(a.Type, ArgDir(a.Dir)) - case *sys.StructType: - if seen[a] { - return // prune recursion via pointers to structs/unions - } - seen[a] = true - for _, f := range a.Fields { - rec(f, d) - } - case *sys.UnionType: - if seen[a] { - return // prune recursion via pointers to structs/unions - } - seen[a] = true - for _, opt := range a.Options { - rec(opt, d) - } - case sys.ResourceType, sys.FileoffType, sys.BufferType, - sys.VmaType, sys.LenType, sys.FlagsType, sys.ConstType, - sys.StrConstType, sys.IntType, sys.FilenameType: - default: - panic("unknown type") - } - } - for _, t := range meta.Args { - rec(t, DirIn) - } - if meta.Ret != nil { - rec(meta.Ret, DirOut) - } -} - // ChooseTable allows to do a weighted choice of a syscall for a given syscall // based on call-to-call priorities and a set of enabled syscalls. type ChoiceTable struct { diff --git a/prog/prog.go b/prog/prog.go index 9953f3ef0..e3a0febd2 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -20,10 +20,8 @@ type Call struct { } type Arg struct { - Call *Call Type sys.Type Kind ArgKind - Dir ArgDir Val uintptr // value of ArgConst AddrPage uintptr // page index for ArgPointer address, page count for ArgPageSize AddrOffset int // page offset for ArgPointer address @@ -53,26 +51,17 @@ const ( ArgReturn // fake value denoting syscall return value ) -type ArgDir sys.Dir - -const ( - DirIn = ArgDir(sys.DirIn) - DirOut = ArgDir(sys.DirOut) - DirInOut = ArgDir(sys.DirInOut) -) - // Returns inner arg for PtrType args -func (a *Arg) InnerArg(typ sys.Type) *Arg { - switch typ1 := typ.(type) { - case sys.PtrType: +func (a *Arg) InnerArg() *Arg { + switch typ := a.Type.(type) { + case *sys.PtrType: if a.Res == nil { - if typ.Optional() { - return nil - } else { - panic(fmt.Sprintf("non-optional pointer is nil\narg: %+v\ntype: %+v", a, typ1)) + if !typ.Optional() { + panic(fmt.Sprintf("non-optional pointer is nil\narg: %+v\ntype: %+v", a, typ)) } + return nil } else { - return a.Res.InnerArg(typ1.Type) + return a.Res.InnerArg() } default: return a @@ -96,43 +85,39 @@ func encodeValue(value, size uintptr, bigEndian bool) uintptr { } // Returns value taking endianness into consideration. -func (a *Arg) Value(typ sys.Type) uintptr { - switch t := typ.(type) { - case sys.IntType: - return encodeValue(a.Val, t.Size(), t.BigEndian) - case sys.ConstType: - return encodeValue(a.Val, t.Size(), t.BigEndian) - case sys.FlagsType: - return encodeValue(a.Val, t.Size(), t.BigEndian) - case sys.LenType: - return encodeValue(a.Val, t.Size(), t.BigEndian) - case sys.FileoffType: - return encodeValue(a.Val, t.Size(), t.BigEndian) +func (a *Arg) Value() uintptr { + switch typ := a.Type.(type) { + case *sys.IntType: + return encodeValue(a.Val, typ.Size(), typ.BigEndian) + case *sys.ConstType: + return encodeValue(a.Val, typ.Size(), typ.BigEndian) + case *sys.FlagsType: + return encodeValue(a.Val, typ.Size(), typ.BigEndian) + case *sys.LenType: + return encodeValue(a.Val, typ.Size(), typ.BigEndian) } return a.Val } -func (a *Arg) Size(typ sys.Type) uintptr { - switch typ1 := typ.(type) { - case sys.IntType, sys.LenType, sys.FlagsType, sys.ConstType, sys.StrConstType, - sys.FileoffType, sys.ResourceType, sys.VmaType, sys.PtrType: +func (a *Arg) Size() uintptr { + switch typ := a.Type.(type) { + case *sys.IntType, *sys.LenType, *sys.FlagsType, *sys.ConstType, + *sys.ResourceType, *sys.VmaType, *sys.PtrType: return typ.Size() - case sys.FilenameType: - return uintptr(len(a.Data)) - case sys.BufferType: + case *sys.BufferType: return uintptr(len(a.Data)) case *sys.StructType: var size uintptr - for i, f := range typ1.Fields { - size += a.Inner[i].Size(f) + for _, fld := range a.Inner { + size += fld.Size() } return size case *sys.UnionType: - return a.Option.Size(a.OptionType) - case sys.ArrayType: + return a.Option.Size() + case *sys.ArrayType: var size uintptr for _, in := range a.Inner { - size += in.Size(typ1.Type) + size += in.Size() } return size default: @@ -140,12 +125,12 @@ func (a *Arg) Size(typ sys.Type) uintptr { } } -func constArg(v uintptr) *Arg { - return &Arg{Kind: ArgConst, Val: v} +func constArg(t sys.Type, v uintptr) *Arg { + return &Arg{Type: t, Kind: ArgConst, Val: v} } -func resultArg(r *Arg) *Arg { - arg := &Arg{Kind: ArgResult, Res: r} +func resultArg(t sys.Type, r *Arg) *Arg { + arg := &Arg{Type: t, Kind: ArgResult, Res: r} if r.Uses == nil { r.Uses = make(map[*Arg]bool) } @@ -156,28 +141,28 @@ func resultArg(r *Arg) *Arg { return arg } -func dataArg(data []byte) *Arg { - return &Arg{Kind: ArgData, Data: append([]byte{}, data...)} +func dataArg(t sys.Type, data []byte) *Arg { + return &Arg{Type: t, Kind: ArgData, Data: append([]byte{}, data...)} } -func pointerArg(page uintptr, off int, npages uintptr, obj *Arg) *Arg { - return &Arg{Kind: ArgPointer, AddrPage: page, AddrOffset: off, AddrPagesNum: npages, Res: obj} +func pointerArg(t sys.Type, page uintptr, off int, npages uintptr, obj *Arg) *Arg { + return &Arg{Type: t, Kind: ArgPointer, AddrPage: page, AddrOffset: off, AddrPagesNum: npages, Res: obj} } -func pageSizeArg(npages uintptr, off int) *Arg { - return &Arg{Kind: ArgPageSize, AddrPage: npages, AddrOffset: off} +func pageSizeArg(t sys.Type, npages uintptr, off int) *Arg { + return &Arg{Type: t, Kind: ArgPageSize, AddrPage: npages, AddrOffset: off} } -func groupArg(inner []*Arg) *Arg { - return &Arg{Kind: ArgGroup, Inner: inner} +func groupArg(t sys.Type, inner []*Arg) *Arg { + return &Arg{Type: t, Kind: ArgGroup, Inner: inner} } -func unionArg(opt *Arg, typ sys.Type) *Arg { - return &Arg{Kind: ArgUnion, Option: opt, OptionType: typ} +func unionArg(t sys.Type, opt *Arg, typ sys.Type) *Arg { + return &Arg{Type: t, Kind: ArgUnion, Option: opt, OptionType: typ} } -func returnArg() *Arg { - return &Arg{Kind: ArgReturn, Dir: DirOut} +func returnArg(t sys.Type) *Arg { + return &Arg{Type: t, Kind: ArgReturn} } func (p *Prog) insertBefore(c *Call, calls []*Call) { @@ -197,8 +182,8 @@ func (p *Prog) insertBefore(c *Call, calls []*Call) { p.Calls = newCalls } -// replaceArg replaces arg with arg1 in p, and inserts calls before arg call. -func (p *Prog) replaceArg(arg, arg1 *Arg, calls []*Call) { +// replaceArg replaces arg with arg1 in call c in program p, and inserts calls before arg call. +func (p *Prog) replaceArg(c *Call, arg, arg1 *Arg, calls []*Call) { if arg.Kind != ArgConst && arg.Kind != ArgResult && arg.Kind != ArgPointer && arg.Kind != ArgUnion { panic(fmt.Sprintf("replaceArg: bad arg kind %v", arg.Kind)) } @@ -209,10 +194,8 @@ func (p *Prog) replaceArg(arg, arg1 *Arg, calls []*Call) { delete(arg.Res.Uses, arg) } for _, c := range calls { - assignTypeAndDir(c) sanitizeCall(c) } - c := arg.Call p.insertBefore(c, calls) // Somewhat hacky, but safe and preserves references to arg. uses := arg.Uses @@ -222,12 +205,11 @@ func (p *Prog) replaceArg(arg, arg1 *Arg, calls []*Call) { delete(arg.Res.Uses, arg1) arg.Res.Uses[arg] = true } - assignTypeAndDir(c) sanitizeCall(c) } -// removeArg removes all references to/from arg0 from p. -func (p *Prog) removeArg(arg0 *Arg) { +// removeArg removes all references to/from arg0 of call c from p. +func (p *Prog) removeArg(c *Call, arg0 *Arg) { foreachSubarg(arg0, func(arg, _ *Arg, _ *[]*Arg) { if arg.Kind == ArgResult { if _, ok := arg.Res.Uses[arg]; !ok { @@ -239,8 +221,8 @@ func (p *Prog) removeArg(arg0 *Arg) { if arg1.Kind != ArgResult { panic("use references not ArgResult") } - arg2 := constArg(arg1.Type.Default()) - p.replaceArg(arg1, arg2, nil) + arg2 := constArg(arg1.Type, arg1.Type.Default()) + p.replaceArg(c, arg1, arg2, nil) } }) } @@ -251,7 +233,7 @@ func (p *Prog) removeCall(idx int) { copy(p.Calls[idx:], p.Calls[idx+1:]) p.Calls = p.Calls[:len(p.Calls)-1] for _, arg := range c.Args { - p.removeArg(arg) + p.removeArg(c, arg) } - p.removeArg(c.Ret) + p.removeArg(c, c.Ret) } diff --git a/prog/rand.go b/prog/rand.go index 18dceeaea..eb24dcc4d 100644 --- a/prog/rand.go +++ b/prog/rand.go @@ -193,25 +193,25 @@ func (r *randGen) inport(s *state) uint16 { return uint16(r.Intn(20))<<8 + 0xab } -func (r *randGen) in6addr(s *state) (arg *Arg, calls []*Call) { +func (r *randGen) in6addr(s *state, typ sys.Type) (arg *Arg, calls []*Call) { // addr: loopback (big endian) - return groupArg([]*Arg{ - constArg(0), - constArg(0), - constArg(0), - constArg(1 << 24), + return groupArg(typ, []*Arg{ + constArg(nil, 0), + constArg(nil, 0), + constArg(nil, 0), + constArg(nil, 1<<24), }), nil } -func (r *randGen) inaddrany(s *state) (arg *Arg, calls []*Call) { +func (r *randGen) inaddrany(s *state, typ sys.Type) (arg *Arg, calls []*Call) { if r.bin() { - return r.in6addr(s) + return r.in6addr(s, typ) } else { - return groupArg([]*Arg{ - constArg(uintptr(r.inaddr(s))), - constArg(0), - constArg(0), - constArg(0), + return groupArg(typ, []*Arg{ + constArg(nil, uintptr(r.inaddr(s))), + constArg(nil, 0), + constArg(nil, 0), + constArg(nil, 0), }), nil } } @@ -258,7 +258,20 @@ func (r *randGen) sockaddr(s *state) []byte { return data } -func (r *randGen) randString(s *state) []byte { +func (r *randGen) randString(s *state, vals []string, dir sys.Dir) []byte { + data := r.randStringImpl(s, vals) + if dir == sys.DirOut { + for i := range data { + data[i] = 0 + } + } + return data +} + +func (r *randGen) randStringImpl(s *state, vals []string) []byte { + if len(vals) != 0 { + return []byte(vals[r.Intn(len(vals))]) + } if len(s.strings) != 0 && r.bin() { // Return an existing string. strings := make([]string, 0, len(s.strings)) @@ -288,81 +301,43 @@ func (r *randGen) randString(s *state) []byte { return buf.Bytes() } -func (r *randGen) filesystem(s *state) []byte { - dict := []string{"sysfs", "rootfs", "ramfs", "tmpfs", "devtmpfs", "debugfs", - "securityfs", "sockfs", "pipefs", "anon_inodefs", "devpts", "ext3", "ext2", "ext4", - "hugetlbfs", "vfat", "ecryptfs", "kdbusfs", "fuseblk", "fuse", "rpc_pipefs", - "nfs", "nfs4", "nfsd", "binfmt_misc", "autofs", "xfs", "jfs", "msdos", "ntfs", - "minix", "hfs", "hfsplus", "qnx4", "ufs", "btrfs", "configfs", "ncpfs", "qnx6", - "exofs", "befs", "vxfs", "gfs2", "gfs2meta", "fusectl", "bfs", "nsfs", "efs", - "cifs", "efivarfs", "affs", "tracefs", "bdev", "ocfs2", "ocfs2_dlmfs", "hpfs", - "proc", "afs", "reiserfs", "jffs2", "romfs", "aio", "sysv", "v7", "udf", - "ceph", "pstore", "adfs", "9p", "hostfs", "squashfs", "cramfs", "iso9660", - "coda", "nilfs2", "logfs", "overlay", "f2fs", "omfs", "ubifs", "openpromfs"} - return []byte(dict[r.Intn(len(dict))] + "\x00") -} - -func (r *randGen) algType(s *state) []byte { - dict := []string{"aead", "hash", "rng", "skcipher"} - res := make([]byte, 14) - copy(res, dict[r.Intn(len(dict))]) - return res -} - -func (r *randGen) algName(s *state) []byte { - dict := []string{"cmac(aes)", "ecb(aes)", "cbc(aes)", "hmac(sha1)", "pcbc(fcrypt)", "ghash", - "jitterentropy_rng", "stdrng", "stdrng", "stdrng", "stdrng", "hmac(sha256)", "stdrng", - "stdrng", "stdrng", "stdrng", "stdrng", "842", "lz4hc", "lz4", "lzo", "crct10dif", "crc32", - "crc32c", "michael_mic", "zlib", "deflate", "poly1305", "chacha20", "salsa20", "seed", - "anubis", "khazad", "xeta", "xtea", "tea", "ecb(arc4)", "arc4", "cast6", "cast5", "camellia", - "aes", "tnepres", "serpent", "twofish", "blowfish", "fcrypt", "des3_ede", "des", "tgr128", - "tgr160", "tgr192", "wp256", "wp384", "wp512", "sha384", "sha512", "sha224", "sha256", - "sha1", "rmd320", "rmd256", "rmd160", "rmd128", "md5", "md4", "digest_null", "compress_null", - "ecb(cipher_null)", "cipher_null", "rsa", "poly1305", "xts(serpent)", "lrw(serpent)", - "ctr(serpent)", "cbc(serpent)", "__ecb-serpent-sse2", "ecb(serpent)", "__xts-serpent-sse2", - "__lrw-serpent-sse2", "__ctr-serpent-sse2", "__cbc-serpent-sse2", "__ecb-serpent-sse2", - "salsa20", "xts(twofish)", "lrw(twofish)", "ctr(twofish)", "cbc(twofish)", "ecb(twofish)", - "twofish", "ctr(blowfish)", "cbc(blowfish)", "ecb(blowfish)", "blowfish", "xts(camellia)", - "lrw(camellia)", "ctr(camellia)", "cbc(camellia)", "ecb(camellia)", "camellia", "ctr(des3_ede)", - "cbc(des3_ede)", "ecb(des3_ede)", "des3_ede", "aes"} - res := make([]byte, 64) - copy(res, dict[r.Intn(len(dict))]) - return res -} - func isSpecialStruct(typ sys.Type) func(r *randGen, s *state) (*Arg, []*Call) { - if _, ok := typ.(*sys.StructType); !ok { + a, ok := typ.(*sys.StructType) + if !ok { panic("must be a struct") } switch typ.Name() { case "timespec": return func(r *randGen, s *state) (*Arg, []*Call) { - return r.timespec(s, false) + return r.timespec(s, a, false) } case "timeval": return func(r *randGen, s *state) (*Arg, []*Call) { - return r.timespec(s, true) + return r.timespec(s, a, true) } case "in6_addr": return func(r *randGen, s *state) (*Arg, []*Call) { - return r.in6addr(s) + return r.in6addr(s, a) } case "in_addr_any": return func(r *randGen, s *state) (*Arg, []*Call) { - return r.inaddrany(s) + return r.inaddrany(s, a) } } return nil } -func (r *randGen) timespec(s *state, usec bool) (arg *Arg, calls []*Call) { +func (r *randGen) timespec(s *state, typ *sys.StructType, usec bool) (arg *Arg, calls []*Call) { // We need to generate timespec/timeval that are either (1) definitely in the past, // or (2) definitely in unreachable fututre, or (3) few ms ahead of now. // Note timespec/timeval can be absolute or relative to now. r.choose( 1, func() { // now for relative, past for absolute - arg = groupArg([]*Arg{constArg(0), constArg(0)}) + arg = groupArg(typ, []*Arg{ + constArg(typ.Fields[0], 0), + constArg(typ.Fields[1], 0), + }) }, 1, func() { // few ms ahead for relative, past for absolute @@ -370,46 +345,77 @@ func (r *randGen) timespec(s *state, usec bool) (arg *Arg, calls []*Call) { if usec { nsec /= 1e3 } - arg = groupArg([]*Arg{constArg(0), constArg(nsec)}) + arg = groupArg(typ, []*Arg{ + constArg(typ.Fields[0], 0), + constArg(typ.Fields[1], nsec), + }) }, 1, func() { // unreachable fututre for both relative and absolute - arg = groupArg([]*Arg{constArg(2e9), constArg(0)}) + arg = groupArg(typ, []*Arg{ + constArg(typ.Fields[0], 2e9), + constArg(typ.Fields[1], 0), + }) }, 1, func() { // few ms ahead for absolute - tp := groupArg([]*Arg{constArg(0), constArg(0)}) + meta := sys.CallMap["clock_gettime"] + ptrArgType := meta.Args[1].(*sys.PtrType) + argType := ptrArgType.Type.(*sys.StructType) + tp := groupArg(argType, []*Arg{ + constArg(argType.Fields[0], 0), + constArg(argType.Fields[1], 0), + }) var tpaddr *Arg - tpaddr, calls = r.addr(s, 2*ptrSize, tp) + tpaddr, calls = r.addr(s, ptrArgType, 2*ptrSize, tp) gettime := &Call{ - Meta: sys.CallMap["clock_gettime"], + Meta: meta, Args: []*Arg{ - constArg(sys.CLOCK_REALTIME), + constArg(meta.Args[0], sys.CLOCK_REALTIME), tpaddr, }, + Ret: returnArg(meta.Ret), } calls = append(calls, gettime) - sec := resultArg(tp.Inner[0]) - nsec := resultArg(tp.Inner[1]) + sec := resultArg(typ.Fields[0], tp.Inner[0]) + nsec := resultArg(typ.Fields[1], tp.Inner[1]) if usec { nsec.OpDiv = 1e3 nsec.OpAdd = 10 * 1e3 } else { nsec.OpAdd = 10 * 1e6 } - arg = groupArg([]*Arg{sec, nsec}) + arg = groupArg(typ, []*Arg{sec, nsec}) }, ) return } -func (r *randGen) addr1(s *state, size uintptr, data *Arg) (*Arg, []*Call) { +// createMmapCall creates a "normal" mmap call that maps [start, start+npages) page range. +func createMmapCall(start, npages uintptr) *Call { + meta := sys.CallMap["mmap"] + mmap := &Call{ + Meta: meta, + Args: []*Arg{ + pointerArg(meta.Args[0], start, 0, npages, nil), + pageSizeArg(meta.Args[1], npages, 0), + constArg(meta.Args[2], sys.PROT_READ|sys.PROT_WRITE), + constArg(meta.Args[3], sys.MAP_ANONYMOUS|sys.MAP_PRIVATE|sys.MAP_FIXED), + constArg(meta.Args[4], sys.InvalidFD), + constArg(meta.Args[5], 0), + }, + Ret: returnArg(meta.Ret), + } + return mmap +} + +func (r *randGen) addr1(s *state, typ sys.Type, size uintptr, data *Arg) (*Arg, []*Call) { npages := (size + pageSize - 1) / pageSize if npages == 0 { npages = 1 } if r.oneOf(10) { - return r.randPageAddr(s, npages, data, false), nil + return r.randPageAddr(s, typ, npages, data, false), nil } for i := uintptr(0); i < maxPages-npages; i++ { free := true @@ -422,24 +428,14 @@ func (r *randGen) addr1(s *state, size uintptr, data *Arg) (*Arg, []*Call) { if !free { continue } - c := &Call{ - Meta: sys.CallMap["mmap"], - Args: []*Arg{ - pointerArg(i, 0, npages, nil), - pageSizeArg(npages, 0), - constArg(sys.PROT_READ | sys.PROT_WRITE), - constArg(sys.MAP_ANONYMOUS | sys.MAP_PRIVATE | sys.MAP_FIXED), - constArg(sys.InvalidFD), - constArg(0), - }, - } - return pointerArg(i, 0, 0, data), []*Call{c} + c := createMmapCall(i, npages) + return pointerArg(typ, i, 0, 0, data), []*Call{c} } - return r.randPageAddr(s, npages, data, false), nil + return r.randPageAddr(s, typ, npages, data, false), nil } -func (r *randGen) addr(s *state, size uintptr, data *Arg) (*Arg, []*Call) { - arg, calls := r.addr1(s, size, data) +func (r *randGen) addr(s *state, typ sys.Type, size uintptr, data *Arg) (*Arg, []*Call) { + arg, calls := r.addr1(s, typ, size, data) if arg.Kind != ArgPointer { panic("bad") } @@ -457,7 +453,7 @@ func (r *randGen) addr(s *state, size uintptr, data *Arg) (*Arg, []*Call) { return arg, calls } -func (r *randGen) randPageAddr(s *state, npages uintptr, data *Arg, vma bool) *Arg { +func (r *randGen) randPageAddr(s *state, typ sys.Type, npages uintptr, data *Arg, vma bool) *Arg { var starts []uintptr for i := uintptr(0); i < maxPages-npages; i++ { busy := true @@ -483,13 +479,13 @@ func (r *randGen) randPageAddr(s *state, npages uintptr, data *Arg, vma bool) *A if !vma { npages = 0 } - return pointerArg(page, 0, npages, data) + return pointerArg(typ, page, 0, npages, data) } -func (r *randGen) createResource(s *state, res sys.ResourceType) (arg *Arg, calls []*Call) { +func (r *randGen) createResource(s *state, res *sys.ResourceType) (arg *Arg, calls []*Call) { if r.inCreateResource { special := res.SpecialValues() - return constArg(special[r.Intn(len(special))]), nil + return constArg(res, special[r.Intn(len(special))]), nil } r.inCreateResource = true defer func() { r.inCreateResource = false }() @@ -516,7 +512,7 @@ func (r *randGen) createResource(s *state, res sys.ResourceType) (arg *Arg, call metas = append(metas, meta) } if len(metas) == 0 { - return constArg(res.Default()), nil + return constArg(res, res.Default()), nil } // Now we have a set of candidate calls that can create the necessary resource. @@ -535,7 +531,7 @@ func (r *randGen) createResource(s *state, res sys.ResourceType) (arg *Arg, call } if len(allres) != 0 { // Bingo! - arg := resultArg(allres[r.Intn(len(allres))]) + arg := resultArg(res, allres[r.Intn(len(allres))]) return arg, calls } switch meta.Name { @@ -599,23 +595,25 @@ func (r *randGen) generateCall(s *state, p *Prog) []*Call { } func (r *randGen) generateParticularCall(s *state, meta *sys.Call) (calls []*Call) { - c := &Call{Meta: meta} - c.Args, calls = r.generateArgs(s, meta.Args, DirIn) + c := &Call{ + Meta: meta, + Ret: returnArg(meta.Ret), + } + c.Args, calls = r.generateArgs(s, meta.Args) calls = append(calls, c) for _, c1 := range calls { - assignTypeAndDir(c1) sanitizeCall(c1) } return calls } -func (r *randGen) generateArgs(s *state, types []sys.Type, dir ArgDir) ([]*Arg, []*Call) { +func (r *randGen) generateArgs(s *state, types []sys.Type) ([]*Arg, []*Call) { var calls []*Call args := make([]*Arg, len(types)) // Generate all args. Size args have the default value 0 for now. for i, typ := range types { - arg, calls1 := r.generateArg(s, typ, dir) + arg, calls1 := r.generateArg(s, typ) if arg == nil { panic(fmt.Sprintf("generated arg is nil for type '%v', types: %+v", typ.Name(), types)) } @@ -623,36 +621,37 @@ func (r *randGen) generateArgs(s *state, types []sys.Type, dir ArgDir) ([]*Arg, calls = append(calls, calls1...) } - assignSizes(types, args) + assignSizes(args) return args, calls } -func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, calls []*Call) { - if dir == DirOut { +func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) { + if typ.Dir() == sys.DirOut { // No need to generate something interesting for output scalar arguments. // But we still need to generate the argument itself so that it can be referenced // in subsequent calls. For the same reason we do generate pointer/array/struct // output arguments (their elements can be referenced in subsequent calls). switch typ.(type) { - case sys.IntType, sys.FlagsType, sys.ConstType, sys.StrConstType, sys.FileoffType, sys.ResourceType: - return constArg(0), nil + case *sys.IntType, *sys.FlagsType, *sys.ConstType, + *sys.ResourceType, *sys.VmaType: + return constArg(typ, 0), nil } } if typ.Optional() && r.oneOf(5) { - if _, ok := typ.(sys.BufferType); ok { + if _, ok := typ.(*sys.BufferType); ok { panic("impossible") // parent PtrType must be Optional instead } - return constArg(typ.Default()), nil + return constArg(typ, typ.Default()), nil } switch a := typ.(type) { - case sys.ResourceType: + case *sys.ResourceType: r.choose( 1, func() { special := a.SpecialValues() - arg = constArg(special[r.Intn(len(special))]) + arg = constArg(a, special[r.Intn(len(special))]) }, 90, func() { // Get an existing resource. @@ -664,7 +663,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal } } if len(allres) != 0 { - arg = resultArg(allres[r.Intn(len(allres))]) + arg = resultArg(a, allres[r.Intn(len(allres))]) } else { arg, calls = r.createResource(s, a) } @@ -675,16 +674,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal }, ) return arg, calls - case sys.FileoffType: - // TODO: can do better - var arg *Arg - r.choose( - 90, func() { arg = constArg(0) }, - 10, func() { arg = constArg(r.rand(100)) }, - 1, func() { arg = constArg(r.randInt()) }, - ) - return arg, nil - case sys.BufferType: + case *sys.BufferType: switch a.Kind { case sys.BufferBlobRand, sys.BufferBlobRange: sz := r.randBufLen() @@ -692,56 +682,38 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal sz = r.randRange(int(a.RangeBegin), int(a.RangeEnd)) } data := make([]byte, sz) - if dir != DirOut { + if a.Dir() != sys.DirOut { for i := range data { data[i] = byte(r.Intn(256)) } } - return dataArg(data), nil + return dataArg(a, data), nil case sys.BufferString: - data := r.randString(s) - return dataArg(data), nil - case sys.BufferFilesystem: - data := r.filesystem(s) - return dataArg(data), nil + data := r.randString(s, a.Values, a.Dir()) + return dataArg(a, data), nil + case sys.BufferFilename: + filename := r.filename(s) + return dataArg(a, []byte(filename)), nil case sys.BufferSockaddr: data := r.sockaddr(s) - if dir == DirOut { - for i := range data { - data[i] = 0 - } - } - return dataArg(data), nil - case sys.BufferAlgType: - data := r.algType(s) - if dir == DirOut { - for i := range data { - data[i] = 0 - } - } - return dataArg(data), nil - case sys.BufferAlgName: - data := r.algName(s) - if dir == DirOut { + if a.Dir() == sys.DirOut { for i := range data { data[i] = 0 } } - return dataArg(data), nil + return dataArg(a, data), nil default: panic("unknown buffer kind") } - case sys.VmaType: + case *sys.VmaType: npages := r.randPageCount() - arg := r.randPageAddr(s, npages, nil, true) + arg := r.randPageAddr(s, a, npages, nil, true) return arg, nil - case sys.FlagsType: - return constArg(r.flags(a.Vals)), nil - case sys.ConstType: - return constArg(a.Val), nil - case sys.StrConstType: - return dataArg([]byte(a.Val)), nil - case sys.IntType: + case *sys.FlagsType: + return constArg(a, r.flags(a.Vals)), nil + case *sys.ConstType: + return constArg(a, a.Val), nil + case *sys.IntType: v := r.randInt() switch a.Kind { case sys.IntSignalno: @@ -750,14 +722,17 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal v = uintptr(r.inaddr(s)) case sys.IntInport: v = uintptr(r.inport(s)) + case sys.IntFileoff: + r.choose( + 90, func() { v = 0 }, + 10, func() { v = r.rand(100) }, + 1, func() { v = r.randInt() }, + ) case sys.IntRange: v = r.randRangeInt(a.RangeBegin, a.RangeEnd) } - return constArg(v), nil - case sys.FilenameType: - filename := r.filename(s) - return dataArg([]byte(filename)), nil - case sys.ArrayType: + return constArg(a, v), nil + case *sys.ArrayType: count := uintptr(0) switch a.Kind { case sys.ArrayRandLen: @@ -768,28 +743,28 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal var inner []*Arg var calls []*Call for i := uintptr(0); i < count; i++ { - arg1, calls1 := r.generateArg(s, a.Type, dir) + arg1, calls1 := r.generateArg(s, a.Type) inner = append(inner, arg1) calls = append(calls, calls1...) } - return groupArg(inner), calls + return groupArg(a, inner), calls case *sys.StructType: - if ctor := isSpecialStruct(a); ctor != nil && dir != DirOut { + if ctor := isSpecialStruct(a); ctor != nil && a.Dir() != sys.DirOut { arg, calls = ctor(r, s) return } - args, calls := r.generateArgs(s, a.Fields, dir) - group := groupArg(args) + args, calls := r.generateArgs(s, a.Fields) + group := groupArg(a, args) return group, calls case *sys.UnionType: optType := a.Options[r.Intn(len(a.Options))] - opt, calls := r.generateArg(s, optType, dir) - return unionArg(opt, optType), calls - case sys.PtrType: - inner, calls := r.generateArg(s, a.Type, ArgDir(a.Dir)) - if ArgDir(a.Dir) == DirOut && inner == nil { + opt, calls := r.generateArg(s, optType) + return unionArg(a, opt, optType), calls + case *sys.PtrType: + inner, calls := r.generateArg(s, a.Type) + if a.Dir() == sys.DirOut && inner == nil { // No data, but we should have got size. - arg, calls1 := r.addr(s, inner.Size(a.Type), nil) + arg, calls1 := r.addr(s, a, inner.Size(), nil) calls = append(calls, calls1...) return arg, calls } @@ -798,15 +773,15 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal // So try to reuse a previously used address. addrs := s.resources["iocbptr"] addr := addrs[r.Intn(len(addrs))] - arg = pointerArg(addr.AddrPage, addr.AddrOffset, addr.AddrPagesNum, inner) + arg = pointerArg(a, addr.AddrPage, addr.AddrOffset, addr.AddrPagesNum, inner) return arg, calls } - arg, calls1 := r.addr(s, inner.Size(a.Type), inner) + arg, calls1 := r.addr(s, a, inner.Size(), inner) calls = append(calls, calls1...) return arg, calls - case sys.LenType: + case *sys.LenType: // Return placeholder value of 0 while generating len args. - return constArg(0), nil + return constArg(a, 0), nil default: panic("unknown argument type") } diff --git a/prog/size_test.go b/prog/size_test.go index 41068e713..ad1ba8740 100644 --- a/prog/size_test.go +++ b/prog/size_test.go @@ -16,7 +16,6 @@ func TestAssignSizeRandom(t *testing.T) { data0 := p.Serialize() for _, call := range p.Calls { assignSizesCall(call) - assignTypeAndDir(call) } if data1 := p.Serialize(); !bytes.Equal(data0, data1) { t.Fatalf("different lens assigned, initial: %v, new: %v", data0, data1) @@ -26,7 +25,6 @@ func TestAssignSizeRandom(t *testing.T) { data0 := p.Serialize() for _, call := range p.Calls { assignSizesCall(call) - assignTypeAndDir(call) } if data1 := p.Serialize(); !bytes.Equal(data0, data1) { t.Fatalf("different lens assigned, initial: %v, new: %v", data0, data1) @@ -113,7 +111,6 @@ func TestAssignSize(t *testing.T) { } for _, call := range p.Calls { assignSizesCall(call) - assignTypeAndDir(call) } p1 := strings.TrimSpace(string(p.Serialize())) if p1 != test.sizedProg { diff --git a/prog/validation.go b/prog/validation.go index a1b68ba1b..701d0ce3d 100644 --- a/prog/validation.go +++ b/prog/validation.go @@ -41,9 +41,6 @@ func (c *Call) validate(ctx *validCtx) error { if arg == nil { return fmt.Errorf("syscall %v: nil arg", c.Meta.Name) } - if arg.Call != c { - return fmt.Errorf("syscall %v: arg has wrong call, call=%p, arg=%+v", c.Meta.Name, c, *arg) - } if ctx.args[arg] { return fmt.Errorf("syscall %v: arg is referenced several times in the tree", c.Meta.Name) } @@ -55,9 +52,9 @@ func (c *Call) validate(ctx *validCtx) error { return fmt.Errorf("syscall %v: no type", c.Meta.Name) } if arg.Type.Name() != typ.Name() { - return fmt.Errorf("syscall %v: arg '%v' type mismatch", c.Meta.Name, typ.Name()) + return fmt.Errorf("syscall %v: type name mismatch: %v vs %v", c.Meta.Name, arg.Type.Name(), typ.Name()) } - if arg.Dir == DirOut { + if arg.Type.Dir() == sys.DirOut { if arg.Val != 0 || arg.AddrPage != 0 || arg.AddrOffset != 0 { return fmt.Errorf("syscall %v: output arg '%v' has data", c.Meta.Name, typ.Name()) } @@ -68,23 +65,17 @@ func (c *Call) validate(ctx *validCtx) error { } } switch arg.Type.(type) { - case sys.ResourceType: + case *sys.ResourceType: switch arg.Kind { case ArgResult: case ArgReturn: case ArgConst: - if arg.Dir == DirOut && arg.Val != 0 { + if arg.Type.Dir() == sys.DirOut && arg.Val != 0 { return fmt.Errorf("syscall %v: out resource arg '%v' has bad const value %v", c.Meta.Name, typ.Name(), arg.Val) } default: return fmt.Errorf("syscall %v: fd arg '%v' has bad kind %v", c.Meta.Name, typ.Name(), arg.Kind) } - case sys.FilenameType: - switch arg.Kind { - case ArgData: - default: - return fmt.Errorf("syscall %v: filename arg '%v' has bad kind %v", c.Meta.Name, typ.Name(), arg.Kind) - } case *sys.StructType, *sys.ArrayType: switch arg.Kind { case ArgGroup: @@ -105,25 +96,25 @@ func (c *Call) validate(ctx *validCtx) error { return fmt.Errorf("syscall %v: result arg '%v' has no reference", c.Meta.Name, typ.Name()) } if !ctx.args[arg.Res] { - return fmt.Errorf("syscall %v: result arg '%v' references out-of-tree result: %p%+v -> %v %p%+v", - c.Meta.Name, typ.Name(), arg, arg, arg.Res.Call.Meta.Name, arg.Res, arg.Res) + return fmt.Errorf("syscall %v: result arg '%v' references out-of-tree result: %p%+v -> %p%+v", + c.Meta.Name, typ.Name(), arg, arg, arg.Res, arg.Res) } if _, ok := arg.Res.Uses[arg]; !ok { return fmt.Errorf("syscall %v: result arg '%v' has broken link (%+v)", c.Meta.Name, typ.Name(), arg.Res.Uses) } case ArgPointer: - if arg.Dir != DirIn { - return fmt.Errorf("syscall %v: pointer arg '%v' has output direction", c.Meta.Name, typ.Name()) - } switch typ1 := typ.(type) { - case sys.VmaType: + case *sys.VmaType: if arg.Res != nil { return fmt.Errorf("syscall %v: vma arg '%v' has data", c.Meta.Name, typ.Name()) } if arg.AddrPagesNum == 0 { return fmt.Errorf("syscall %v: vma arg '%v' has size 0", c.Meta.Name, typ.Name()) } - case sys.PtrType: + case *sys.PtrType: + if arg.Type.Dir() != sys.DirIn { + return fmt.Errorf("syscall %v: pointer arg '%v' has output direction", c.Meta.Name, typ.Name()) + } if arg.Res == nil && !typ.Optional() { return fmt.Errorf("syscall %v: non optional pointer arg '%v' is nil", c.Meta.Name, typ.Name()) } @@ -151,7 +142,7 @@ func (c *Call) validate(ctx *validCtx) error { return err } } - case sys.ArrayType: + case *sys.ArrayType: for _, arg1 := range arg.Inner { if err := checkArg(arg1, typ1.Type); err != nil { return err @@ -185,7 +176,7 @@ func (c *Call) validate(ctx *validCtx) error { return nil } for i, arg := range c.Args { - if c.Ret.Kind != ArgReturn { + if arg.Kind == ArgReturn { return fmt.Errorf("syscall %v: arg '%v' has wrong return kind", c.Meta.Name, arg.Type.Name()) } if err := checkArg(arg, c.Meta.Args[i]); err != nil { diff --git a/sys/README.md b/sys/README.md index 18b3c76ab..8125a7b7c 100644 --- a/sys/README.md +++ b/sys/README.md @@ -23,7 +23,7 @@ Pseudo-formal grammar of syscall description: type = typename [ "[" type-options "]" ] typename = "const" | "intN" | "intptr" | "flags" | "array" | "ptr" | "buffer" | "string" | "strconst" | "filename" | - "fileoff" | "len" | "bytesize" | "vma" + "len" | "bytesize" | "vma" type-options = [type-opt ["," type-opt]] ``` common type-options include: @@ -44,12 +44,12 @@ rest of the type-options are type-specific: type of the object; direction (in/out/inout) "buffer": a pointer to a memory buffer (like read/write buffer argument), type-options: direction (in/out/inout) - "string": a pointer to a memory buffer, similar to buffer[in] - "strconst": a pointer to a constant string, type-options: - the underlying string (for example "/dev/dsp") + "string": a zero-terminated memory buffer (no pointer indirection implied), type-options: + either a string value in quotes for constant strings (e.g. "foo"), + or a reference to string flags, + optionally followed by a buffer size (string values will be padded with \x00 to that size) "filename": a file/link/dir name - "fileoff": offset within a file, type-options: - argname of the file + "fileoff": offset within a file "len": length of another field (for array it is number of elements), type-options: argname of the object "bytesize": similar to "len", but always denotes the size in bytes, type-options: @@ -62,6 +62,10 @@ Flags are described as: ``` flagname = const ["," const]* ``` +or for string flags as: +``` + flagname = "\"" literal "\"" ["," "\"" literal "\""]* +``` ### Structs diff --git a/sys/align.go b/sys/align.go index 055a433f8..1b1ea66ac 100644 --- a/sys/align.go +++ b/sys/align.go @@ -7,9 +7,9 @@ func initAlign() { var rec func(t Type) rec = func(t Type) { switch t1 := t.(type) { - case PtrType: + case *PtrType: rec(t1.Type) - case ArrayType: + case *ArrayType: rec(t1.Type) case *StructType: if !t1.padded { @@ -49,10 +49,10 @@ func addAlignment(t *StructType) { fields = append(fields, makePad(pad)) } fields = append(fields, f) - if at, ok := f.(ArrayType); ok && (at.Kind == ArrayRandLen || (at.Kind == ArrayRangeLen && at.RangeBegin != at.RangeEnd)) { + if at, ok := f.(*ArrayType); ok && (at.Kind == ArrayRandLen || (at.Kind == ArrayRangeLen && at.RangeBegin != at.RangeEnd)) { varLen = true } - if at, ok := f.(BufferType); ok && (at.Kind == BufferBlobRand || (at.Kind == BufferBlobRange && at.RangeBegin != at.RangeEnd)) { + if at, ok := f.(*BufferType); ok && (at.Kind == BufferBlobRand || (at.Kind == BufferBlobRange && at.RangeBegin != at.RangeEnd)) { varLen = true } if varLen && i != len(t.Fields)-1 { @@ -71,7 +71,7 @@ func addAlignment(t *StructType) { } func makePad(sz uintptr) Type { - return ConstType{ + return &ConstType{ TypeCommon: TypeCommon{TypeName: "pad", IsOptional: false}, TypeSize: sz, Val: 0, diff --git a/sys/bpf.txt b/sys/bpf.txt index 68b4c0ab9..e7338cc53 100644 --- a/sys/bpf.txt +++ b/sys/bpf.txt @@ -52,7 +52,7 @@ bpf_prog { type flags[bpf_prog_type, int32] ninsn len[insns, int32] insns ptr[in, array[bpf_insn]] - license string + license ptr[in, string] loglev int32 logsize len[log, int32] log buffer[out] diff --git a/sys/decl.go b/sys/decl.go index 89773b0dd..84c2f8c08 100644 --- a/sys/decl.go +++ b/sys/decl.go @@ -19,17 +19,25 @@ type Call struct { Ret Type } +type Dir int + +const ( + DirIn Dir = iota + DirOut + DirInOut +) + type Type interface { Name() string + Dir() Dir Optional() bool Default() uintptr Size() uintptr Align() uintptr - InnerType() Type // returns inner type for PtrType } func IsPad(t Type) bool { - if ct, ok := t.(ConstType); ok && ct.IsPad { + if ct, ok := t.(*ConstType); ok && ct.IsPad { return true } return false @@ -37,21 +45,26 @@ func IsPad(t Type) bool { type TypeCommon struct { TypeName string + ArgDir Dir IsOptional bool } -func (t TypeCommon) Name() string { +func (t *TypeCommon) Name() string { return t.TypeName } -func (t TypeCommon) Optional() bool { +func (t *TypeCommon) Optional() bool { return t.IsOptional } -func (t TypeCommon) Default() uintptr { +func (t *TypeCommon) Default() uintptr { return 0 } +func (t TypeCommon) Dir() Dir { + return t.ArgDir +} + const ( InvalidFD = ^uintptr(0) ) @@ -68,55 +81,30 @@ type ResourceType struct { Desc *ResourceDesc } -func (t ResourceType) Default() uintptr { +func (t *ResourceType) Default() uintptr { return t.Desc.Values[0] } -func (t ResourceType) SpecialValues() []uintptr { +func (t *ResourceType) SpecialValues() []uintptr { return t.Desc.Values } -func (t ResourceType) Size() uintptr { +func (t *ResourceType) Size() uintptr { return t.Desc.Type.Size() } -func (t ResourceType) Align() uintptr { +func (t *ResourceType) Align() uintptr { return t.Desc.Type.Align() } -func (t ResourceType) InnerType() Type { - return t -} - -type FileoffType struct { - TypeCommon - TypeSize uintptr - BigEndian bool - File string -} - -func (t FileoffType) Size() uintptr { - return t.TypeSize -} - -func (t FileoffType) Align() uintptr { - return t.Size() -} - -func (t FileoffType) InnerType() Type { - return t -} - type BufferKind int const ( BufferBlobRand BufferKind = iota BufferBlobRange BufferString + BufferFilename BufferSockaddr - BufferFilesystem - BufferAlgType - BufferAlgName ) type BufferType struct { @@ -124,48 +112,48 @@ type BufferType struct { Kind BufferKind RangeBegin uintptr // for BufferBlobRange kind RangeEnd uintptr // for BufferBlobRange kind + SubKind string + Values []string // possible values for BufferString kind } -func (t BufferType) Size() uintptr { +func (t *BufferType) Size() uintptr { switch t.Kind { - case BufferAlgType: - return 14 - case BufferAlgName: - return 64 + case BufferString: + size := 0 + for _, s := range t.Values { + if size != 0 && size != len(s) { + size = 0 + break + } + size = len(s) + } + if size != 0 { + return uintptr(size) + } case BufferBlobRange: if t.RangeBegin == t.RangeEnd { return t.RangeBegin } - fallthrough - default: - panic(fmt.Sprintf("buffer size is not statically known: %v", t.Name())) } + panic(fmt.Sprintf("buffer size is not statically known: %v", t.Name())) } -func (t BufferType) Align() uintptr { +func (t *BufferType) Align() uintptr { return 1 } -func (t BufferType) InnerType() Type { - return t -} - type VmaType struct { TypeCommon } -func (t VmaType) Size() uintptr { +func (t *VmaType) Size() uintptr { return ptrSize } -func (t VmaType) Align() uintptr { +func (t *VmaType) Align() uintptr { return t.Size() } -func (t VmaType) InnerType() Type { - return t -} - type LenType struct { TypeCommon TypeSize uintptr @@ -174,18 +162,14 @@ type LenType struct { Buf string } -func (t LenType) Size() uintptr { +func (t *LenType) Size() uintptr { return t.TypeSize } -func (t LenType) Align() uintptr { +func (t *LenType) Align() uintptr { return t.Size() } -func (t LenType) InnerType() Type { - return t -} - type FlagsType struct { TypeCommon TypeSize uintptr @@ -193,18 +177,14 @@ type FlagsType struct { Vals []uintptr } -func (t FlagsType) Size() uintptr { +func (t *FlagsType) Size() uintptr { return t.TypeSize } -func (t FlagsType) Align() uintptr { +func (t *FlagsType) Align() uintptr { return t.Size() } -func (t FlagsType) InnerType() Type { - return t -} - type ConstType struct { TypeCommon TypeSize uintptr @@ -213,36 +193,14 @@ type ConstType struct { IsPad bool } -func (t ConstType) Size() uintptr { +func (t *ConstType) Size() uintptr { return t.TypeSize } -func (t ConstType) Align() uintptr { +func (t *ConstType) Align() uintptr { return t.Size() } -func (t ConstType) InnerType() Type { - return t -} - -type StrConstType struct { - TypeCommon - TypeSize uintptr - Val string -} - -func (t StrConstType) Size() uintptr { - return uintptr(len(t.Val)) -} - -func (t StrConstType) Align() uintptr { - return 1 -} - -func (t StrConstType) InnerType() Type { - return t -} - type IntKind int const ( @@ -250,6 +208,7 @@ const ( IntSignalno IntInaddr IntInport + IntFileoff // offset within a file IntRange ) @@ -262,34 +221,14 @@ type IntType struct { RangeEnd int64 } -func (t IntType) Size() uintptr { +func (t *IntType) Size() uintptr { return t.TypeSize } -func (t IntType) Align() uintptr { +func (t *IntType) Align() uintptr { return t.Size() } -func (t IntType) InnerType() Type { - return t -} - -type FilenameType struct { - TypeCommon -} - -func (t FilenameType) Size() uintptr { - panic("filename size is not statically known") -} - -func (t FilenameType) Align() uintptr { - return 1 -} - -func (t FilenameType) InnerType() Type { - return t -} - type ArrayKind int const ( @@ -305,39 +244,30 @@ type ArrayType struct { RangeEnd uintptr } -func (t ArrayType) Size() uintptr { +func (t *ArrayType) Size() uintptr { if t.RangeBegin == t.RangeEnd { return t.RangeBegin * t.Type.Size() } return 0 // for trailing embed arrays } -func (t ArrayType) Align() uintptr { +func (t *ArrayType) Align() uintptr { return t.Type.Align() } -func (t ArrayType) InnerType() Type { - return t -} - type PtrType struct { TypeCommon Type Type - Dir Dir } -func (t PtrType) Size() uintptr { +func (t *PtrType) Size() uintptr { return ptrSize } -func (t PtrType) Align() uintptr { +func (t *PtrType) Align() uintptr { return t.Size() } -func (t PtrType) InnerType() Type { - return t.Type.InnerType() -} - type StructType struct { TypeCommon Fields []Type @@ -370,10 +300,6 @@ func (t *StructType) Align() uintptr { return align } -func (t *StructType) InnerType() Type { - return t -} - type UnionType struct { TypeCommon Options []Type @@ -403,18 +329,6 @@ func (t *UnionType) Align() uintptr { return align } -func (t *UnionType) InnerType() Type { - return t -} - -type Dir int - -const ( - DirIn Dir = iota - DirOut - DirInOut -) - var ctors = make(map[string][]*Call) // ResourceConstructors returns a list of calls that can create a resource of the given kind. @@ -431,56 +345,20 @@ func initResources() { func resourceCtors(kind []string, precise bool) []*Call { // Find calls that produce the necessary resources. var metas []*Call - // Recurse into arguments to see if there is an out/inout arg of necessary type. - seen := make(map[Type]bool) - var checkArg func(typ Type, dir Dir) bool - checkArg = func(typ Type, dir Dir) bool { - if resarg, ok := typ.(ResourceType); ok && dir != DirIn && isCompatibleResource(kind, resarg.Desc.Kind, precise) { - return true - } - switch typ1 := typ.(type) { - case ArrayType: - if checkArg(typ1.Type, dir) { - return true - } - case *StructType: - if seen[typ1] { - return false // prune recursion via pointers to structs/unions - } - seen[typ1] = true - for _, fld := range typ1.Fields { - if checkArg(fld, dir) { - return true - } - } - case *UnionType: - if seen[typ1] { - return false // prune recursion via pointers to structs/unions - } - seen[typ1] = true - for _, opt := range typ1.Options { - if checkArg(opt, dir) { - return true - } - } - case PtrType: - if checkArg(typ1.Type, typ1.Dir) { - return true - } - } - return false - } for _, meta := range Calls { + // Recurse into arguments to see if there is an out/inout arg of necessary type. ok := false - for _, arg := range meta.Args { - if checkArg(arg, DirIn) { - ok = true - break + ForeachType(meta, func(typ Type) { + if ok { + return } - } - if !ok && meta.Ret != nil && checkArg(meta.Ret, DirOut) { - ok = true - } + switch typ1 := typ.(type) { + case *ResourceType: + if typ1.Dir() != DirIn && isCompatibleResource(kind, typ1.Desc.Kind, precise) { + ok = true + } + } + }) if ok { metas = append(metas, meta) } @@ -524,41 +402,16 @@ func isCompatibleResource(dst, src []string, precise bool) bool { return true } -func (c *Call) InputResources() []ResourceType { - var resources []ResourceType - seen := make(map[Type]bool) - var checkArg func(typ Type, dir Dir) - checkArg = func(typ Type, dir Dir) { +func (c *Call) InputResources() []*ResourceType { + var resources []*ResourceType + ForeachType(c, func(typ Type) { switch typ1 := typ.(type) { - case ResourceType: - if dir != DirOut && !typ1.IsOptional { + case *ResourceType: + if typ1.Dir() != DirOut && !typ1.IsOptional { resources = append(resources, typ1) } - case ArrayType: - checkArg(typ1.Type, dir) - case PtrType: - checkArg(typ1.Type, typ1.Dir) - case *StructType: - if seen[typ1] { - return // prune recursion via pointers to structs/unions - } - seen[typ1] = true - for _, fld := range typ1.Fields { - checkArg(fld, dir) - } - case *UnionType: - if seen[typ1] { - return // prune recursion via pointers to structs/unions - } - seen[typ1] = true - for _, opt := range typ1.Options { - checkArg(opt, dir) - } } - } - for _, arg := range c.Args { - checkArg(arg, DirIn) - } + }) return resources } @@ -598,6 +451,46 @@ func TransitivelyEnabledCalls(enabled map[*Call]bool) map[*Call]bool { return supported } +func ForeachType(meta *Call, f func(Type)) { + seen := make(map[Type]bool) + var rec func(t Type) + rec = func(t Type) { + f(t) + switch a := t.(type) { + case *PtrType: + rec(a.Type) + case *ArrayType: + rec(a.Type) + case *StructType: + if seen[a] { + return // prune recursion via pointers to structs/unions + } + seen[a] = true + for _, f := range a.Fields { + rec(f) + } + case *UnionType: + if seen[a] { + return // prune recursion via pointers to structs/unions + } + seen[a] = true + for _, opt := range a.Options { + rec(opt) + } + case *ResourceType, *BufferType, *VmaType, *LenType, + *FlagsType, *ConstType, *IntType: + default: + panic("unknown type") + } + } + for _, t := range meta.Args { + rec(t) + } + if meta.Ret != nil { + rec(meta.Ret) + } +} + var ( Calls []*Call CallCount int diff --git a/sys/dri.txt b/sys/dri.txt index 3c5753f23..bc35016e4 100644 --- a/sys/dri.txt +++ b/sys/dri.txt @@ -10,9 +10,9 @@ resource drm_agp_handle[intptr] resource drm_gem_handle[int32] resource drm_gem_name[int32] -syz_open_dev$dri(dev strconst["/dev/dri/card#"], id intptr, flags flags[open_flags]) fd_dri -syz_open_dev$dricontrol(dev strconst["/dev/dri/controlD#"], id intptr, flags flags[open_flags]) fd_dri -syz_open_dev$drirender(dev strconst["/dev/dri/renderD#"], id intptr, flags flags[open_flags]) fd_dri +syz_open_dev$dri(dev ptr[in, string["/dev/dri/card#"]], id intptr, flags flags[open_flags]) fd_dri +syz_open_dev$dricontrol(dev ptr[in, string["/dev/dri/controlD#"]], id intptr, flags flags[open_flags]) fd_dri +syz_open_dev$drirender(dev ptr[in, string["/dev/dri/renderD#"]], id intptr, flags flags[open_flags]) fd_dri ioctl$DRM_IOCTL_VERSION(fd fd_dri, cmd const[DRM_IOCTL_VERSION], arg ptr[in, drm_version]) ioctl$DRM_IOCTL_GET_UNIQUE(fd fd_dri, cmd const[DRM_IOCTL_GET_UNIQUE], arg ptr[in, drm_unique_out]) diff --git a/sys/input.txt b/sys/input.txt index 236d6c89c..4266c2b2b 100644 --- a/sys/input.txt +++ b/sys/input.txt @@ -6,10 +6,10 @@ include <linux/input.h> resource fd_evdev[fd] # There seems to be nothing special we can do with this fd. -syz_open_dev$mouse(dev strconst["/dev/input/mouse#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$mice(dev strconst["/dev/input/mice"], id const[0], flags flags[open_flags]) fd +syz_open_dev$mouse(dev ptr[in, string["/dev/input/mouse#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$mice(dev ptr[in, string["/dev/input/mice"]], id const[0], flags flags[open_flags]) fd -syz_open_dev$evdev(dev strconst["/dev/input/event#"], id intptr, flags flags[open_flags]) fd_evdev +syz_open_dev$evdev(dev ptr[in, string["/dev/input/event#"]], id intptr, flags flags[open_flags]) fd_evdev write$evdev(fd fd_evdev, data ptr[in, array[input_event]], len bytesize[data]) diff --git a/sys/kdbus.txt b/sys/kdbus.txt index 5d40b8625..97bd49e70 100644 --- a/sys/kdbus.txt +++ b/sys/kdbus.txt @@ -6,7 +6,7 @@ include <uapi/linux/fcntl.h> resource fd_kdbus[fd] -openat$kdbus(fd const[AT_FDCWD], file strconst["/dev/kdbus"], flags flags[open_flags], mode const[0]) fd_kdbus +openat$kdbus(fd const[AT_FDCWD], file ptr[in, string["/dev/kdbus"]], flags flags[open_flags], mode const[0]) fd_kdbus ioctl$kdbus_bus_make(fd fd_kdbus, cmd const[KDBUS_CMD_BUS_MAKE], arg ptr[in, kdbus_cmd_bus_make]) ioctl$kdbus_ep_make(fd fd_kdbus, cmd const[KDBUS_CMD_ENDPOINT_MAKE], arg ptr[in, kdbus_cmd_ep_make]) ioctl$kdbus_ep_update(fd fd_kdbus, cmd const[KDBUS_CMD_ENDPOINT_UPDATE], arg ptr[in, kdbus_cmd_ep_update]) diff --git a/sys/key.txt b/sys/key.txt index 6c431682c..c0b18f5e8 100644 --- a/sys/key.txt +++ b/sys/key.txt @@ -6,17 +6,17 @@ include <uapi/linux/keyctl.h> resource key[int32]: KEY_SPEC_THREAD_KEYRING, KEY_SPEC_PROCESS_KEYRING, KEY_SPEC_SESSION_KEYRING, KEY_SPEC_USER_KEYRING, KEY_SPEC_USER_SESSION_KEYRING, KEY_SPEC_GROUP_KEYRING, KEY_SPEC_REQKEY_AUTH_KEY, KEY_SPEC_REQUESTOR_KEYRING -add_key(type string, desc string, payload buffer[in, opt], paylen len[payload], keyring flags[keyring_type]) key -request_key(type string, desc string, callout string, keyring flags[keyring_type]) key +add_key(type ptr[in, string], desc ptr[in, string], payload buffer[in, opt], paylen len[payload], keyring flags[keyring_type]) key +request_key(type ptr[in, string], desc ptr[in, string], callout ptr[in, string], keyring flags[keyring_type]) key keyctl$get_keyring_id(code const[KEYCTL_GET_KEYRING_ID], key key, create intptr) -keyctl$join(code const[KEYCTL_JOIN_SESSION_KEYRING], session string) +keyctl$join(code const[KEYCTL_JOIN_SESSION_KEYRING], session ptr[in, string]) keyctl$update(code const[KEYCTL_UPDATE], key key, payload buffer[in, opt], paylen len[payload]) keyctl$revoke(code const[KEYCTL_REVOKE], key key) keyctl$describe(code const[KEYCTL_DESCRIBE], key key, desc buffer[out], len len[desc]) keyctl$clear(code const[KEYCTL_CLEAR], key key) keyctl$link(code const[KEYCTL_LINK], key1 key, key2 key) keyctl$unlink(code const[KEYCTL_UNLINK], key1 key, key2 key) -keyctl$search(code const[KEYCTL_SEARCH], key key, type string, desc string, ring key) +keyctl$search(code const[KEYCTL_SEARCH], key key, type ptr[in, string], desc ptr[in, string], ring key) keyctl$read(code const[KEYCTL_READ], key key, payload buffer[out], len len[payload]) keyctl$chown(code const[KEYCTL_CHOWN], key key, uid uid, gid gid) # perm is a mask of KEY_POS_VIEW, etc consants, but they cover almost whole int32. diff --git a/sys/kvm.txt b/sys/kvm.txt index b80f4ce72..96e73d74e 100644 --- a/sys/kvm.txt +++ b/sys/kvm.txt @@ -9,7 +9,7 @@ resource fd_kvm[fd] resource fd_kvmvm[fd] resource fd_kvmcpu[fd] -syz_open_dev$kvm(dev strconst["/dev/kvm"], id const[0], flags flags[open_flags]) fd_kvm +syz_open_dev$kvm(dev ptr[in, string["/dev/kvm"]], id const[0], flags flags[open_flags]) fd_kvm ioctl$KVM_CREATE_VM(fd fd_kvm, cmd const[KVM_CREATE_VM], type const[0]) fd_kvmvm ioctl$KVM_GET_MSR_INDEX_LIST(fd fd_kvm, cmd const[KVM_GET_MSR_INDEX_LIST], arg ptr[in, kvm_msr_list]) @@ -99,7 +99,7 @@ ioctl$KVM_SET_GUEST_DEBUG(fd fd_kvmcpu, cmd const[KVM_SET_GUEST_DEBUG], arg ptr[ ioctl$KVM_SMI(fd fd_kvmcpu, cmd const[KVM_SMI]) # TODO: extend support (there are some ioctls) -openat$xenevtchn(fd const[AT_FDCWD], file strconst["/dev/xen/evtchn"], flags flags[open_flags], mode const[0]) fd +openat$xenevtchn(fd const[AT_FDCWD], file ptr[in, string["/dev/xen/evtchn"]], flags flags[open_flags], mode const[0]) fd kvm_mem_region_flags = KVM_MEM_LOG_DIRTY_PAGES, KVM_MEM_READONLY, KVM_MEMSLOT_INVALID, KVM_MEMSLOT_INCOHERENT kvm_mp_state = KVM_MP_STATE_RUNNABLE, KVM_MP_STATE_UNINITIALIZED, KVM_MP_STATE_INIT_RECEIVED, KVM_MP_STATE_HALTED, KVM_MP_STATE_SIPI_RECEIVED, KVM_MP_STATE_STOPPED, KVM_MP_STATE_CHECK_STOP, KVM_MP_STATE_OPERATING, KVM_MP_STATE_LOAD diff --git a/sys/perf.txt b/sys/perf.txt index a860d75c8..e35ad22b9 100644 --- a/sys/perf.txt +++ b/sys/perf.txt @@ -15,7 +15,7 @@ ioctl$PERF_EVENT_IOC_REFRESH(fd fd_perf, cmd const[PERF_EVENT_IOC_REFRESH], refr ioctl$PERF_EVENT_IOC_PERIOD(fd fd_perf, cmd const[PERF_EVENT_IOC_PERIOD], period ptr[in, int64]) ioctl$PERF_EVENT_IOC_ID(fd fd_perf, cmd const[PERF_EVENT_IOC_ID], id ptr[out, int64]) ioctl$PERF_EVENT_IOC_SET_OUTPUT(fd fd_perf, cmd const[PERF_EVENT_IOC_SET_OUTPUT], other fd_perf) -ioctl$PERF_EVENT_IOC_SET_FILTER(fd fd_perf, cmd const[PERF_EVENT_IOC_SET_FILTER], filter string) +ioctl$PERF_EVENT_IOC_SET_FILTER(fd fd_perf, cmd const[PERF_EVENT_IOC_SET_FILTER], filter ptr[in, string]) ioctl$PERF_EVENT_IOC_SET_BPF(fd fd_perf, cmd const[PERF_EVENT_IOC_SET_BPF], prog fd_bpf_prog) perf_flags = PERF_FLAG_FD_NO_GROUP, PERF_FLAG_FD_OUTPUT, PERF_FLAG_PID_CGROUP, PERF_FLAG_FD_CLOEXEC diff --git a/sys/random.txt b/sys/random.txt index 7c8fd11c0..234d1be40 100755 --- a/sys/random.txt +++ b/sys/random.txt @@ -5,8 +5,8 @@ include <linux/random.h> resource fd_random[fd] -syz_open_dev$random(dev strconst["/dev/random"], id const[0], flags flags[open_flags]) fd_random -syz_open_dev$urandom(dev strconst["/dev/urandom"], id const[0], flags flags[open_flags]) fd_random +syz_open_dev$random(dev ptr[in, string["/dev/random"]], id const[0], flags flags[open_flags]) fd_random +syz_open_dev$urandom(dev ptr[in, string["/dev/urandom"]], id const[0], flags flags[open_flags]) fd_random ioctl$RNDGETENTCNT(fd fd_random, cmd const[RNDGETENTCNT], arg ptr[out, int32]) ioctl$RNDADDTOENTCNT(fd fd_random, cmd const[RNDADDTOENTCNT], arg ptr[in, int32]) diff --git a/sys/sndcontrol.txt b/sys/sndcontrol.txt index 20d5cc320..1ec602f03 100644 --- a/sys/sndcontrol.txt +++ b/sys/sndcontrol.txt @@ -5,7 +5,7 @@ include <sound/asound.h> resource fd_sndctrl[fd] -syz_open_dev$sndctrl(dev strconst["/dev/snd/controlC#"], id intptr, flags flags[open_flags]) fd_sndctrl +syz_open_dev$sndctrl(dev ptr[in, string["/dev/snd/controlC#"]], id intptr, flags flags[open_flags]) fd_sndctrl ioctl$SNDRV_CTL_IOCTL_PVERSION(fd fd_sndctrl, cmd const[SNDRV_CTL_IOCTL_PVERSION], arg buffer[out]) ioctl$SNDRV_CTL_IOCTL_CARD_INFO(fd fd_sndctrl, cmd const[SNDRV_CTL_IOCTL_CARD_INFO], arg buffer[out]) @@ -61,7 +61,7 @@ snd_ctl_elem_info { items int32 item int32 name array[int8, 64] - nameptr string + nameptr ptr[in, string] namelen len[nameptr, int32] pad1 array[const[0, int8], 44] d array[int16, 4] diff --git a/sys/sndseq.txt b/sys/sndseq.txt index 62a844ed7..40ad7118d 100644 --- a/sys/sndseq.txt +++ b/sys/sndseq.txt @@ -6,7 +6,7 @@ include <sound/asequencer.h> resource fd_sndseq[fd] -syz_open_dev$sndseq(dev strconst["/dev/snd/seq"], id const[0], flags flags[open_flags]) fd_sndseq +syz_open_dev$sndseq(dev ptr[in, string["/dev/snd/seq"]], id const[0], flags flags[open_flags]) fd_sndseq write$sndseq(fd fd_sndseq, data ptr[in, array[snd_seq_event]], len bytesize[data]) ioctl$SNDRV_SEQ_IOCTL_PVERSION(fd fd_sndseq, cmd const[SNDRV_SEQ_IOCTL_PVERSION], arg ptr[out, int32]) diff --git a/sys/sndtimer.txt b/sys/sndtimer.txt index 67e0a13a8..f7eebc2af 100644 --- a/sys/sndtimer.txt +++ b/sys/sndtimer.txt @@ -5,7 +5,7 @@ include <sound/asound.h> resource fd_sndtimer[fd] -syz_open_dev$sndtimer(dev strconst["/dev/snd/timer"], id const[0], flags flags[open_flags]) fd_sndtimer +syz_open_dev$sndtimer(dev ptr[in, string["/dev/snd/timer"]], id const[0], flags flags[open_flags]) fd_sndtimer ioctl$SNDRV_TIMER_IOCTL_PVERSION(fd fd_sndtimer, cmd const[SNDRV_TIMER_IOCTL_PVERSION], arg ptr[out, int32]) ioctl$SNDRV_TIMER_IOCTL_NEXT_DEVICE(fd fd_sndtimer, cmd const[SNDRV_TIMER_IOCTL_NEXT_DEVICE], arg ptr[in, snd_timer_id]) diff --git a/sys/socket.txt b/sys/socket.txt index b2db95849..74728194f 100644 --- a/sys/socket.txt +++ b/sys/socket.txt @@ -46,7 +46,7 @@ ioctl$SIOCINQ(fd sock, cmd const[SIOCINQ], arg ptr[out, int32]) setsockopt$sock_void(fd sock, level const[SOL_SOCKET], optname flags[sockopt_opt_sock_void], optval const[0], optlen const[0]) getsockopt$sock_int(fd sock, level const[SOL_SOCKET], optname flags[sockopt_opt_sock_int], optval ptr[out, int32], optlen ptr[inout, len[optval, int32]]) setsockopt$sock_int(fd sock, level const[SOL_SOCKET], optname flags[sockopt_opt_sock_int], optval ptr[in, int32], optlen len[optval]) -setsockopt$sock_str(fd sock, level const[SOL_SOCKET], optname const[SO_BINDTODEVICE], optval string, optlen len[optval]) +setsockopt$sock_str(fd sock, level const[SOL_SOCKET], optname const[SO_BINDTODEVICE], optval ptr[in, string], optlen len[optval]) getsockopt$sock_linger(fd sock, level const[SOL_SOCKET], optname const[SO_LINGER], optval ptr[out, linger], optlen ptr[inout, len[optval, int32]]) setsockopt$sock_linger(fd sock, level const[SOL_SOCKET], optname const[SO_LINGER], optval ptr[in, linger], optlen len[optval]) getsockopt$sock_cred(fd sock, level const[SOL_SOCKET], optname const[SO_PEERCRED], optval ptr[out, ucred], optlen ptr[inout, len[optval, int32]]) @@ -273,10 +273,10 @@ sendmmsg$alg(fd sock_algconn, mmsg ptr[in, array[msghdr_alg]], vlen len[mmsg], f sockaddr_alg { family const[AF_ALG, int16] - type salg_type + type string[salg_type, 14] feat flags[af_alg_type, int32] mask flags[af_alg_type, int32] - name salg_name + name string[salg_name, 64] } msghdr_alg { @@ -320,6 +320,9 @@ cmsghdr_alg_assoc { af_alg_type = CRYPTO_ALG_TYPE_MASK, CRYPTO_ALG_TYPE_CIPHER, CRYPTO_ALG_TYPE_COMPRESS, CRYPTO_ALG_TYPE_AEAD, CRYPTO_ALG_TYPE_BLKCIPHER, CRYPTO_ALG_TYPE_ABLKCIPHER, CRYPTO_ALG_TYPE_GIVCIPHER, CRYPTO_ALG_TYPE_DIGEST, CRYPTO_ALG_TYPE_HASH, CRYPTO_ALG_TYPE_SHASH, CRYPTO_ALG_TYPE_AHASH, CRYPTO_ALG_TYPE_RNG, CRYPTO_ALG_TYPE_AKCIPHER, CRYPTO_ALG_TYPE_PCOMPRESS, CRYPTO_ALG_LARVAL, CRYPTO_ALG_DEAD, CRYPTO_ALG_DYING, CRYPTO_ALG_ASYNC, CRYPTO_ALG_NEED_FALLBACK, CRYPTO_ALG_GENIV, CRYPTO_ALG_TESTED, CRYPTO_ALG_INSTANCE, CRYPTO_ALG_KERN_DRIVER_ONLY, CRYPTO_ALG_INTERNAL +salg_type = "aead", "hash", "rng", "skcipher" +salg_name = "cmac(aes)", "ecb(aes)", "cbc(aes)", "hmac(sha1)", "pcbc(fcrypt)", "ghash", "jitterentropy_rng", "stdrng", "stdrng", "stdrng", "stdrng", "hmac(sha256)", "stdrng", "stdrng", "stdrng", "stdrng", "stdrng", "842", "lz4hc", "lz4", "lzo", "crct10dif", "crc32", "crc32c", "michael_mic", "zlib", "deflate", "poly1305", "chacha20", "salsa20", "seed", "anubis", "khazad", "xeta", "xtea", "tea", "ecb(arc4)", "arc4", "cast6", "cast5", "camellia", "aes", "tnepres", "serpent", "twofish", "blowfish", "fcrypt", "des3_ede", "des", "tgr128", "tgr160", "tgr192", "wp256", "wp384", "wp512", "sha384", "sha512", "sha224", "sha256", "sha1", "rmd320", "rmd256", "rmd160", "rmd128", "md5", "md4", "digest_null", "compress_null", "ecb(cipher_null)", "cipher_null", "rsa", "poly1305", "xts(serpent)", "lrw(serpent)", "ctr(serpent)", "cbc(serpent)", "__ecb-serpent-sse2", "ecb(serpent)", "__xts-serpent-sse2", "__lrw-serpent-sse2", "__ctr-serpent-sse2", "__cbc-serpent-sse2", "__ecb-serpent-sse2", "salsa20", "xts(twofish)", "lrw(twofish)", "ctr(twofish)", "cbc(twofish)", "ecb(twofish)", "twofish", "ctr(blowfish)", "cbc(blowfish)", "ecb(blowfish)", "blowfish", "xts(camellia)", "lrw(camellia)", "ctr(camellia)", "cbc(camellia)", "ecb(camellia)", "camellia", "ctr(des3_ede)", "cbc(des3_ede)", "ecb(des3_ede)", "des3_ede", "aes" + diff --git a/sys/sys.txt b/sys/sys.txt index be0d10860..c6da9a800 100644 --- a/sys/sys.txt +++ b/sys/sys.txt @@ -79,14 +79,14 @@ openat(fd fd_dir, file filename, flags flags[open_flags], mode flags[open_mode]) creat(file filename, mode flags[open_mode]) fd close(fd fd) read(fd fd, buf buffer[out], count len[buf]) len[buf] -pread64(fd fd, buf buffer[out], count len[buf], pos fileoff[fd]) +pread64(fd fd, buf buffer[out], count len[buf], pos fileoff) readv(fd fd, vec ptr[in, array[iovec_out]], vlen len[vec]) -preadv(fd fd, vec ptr[in, array[iovec_out]], vlen len[vec], off fileoff[fd]) +preadv(fd fd, vec ptr[in, array[iovec_out]], vlen len[vec], off fileoff) write(fd fd, buf buffer[in], count len[buf]) len[buf] -pwrite64(fd fd, buf buffer[in], count len[buf], pos fileoff[fd]) +pwrite64(fd fd, buf buffer[in], count len[buf], pos fileoff) writev(fd fd, vec ptr[in, array[iovec_in]], vlen len[vec]) -pwritev(fd fd, vec ptr[in, array[iovec_in]], vlen len[vec], off fileoff[fd]) -lseek(fd fd, offset fileoff[fd], whence flags[seek_whence]) +pwritev(fd fd, vec ptr[in, array[iovec_in]], vlen len[vec], off fileoff) +lseek(fd fd, offset fileoff, whence flags[seek_whence]) dup(oldfd fd) fd dup2(oldfd fd, newfd fd) fd @@ -96,9 +96,9 @@ pipe(pipefd ptr[out, pipefd]) pipe2(pipefd ptr[out, pipefd], flags flags[pipe_flags]) tee(fdin fd, fdout fd, len int64, f flags[splice_flags]) -splice(fdin fd, offin fileoff[fdin], fdout fd, offout fileoff[fdout], len int64, f flags[splice_flags]) +splice(fdin fd, offin fileoff, fdout fd, offout fileoff, len int64, f flags[splice_flags]) vmsplice(fd fd, vec ptr[in, array[iovec_in]], vlen len[vec], f flags[splice_flags]) -sendfile(fdout fd, fdin fd, off ptr[inout, fileoff[fdin, int64], opt], count int64) +sendfile(fdout fd, fdin fd, off ptr[inout, fileoff[int64], opt], count int64) stat(file filename, statbuf ptr[out, stat]) lstat(file filename, statbuf ptr[out, stat]) @@ -136,14 +136,14 @@ ioctl$UFFDIO_WAKE(fd fd_uffd, cmd const[UFFDIO_WAKE], arg ptr[in, uffdio_range]) ioctl$UFFDIO_COPY(fd fd_uffd, cmd const[UFFDIO_WAKE], arg ptr[in, uffdio_range]) ioctl$UFFDIO_ZEROPAGE(fd fd_uffd, cmd const[UFFDIO_WAKE], arg ptr[in, uffdio_range]) -mmap(addr vma, len len[addr], prot flags[mmap_prot], flags flags[mmap_flags], fd fd, offset fileoff[fd]) vma +mmap(addr vma, len len[addr], prot flags[mmap_prot], flags flags[mmap_flags], fd fd, offset fileoff) vma munmap(addr vma, len len[addr]) mremap(addr vma, len len[addr], newlen len[newaddr], flags flags[mremap_flags], newaddr vma) vma remap_file_pages(addr vma, size len[addr], prot flags[mmap_prot], pgoff intptr, flags flags[mmap_flags]) mprotect(addr vma, len len[addr], prot flags[mmap_prot]) msync(addr vma, len len[addr], f flags[msync_flags]) madvise(addr vma, len len[addr], advice flags[madvise_flags]) -fadvise64(fd fd, offset fileoff[fd], len intptr, advice flags[fadvise_flags]) +fadvise64(fd fd, offset fileoff, len intptr, advice flags[fadvise_flags]) readahead(fd fd, off intptr, count intptr) mbind(addr vma, len len[addr], mode flags[mbind_mode], nodemask ptr[in, int64], maxnode intptr, flags flags[mbind_flags]) move_pages(pid pid, nr len[pages], pages ptr[in, array[vma]], nodes ptr[in, array[int32], opt], status ptr[out, array[int32]], flags flags[move_pages_flags]) @@ -156,7 +156,7 @@ mlock2(addr vma, size len[addr], flags flags[mlock_flags]) munlock(addr vma, size len[addr]) mlockall(flags flags[mlockall_flags]) munlockall() -memfd_create(name string, flags flags[memfd_flags]) fd +memfd_create(name ptr[in, string], flags flags[memfd_flags]) fd unshare(flags flags[clone_flags]) kcmp(pid1 pid, pid2 pid, type flags[kcmp_flags], fd1 fd, fd2 fd) @@ -220,7 +220,7 @@ prctl$intptr(option flags[prctl_code_intptr], arg intptr) prctl$getreaper(option flags[prctl_code_getreaper], arg ptr[out, intptr]) prctl$setendian(option const[PR_SET_ENDIAN], arg flags[prctl_endian]) prctl$setfpexc(option const[PR_SET_FPEXC], arg flags[prctl_fpexc]) -prctl$setname(option const[PR_SET_NAME], name string) +prctl$setname(option const[PR_SET_NAME], name ptr[in, string]) prctl$getname(option const[PR_GET_NAME], name buffer[out]) prctl$setptracer(option const[PR_SET_PTRACER], pid pid) prctl$seccomp(option const[PR_SET_SECCOMP], mode flags[prctl_seccomp_mode], prog ptr[in, sock_fprog]) @@ -230,12 +230,12 @@ arch_prctl(code flags[arch_prctl_code], addr buffer[in]) seccomp(op flags[seccomp_op], flags flags[seccomp_flags], prog ptr[in, sock_fprog]) resource fd_mq[fd] -mq_open(name string, flags flags[mq_open_flags], mode flags[open_mode], attr ptr[in, mq_attr]) fd_mq +mq_open(name ptr[in, string], flags flags[mq_open_flags], mode flags[open_mode], attr ptr[in, mq_attr]) fd_mq mq_timedsend(mqd fd_mq, msg buffer[in], msglen len[msg], prio intptr, timeout ptr[in, timespec, opt]) mq_timedreceive(mqd fd_mq, msg buffer[out], msglen len[msg], prio intptr, timeout ptr[in, timespec, opt]) mq_notify(mqd fd_mq, notif ptr[in, sigevent]) mq_getsetattr(mqd fd_mq, attr ptr[in, mq_attr], oldattr ptr[out, mq_attr, opt]) -mq_unlink(name string) +mq_unlink(name ptr[in, string]) resource ipc[int32]: 0, 0xffffffffffffffff resource ipc_msq[ipc] @@ -345,21 +345,23 @@ getdents64(fd fd_dir, ent buffer[out], count len[ent]) name_to_handle_at(fd fd_dir, file filename, handle ptr[in, file_handle], mnt ptr[out, int32], flags flags[name_to_handle_at_flags]) open_by_handle_at(mountdirfd fd, handle ptr[in, file_handle], flags flags[open_flags]) -mount(src filename, dst filename, type filesystem, flags flags[mount_flags], data buffer[in]) -mount$fs(src filesystem, dst filename, type filesystem, flags flags[mount_flags], data buffer[in]) +mount(src filename, dst filename, type ptr[in, string[filesystem]], flags flags[mount_flags], data buffer[in]) +mount$fs(src ptr[in, string[filesystem]], dst filename, type ptr[in, string[filesystem]], flags flags[mount_flags], data buffer[in]) umount2(path filename, flags flags[umount_flags]) pivot_root(new_root filename, put_old filename) -sysfs$1(option flags[sysfs_opt1], fsname string) -sysfs$2(option flags[sysfs_opt2], fsindex intptr, fsname buffer[out]) -sysfs$3(option flags[sysfs_opt3]) +filesystem = "sysfs", "rootfs", "ramfs", "tmpfs", "devtmpfs", "debugfs", "securityfs", "sockfs", "pipefs", "anon_inodefs", "devpts", "ext3", "ext2", "ext4", "hugetlbfs", "vfat", "ecryptfs", "kdbusfs", "fuseblk", "fuse", "rpc_pipefs", "nfs", "nfs4", "nfsd", "binfmt_misc", "autofs", "xfs", "jfs", "msdos", "ntfs", "minix", "hfs", "hfsplus", "qnx4", "ufs", "btrfs", "configfs", "ncpfs", "qnx6", "exofs", "befs", "vxfs", "gfs2", "gfs2meta", "fusectl", "bfs", "nsfs", "efs", "cifs", "efivarfs", "affs", "tracefs", "bdev", "ocfs2", "ocfs2_dlmfs", "hpfs", "proc", "afs", "reiserfs", "jffs2", "romfs", "aio", "sysv", "v7", "udf", "ceph", "pstore", "adfs", "9p", "hostfs", "squashfs", "cramfs", "iso9660", "coda", "nilfs2", "logfs", "overlay", "f2fs", "omfs", "ubifs", "openpromfs" + +sysfs$1(option const[1], fsname ptr[in, string]) +sysfs$2(option const[2], fsindex intptr, fsname buffer[out]) +sysfs$3(option const[3]) statfs(path filename, buf buffer[out]) fstatfs(fd fd, buf buffer[out]) uselib(lib filename) -init_module(mod string, len len[mod], args string) -finit_module(fd fd, args string, flags flags[finit_module_flags]) -delete_module(name string, flags flags[delete_module_flags]) +init_module(mod ptr[in, string], len len[mod], args ptr[in, string]) +finit_module(fd fd, args ptr[in, string], flags flags[finit_module_flags]) +delete_module(name ptr[in, string], flags flags[delete_module_flags]) kexec_load(entry intptr, nr_segments len[segments], segments ptr[in, array[kexec_segment]], flags flags[kexec_load_flags]) get_kernel_syms(table buffer[out]) syslog(cmd flags[syslog_cmd], buf buffer[out, opt], len len[buf]) @@ -381,18 +383,18 @@ ioprio_set$pid(which flags[ioprio_which_pid], who pid, prio intptr) ioprio_set$uid(which flags[ioprio_which_uid], who uid, prio intptr) setns(fd fd, type flags[ns_type]) -setxattr(path filename, name string, val string, size len[val], flags flags[setxattr_flags]) -lsetxattr(path filename, name string, val string, size len[val], flags flags[setxattr_flags]) -fsetxattr(fd fd, name string, val string, size len[val], flags flags[setxattr_flags]) -getxattr(path filename, name string, val buffer[out], size len[val]) -lgetxattr(path filename, name string, val buffer[out], size len[val]) -fgetxattr(fd fd, name string, val buffer[out], size len[val]) +setxattr(path filename, name ptr[in, string], val ptr[in, string], size len[val], flags flags[setxattr_flags]) +lsetxattr(path filename, name ptr[in, string], val ptr[in, string], size len[val], flags flags[setxattr_flags]) +fsetxattr(fd fd, name ptr[in, string], val ptr[in, string], size len[val], flags flags[setxattr_flags]) +getxattr(path filename, name ptr[in, string], val buffer[out], size len[val]) +lgetxattr(path filename, name ptr[in, string], val buffer[out], size len[val]) +fgetxattr(fd fd, name ptr[in, string], val buffer[out], size len[val]) listxattr(path filename, list buffer[out], size len[list]) llistxattr(path filename, list buffer[out], size len[list]) flistxattr(fd fd, list buffer[out], size len[list]) -removexattr(path filename, name string) -lremovexattr(path filename, name string) -fremovexattr(fd fd, name string) +removexattr(path filename, name ptr[in, string]) +lremovexattr(path filename, name ptr[in, string]) +fremovexattr(fd fd, name ptr[in, string]) resource timerid[int32] timer_create(id flags[clock_id], ev ptr[in, sigevent], timerid ptr[out, timerid]) @@ -463,55 +465,55 @@ membarrier(cmd const[1], flags const[0]) # These devices are relatively safe (don't reboot and don't corrupt kernel memory). # They need a more comprehensive support. But let at least open them for now, # maybe fuzzer will be able to skrew them in a useful way. -syz_open_dev$floppy(dev strconst["/dev/fd#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$pktcdvd(dev strconst["/dev/pktcdvd/control"], id const[0], flags flags[open_flags]) fd -syz_open_dev$lightnvm(dev strconst["/dev/lightnvm/control"], id const[0], flags flags[open_flags]) fd -syz_open_dev$vcs(dev strconst["/dev/vcs"], id const[0], flags flags[open_flags]) fd -syz_open_dev$vcsn(dev strconst["/dev/vcs#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$vcsa(dev strconst["/dev/vcsa#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$vga_arbiter(dev strconst["/dev/vga_arbiter"], id const[0], flags flags[open_flags]) fd -syz_open_dev$vhci(dev strconst["/dev/vhci"], id const[0], flags flags[open_flags]) fd -syz_open_dev$userio(dev strconst["/dev/userio"], id const[0], flags flags[open_flags]) fd -syz_open_dev$rtc(dev strconst["/dev/rtc"], id const[0], flags flags[open_flags]) fd -syz_open_dev$rfkill(dev strconst["/dev/rfkill"], id const[0], flags flags[open_flags]) fd -syz_open_dev$qat_adf_ctl(dev strconst["/dev/qat_adf_ctl"], id const[0], flags flags[open_flags]) fd -syz_open_dev$ppp(dev strconst["/dev/ppp"], id const[0], flags flags[open_flags]) fd -syz_open_dev$mixer(dev strconst["/dev/mixer"], id const[0], flags flags[open_flags]) fd -syz_open_dev$irnet(dev strconst["/dev/irnet"], id const[0], flags flags[open_flags]) fd -syz_open_dev$hwrng(dev strconst["/dev/hwrng"], id const[0], flags flags[open_flags]) fd -syz_open_dev$hpet(dev strconst["/dev/hpet"], id const[0], flags flags[open_flags]) fd -syz_open_dev$hidraw0(dev strconst["/dev/hidraw0"], id const[0], flags flags[open_flags]) fd -syz_open_dev$fb0(dev strconst["/dev/fb0"], id const[0], flags flags[open_flags]) fd -syz_open_dev$cuse(dev strconst["/dev/cuse"], id const[0], flags flags[open_flags]) fd -syz_open_dev$console(dev strconst["/dev/console"], id const[0], flags flags[open_flags]) fd -syz_open_dev$capi20(dev strconst["/dev/capi20"], id const[0], flags flags[open_flags]) fd -syz_open_dev$autofs(dev strconst["/dev/autofs"], id const[0], flags flags[open_flags]) fd -syz_open_dev$binder(dev strconst["/dev/binder"], id const[0], flags flags[open_flags]) fd -syz_open_dev$ion(dev strconst["/dev/ion"], id const[0], flags flags[open_flags]) fd -syz_open_dev$keychord(dev strconst["/dev/keychord"], id const[0], flags flags[open_flags]) fd -syz_open_dev$zygote(dev strconst["/dev/socket/zygote"], id const[0], flags flags[open_flags]) fd -syz_open_dev$sw_sync(dev strconst["/dev/sw_sync"], id const[0], flags flags[open_flags]) fd -syz_open_dev$sr(dev strconst["/dev/sr0"], id const[0], flags flags[open_flags]) fd -syz_open_dev$sequencer(dev strconst["/dev/sequencer"], id const[0], flags flags[open_flags]) fd -syz_open_dev$sequencer2(dev strconst["/dev/sequencer2"], id const[0], flags flags[open_flags]) fd -syz_open_dev$dsp(dev strconst["/dev/dsp"], id const[0], flags flags[open_flags]) fd -syz_open_dev$audio(dev strconst["/dev/audio"], id const[0], flags flags[open_flags]) fd -syz_open_dev$usbmon(dev strconst["/dev/usbmon#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$sg(dev strconst["/dev/sg#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$midi(dev strconst["/dev/midi#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$loop(dev strconst["/dev/loop#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$ircomm(dev strconst["/dev/ircomm#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$dspn(dev strconst["/dev/dsp#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$dmmidi(dev strconst["/dev/dmmidi#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$admmidi(dev strconst["/dev/admmidi#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$adsp(dev strconst["/dev/adsp#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$amidi(dev strconst["/dev/amidi#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$audion(dev strconst["/dev/audio#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$usb(dev strconst["/dev/bus/usb/00#/00#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$sndhw(dev strconst["/dev/snd/hwC#D#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$sndmidi(dev strconst["/dev/snd/midiC#D#"], id intptr, flags flags[open_flags]) fd -syz_open_dev$sndpcmc(dev strconst["/dev/snd/pcmC#D#c"], id intptr, flags flags[open_flags]) fd -syz_open_dev$sndpcmp(dev strconst["/dev/snd/pcmC#D#p"], id intptr, flags flags[open_flags]) fd +syz_open_dev$floppy(dev ptr[in, string["/dev/fd#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$pktcdvd(dev ptr[in, string["/dev/pktcdvd/control"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$lightnvm(dev ptr[in, string["/dev/lightnvm/control"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$vcs(dev ptr[in, string["/dev/vcs"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$vcsn(dev ptr[in, string["/dev/vcs#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$vcsa(dev ptr[in, string["/dev/vcsa#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$vga_arbiter(dev ptr[in, string["/dev/vga_arbiter"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$vhci(dev ptr[in, string["/dev/vhci"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$userio(dev ptr[in, string["/dev/userio"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$rtc(dev ptr[in, string["/dev/rtc"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$rfkill(dev ptr[in, string["/dev/rfkill"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$qat_adf_ctl(dev ptr[in, string["/dev/qat_adf_ctl"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$ppp(dev ptr[in, string["/dev/ppp"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$mixer(dev ptr[in, string["/dev/mixer"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$irnet(dev ptr[in, string["/dev/irnet"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$hwrng(dev ptr[in, string["/dev/hwrng"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$hpet(dev ptr[in, string["/dev/hpet"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$hidraw0(dev ptr[in, string["/dev/hidraw0"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$fb0(dev ptr[in, string["/dev/fb0"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$cuse(dev ptr[in, string["/dev/cuse"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$console(dev ptr[in, string["/dev/console"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$capi20(dev ptr[in, string["/dev/capi20"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$autofs(dev ptr[in, string["/dev/autofs"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$binder(dev ptr[in, string["/dev/binder"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$ion(dev ptr[in, string["/dev/ion"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$keychord(dev ptr[in, string["/dev/keychord"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$zygote(dev ptr[in, string["/dev/socket/zygote"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$sw_sync(dev ptr[in, string["/dev/sw_sync"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$sr(dev ptr[in, string["/dev/sr0"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$sequencer(dev ptr[in, string["/dev/sequencer"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$sequencer2(dev ptr[in, string["/dev/sequencer2"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$dsp(dev ptr[in, string["/dev/dsp"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$audio(dev ptr[in, string["/dev/audio"]], id const[0], flags flags[open_flags]) fd +syz_open_dev$usbmon(dev ptr[in, string["/dev/usbmon#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$sg(dev ptr[in, string["/dev/sg#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$midi(dev ptr[in, string["/dev/midi#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$loop(dev ptr[in, string["/dev/loop#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$ircomm(dev ptr[in, string["/dev/ircomm#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$dspn(dev ptr[in, string["/dev/dsp#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$dmmidi(dev ptr[in, string["/dev/dmmidi#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$admmidi(dev ptr[in, string["/dev/admmidi#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$adsp(dev ptr[in, string["/dev/adsp#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$amidi(dev ptr[in, string["/dev/amidi#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$audion(dev ptr[in, string["/dev/audio#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$usb(dev ptr[in, string["/dev/bus/usb/00#/00#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$sndhw(dev ptr[in, string["/dev/snd/hwC#D#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$sndmidi(dev ptr[in, string["/dev/snd/midiC#D#"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$sndpcmc(dev ptr[in, string["/dev/snd/pcmC#D#c"]], id intptr, flags flags[open_flags]) fd +syz_open_dev$sndpcmp(dev ptr[in, string["/dev/snd/pcmC#D#p"]], id intptr, flags flags[open_flags]) fd @@ -1167,9 +1169,6 @@ ioprio_which_uid = IOPRIO_WHO_USER setxattr_flags = XATTR_CREATE, XATTR_REPLACE ns_type = 0, CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWUTS personality_flags = PER_LINUX, PER_SVR4, PER_SVR3, PER_OSR5, PER_WYSEV386, PER_ISCR4, PER_BSD, PER_XENIX, PER_LINUX32, PER_IRIX32, PER_IRIXN32, PER_IRIX64, PER_RISCOS, PER_SOLARIS, PER_UW7, PER_OSF4, PER_HPUX, ADDR_NO_RANDOMIZE, MMAP_PAGE_ZERO, ADDR_COMPAT_LAYOUT, READ_IMPLIES_EXEC, ADDR_LIMIT_32BIT, SHORT_INODE, WHOLE_SECONDS, STICKY_TIMEOUTS, ADDR_LIMIT_3GB -sysfs_opt1 = 1 -sysfs_opt2 = 2 -sysfs_opt3 = 3 clock_id = CLOCK_REALTIME, CLOCK_REALTIME_COARSE, CLOCK_MONOTONIC, CLOCK_MONOTONIC_COARSE, CLOCK_MONOTONIC_RAW, CLOCK_BOOTTIME, CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID sigprocmask_how = SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK getitimer_which = ITIMER_REAL, ITIMER_VIRTUAL, ITIMER_PROF diff --git a/sys/tlk_device.txt b/sys/tlk_device.txt index 7535d16f7..1d5bd8229 100644 --- a/sys/tlk_device.txt +++ b/sys/tlk_device.txt @@ -12,7 +12,7 @@ include <security/tlk_driver/ote_protocol.h> resource fd_tlk[fd] resource te_session_id[int32] -syz_open_dev$tlk_device(dev strconst["/dev/tlk_device"], id const[0], flags flags[open_flags]) fd_tlk +syz_open_dev$tlk_device(dev ptr[in, string["/dev/tlk_device"]], id const[0], flags flags[open_flags]) fd_tlk ioctl$TE_IOCTL_OPEN_CLIENT_SESSION(fd fd_tlk, cmd const[TE_IOCTL_OPEN_CLIENT_SESSION], arg ptr[inout, te_opensession]) ioctl$TE_IOCTL_CLOSE_CLIENT_SESSION(fd fd_tlk, cmd const[TE_IOCTL_CLOSE_CLIENT_SESSION], arg ptr[inout, te_closesession]) diff --git a/sys/tty.txt b/sys/tty.txt index 67b11b754..e9717806c 100644 --- a/sys/tty.txt +++ b/sys/tty.txt @@ -8,7 +8,7 @@ include <uapi/linux/fcntl.h> resource fd_tty[fd] -openat$ptmx(fd const[AT_FDCWD], file strconst["/dev/ptmx"], flags flags[open_flags], mode const[0]) fd_tty +openat$ptmx(fd const[AT_FDCWD], file ptr[in, string["/dev/ptmx"]], flags flags[open_flags], mode const[0]) fd_tty syz_open_pts(fd fd_tty, flags flags[open_flags]) fd_tty ioctl$TCGETS(fd fd_tty, cmd const[TCGETS], arg ptr[out, termios]) ioctl$TCSETS(fd fd_tty, cmd const[TCSETS], arg ptr[in, termios]) diff --git a/sys/tun.txt b/sys/tun.txt index 04e640786..a730ed86a 100755 --- a/sys/tun.txt +++ b/sys/tun.txt @@ -6,7 +6,7 @@ include <linux/virtio_net.h> resource fd_tun[fd] -syz_open_dev$tun(dev strconst["/dev/net/tun"], id const[0], flags flags[open_flags]) fd_tun +syz_open_dev$tun(dev ptr[in, string["/dev/net/tun"]], id const[0], flags flags[open_flags]) fd_tun write$tun(fd fd_tun, buf ptr[in, tun_buffer], count len[buf]) ioctl$TUNGETFEATURES(fd fd_tun, cmd const[TUNGETFEATURES], arg ptr[out, int32]) diff --git a/sysgen/sysgen.go b/sysgen/sysgen.go index d197b774b..fda931b14 100644 --- a/sysgen/sysgen.go +++ b/sysgen/sysgen.go @@ -162,7 +162,7 @@ func generate(arch string, desc *Description, consts map[string]uint64, out io.W fmt.Fprintf(out, "func() { Calls = append(Calls, &Call{Name: \"%v\", CallName: \"%v\"", s.Name, s.CallName) if len(s.Ret) != 0 { fmt.Fprintf(out, ", Ret: ") - generateArg("", "ret", s.Ret[0], s.Ret[1:], desc, consts, true, false, out) + generateArg("", "ret", s.Ret[0], "out", s.Ret[1:], desc, consts, true, false, out) } fmt.Fprintf(out, ", Args: []Type{") for i, a := range s.Args { @@ -170,7 +170,7 @@ func generate(arch string, desc *Description, consts map[string]uint64, out io.W fmt.Fprintf(out, ", ") } logf(5, " generate description for arg %v", i) - generateArg("", a[0], a[1], a[2:], desc, consts, true, false, out) + generateArg("", a[0], a[1], "in", a[2:], desc, consts, true, false, out) } if skipCurrentSyscall != "" { logf(0, "unsupported syscall: %v due to %v", s.Name, skipCurrentSyscall) @@ -230,7 +230,7 @@ func generateResources(desc *Description, consts map[string]uint64, out io.Write } } fmt.Fprintf(out, "\"%v\": &ResourceDesc{Name: \"%v\", Type: ", name, name) - generateArg("", "resource-type", underlying, nil, desc, consts, true, true, out) + generateArg("", "resource-type", underlying, "inout", nil, desc, consts, true, true, out) fmt.Fprintf(out, ", Kind: []string{") for i, k := range kind { if i != 0 { @@ -253,11 +253,21 @@ func generateResources(desc *Description, consts map[string]uint64, out io.Write fmt.Fprintf(out, "}\n") } -func generateStructEntry(str Struct, key string, name string, out io.Writer) { +type structKey struct { + name string + field string + dir string +} + +func generateStructEntry(str Struct, key structKey, out io.Writer) { typ := "StructType" if str.IsUnion { typ = "UnionType" } + name := key.field + if name == "" { + name = key.name + } packed := "" if str.Packed { packed = ", packed: true" @@ -270,11 +280,11 @@ func generateStructEntry(str Struct, key string, name string, out io.Writer) { if str.Align != 0 { align = fmt.Sprintf(", align: %v", str.Align) } - fmt.Fprintf(out, "\"%v\": &%v{TypeCommon: TypeCommon{TypeName: \"%v\", IsOptional: %v} %v %v %v},\n", - key, typ, name, false, packed, align, varlen) + fmt.Fprintf(out, "\"%v\": &%v{TypeCommon: TypeCommon{TypeName: \"%v\", ArgDir: %v, IsOptional: %v} %v %v %v},\n", + key, typ, name, fmtDir(key.dir), false, packed, align, varlen) } -func generateStructFields(str Struct, key string, desc *Description, consts map[string]uint64, out io.Writer) { +func generateStructFields(str Struct, key structKey, desc *Description, consts map[string]uint64, out io.Writer) { typ := "StructType" fields := "Fields" if str.IsUnion { @@ -284,7 +294,7 @@ func generateStructFields(str Struct, key string, desc *Description, consts map[ fmt.Fprintf(out, "{ s := Structs[\"%v\"].(*%v)\n", key, typ) for _, a := range str.Flds { fmt.Fprintf(out, "s.%v = append(s.%v, ", fields, fields) - generateArg(str.Name, a[0], a[1], a[2:], desc, consts, false, true, out) + generateArg(str.Name, a[0], a[1], key.dir, a[2:], desc, consts, false, true, out) fmt.Fprintf(out, ")\n") } fmt.Fprintf(out, "}\n") @@ -301,24 +311,23 @@ func generateStructs(desc *Description, consts map[string]uint64, out io.Writer) // for each field indexed by the name of the parent struct and the // field name. - structMap := make(map[string]Struct) + structMap := make(map[structKey]Struct) for _, str := range desc.Structs { - if _, ok := structMap[str.Name]; ok { - failf("two structs with the same name '%v'", str.Name) + for _, dir := range []string{"in", "out", "inout"} { + structMap[structKey{str.Name, "", dir}] = str } - structMap[str.Name] = str for _, a := range str.Flds { if innerStr, ok := desc.Structs[a[1]]; ok { - structMap[fmt.Sprintf("%v-%v", str.Name, a[0])] = innerStr + for _, dir := range []string{"in", "out", "inout"} { + structMap[structKey{a[1], a[0], dir}] = innerStr + } } } } fmt.Fprintf(out, "var Structs = map[string]Type{\n") for key, str := range structMap { - keyParts := strings.Split(key, "-") - name := keyParts[len(keyParts)-1] - generateStructEntry(str, key, name, out) + generateStructEntry(str, key, out) } fmt.Fprintf(out, "}\n") @@ -351,7 +360,7 @@ func parseRange(buffer string, consts map[string]uint64) (string, string) { } func generateArg( - parent, name, typ string, + parent, name, typ, dir string, a []string, desc *Description, consts map[string]uint64, @@ -369,7 +378,7 @@ func generateArg( } } common := func() string { - return fmt.Sprintf("TypeCommon: TypeCommon{TypeName: %v, IsOptional: %v}", name, opt) + return fmt.Sprintf("TypeCommon: TypeCommon{TypeName: %v, ArgDir: %v, IsOptional: %v}", name, fmtDir(dir), opt) } canBeArg := false switch typ { @@ -378,61 +387,89 @@ func generateArg( size := uint64(ptrSize) bigEndian := false if isField { - if want := 2; len(a) != want { + if want := 1; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - size, bigEndian = decodeIntType(a[1]) + size, bigEndian = decodeIntType(a[0]) } else { - if want := 1; len(a) != want { + if want := 0; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } } - fmt.Fprintf(out, "FileoffType{%v, File: \"%v\", TypeSize: %v, BigEndian: %v}", common(), a[0], size, bigEndian) + fmt.Fprintf(out, "&IntType{%v, TypeSize: %v, BigEndian: %v, Kind: IntFileoff}", common(), size, bigEndian) case "buffer": canBeArg = true if want := 1; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - commonHdr := common() + ptrCommonHdr := common() + dir = a[0] opt = false - fmt.Fprintf(out, "PtrType{%v, Dir: %v, Type: BufferType{%v, Kind: BufferBlobRand}}", commonHdr, fmtDir(a[0]), common()) + fmt.Fprintf(out, "&PtrType{%v, Type: &BufferType{%v, Kind: BufferBlobRand}}", ptrCommonHdr, common()) case "string": - canBeArg = true - if want := 0; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) + if len(a) != 0 && len(a) != 1 && len(a) != 2 { + failf("wrong number of arguments for %v arg %v, want 0-2, got %v", typ, name, len(a)) + } + var vals []string + subkind := "" + if len(a) >= 1 { + if a[0][0] == '"' { + vals = append(vals, a[0][1:len(a[0])-1]) + } else { + vals1, ok := desc.StrFlags[a[0]] + if !ok { + failf("unknown string flags %v", a[0]) + } + vals = append([]string{}, vals1...) + subkind = a[0] + } } - commonHdr := common() - opt = false - fmt.Fprintf(out, "PtrType{%v, Dir: %v, Type: BufferType{%v, Kind: BufferString}}", commonHdr, fmtDir("in"), common()) - case "filesystem": - canBeArg = true - if want := 0; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) + for i, s := range vals { + vals[i] = s + "\x00" } - commonHdr := common() - opt = false - fmt.Fprintf(out, "PtrType{%v, Dir: %v, Type: BufferType{%v, Kind: BufferFilesystem}}", commonHdr, fmtDir("in"), common()) + if len(a) >= 2 { + var size uint64 + if v, ok := consts[a[1]]; ok { + size = v + } else { + v, err := strconv.ParseUint(a[1], 10, 64) + if err != nil { + failf("failed to parse string length for %v", name, a[1]) + } + size = v + } + for i, s := range vals { + if uint64(len(s)) > size { + failf("string value %q exceeds buffer length %v for arg %v", s, size, name) + } + for uint64(len(s)) < size { + s += "\x00" + } + vals[i] = s + } + } + fmt.Fprintf(out, "&BufferType{%v, Kind: BufferString, SubKind: %q, Values: %#v}", common(), subkind, vals) case "sockaddr": if want := 0; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - fmt.Fprintf(out, "BufferType{%v, Kind: BufferSockaddr}", common()) + fmt.Fprintf(out, "&BufferType{%v, Kind: BufferSockaddr}", common()) case "salg_type": if want := 0; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - fmt.Fprintf(out, "BufferType{%v, Kind: BufferAlgType}", common()) + fmt.Fprintf(out, "&BufferType{%v, Kind: BufferAlgType}", common()) case "salg_name": if want := 0; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - fmt.Fprintf(out, "BufferType{%v, Kind: BufferAlgName}", common()) + fmt.Fprintf(out, "&BufferType{%v, Kind: BufferAlgName}", common()) case "vma": canBeArg = true if want := 0; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - fmt.Fprintf(out, "VmaType{%v}", common()) + fmt.Fprintf(out, "&VmaType{%v}", common()) case "len", "bytesize": canBeArg = true size := uint64(ptrSize) @@ -447,7 +484,7 @@ func generateArg( failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } } - fmt.Fprintf(out, "LenType{%v, Buf: \"%v\", TypeSize: %v, BigEndian: %v, ByteSize: %v}", common(), a[0], size, bigEndian, typ == "bytesize") + fmt.Fprintf(out, "&LenType{%v, Buf: \"%v\", TypeSize: %v, BigEndian: %v, ByteSize: %v}", common(), a[0], size, bigEndian, typ == "bytesize") case "flags": canBeArg = true size := uint64(ptrSize) @@ -467,9 +504,9 @@ func generateArg( failf("unknown flag %v", a[0]) } if len(vals) == 0 { - fmt.Fprintf(out, "IntType{%v, TypeSize: %v, BigEndian: %v}", common(), size, bigEndian) + fmt.Fprintf(out, "&IntType{%v, TypeSize: %v, BigEndian: %v}", common(), size, bigEndian) } else { - fmt.Fprintf(out, "FlagsType{%v, TypeSize: %v, BigEndian: %v, Vals: []uintptr{%v}}", common(), size, bigEndian, strings.Join(vals, ",")) + fmt.Fprintf(out, "&FlagsType{%v, TypeSize: %v, BigEndian: %v, Vals: []uintptr{%v}}", common(), size, bigEndian, strings.Join(vals, ",")) } case "const": canBeArg = true @@ -494,22 +531,16 @@ func generateArg( val = "0" skipSyscall(fmt.Sprintf("missing const %v", a[0])) } - fmt.Fprintf(out, "ConstType{%v, TypeSize: %v, BigEndian: %v, Val: uintptr(%v)}", common(), size, bigEndian, val) - case "strconst": - canBeArg = true - if want := 1; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - fmt.Fprintf(out, "PtrType{%v, Dir: %v, Type: StrConstType{%v, Val: \"%v\"}}", common(), fmtDir("in"), common(), a[0]+"\\x00") + fmt.Fprintf(out, "&ConstType{%v, TypeSize: %v, BigEndian: %v, Val: uintptr(%v)}", common(), size, bigEndian, val) case "int8", "int16", "int32", "int64", "intptr", "int16be", "int32be", "int64be", "intptrbe": canBeArg = true size, bigEndian := decodeIntType(typ) switch len(a) { case 0: - fmt.Fprintf(out, "IntType{%v, TypeSize: %v, BigEndian: %v}", common(), size, bigEndian) + fmt.Fprintf(out, "&IntType{%v, TypeSize: %v, BigEndian: %v}", common(), size, bigEndian) case 1: begin, end := parseRange(a[0], consts) - fmt.Fprintf(out, "IntType{%v, TypeSize: %v, BigEndian: %v, Kind: IntRange, RangeBegin: %v, RangeEnd: %v}", common(), size, bigEndian, begin, end) + fmt.Fprintf(out, "&IntType{%v, TypeSize: %v, BigEndian: %v, Kind: IntRange, RangeBegin: %v, RangeEnd: %v}", common(), size, bigEndian, begin, end) default: failf("wrong number of arguments for %v arg %v, want 0 or 1, got %v", typ, name, len(a)) } @@ -518,41 +549,42 @@ func generateArg( if want := 0; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - fmt.Fprintf(out, "IntType{%v, TypeSize: 4, Kind: IntSignalno}", common()) + fmt.Fprintf(out, "&IntType{%v, TypeSize: 4, Kind: IntSignalno}", common()) case "in_addr": if want := 0; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - fmt.Fprintf(out, "IntType{%v, TypeSize: 4, Kind: IntInaddr}", common()) + fmt.Fprintf(out, "&IntType{%v, TypeSize: 4, Kind: IntInaddr}", common()) case "in_port": if want := 0; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - fmt.Fprintf(out, "IntType{%v, TypeSize: 2, Kind: IntInport}", common()) + fmt.Fprintf(out, "&IntType{%v, TypeSize: 2, Kind: IntInport}", common()) case "filename": canBeArg = true if want := 0; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - commonHdr := common() + ptrCommonHdr := common() + dir = "in" opt = false - fmt.Fprintf(out, "PtrType{%v, Dir: DirIn, Type: FilenameType{%v}}", commonHdr, common()) + fmt.Fprintf(out, "&PtrType{%v, Type: &BufferType{%v, Kind: BufferFilename}}", ptrCommonHdr, common()) case "array": if len(a) != 1 && len(a) != 2 { failf("wrong number of arguments for %v arg %v, want 1 or 2, got %v", typ, name, len(a)) } if len(a) == 1 { if a[0] == "int8" { - fmt.Fprintf(out, "BufferType{%v, Kind: BufferBlobRand}", common()) + fmt.Fprintf(out, "&BufferType{%v, Kind: BufferBlobRand}", common()) } else { - fmt.Fprintf(out, "ArrayType{%v, Type: %v, Kind: ArrayRandLen}", common(), generateType(a[0], desc, consts)) + fmt.Fprintf(out, "&ArrayType{%v, Type: %v, Kind: ArrayRandLen}", common(), generateType(a[0], dir, desc, consts)) } } else { begin, end := parseRange(a[1], consts) if a[0] == "int8" { - fmt.Fprintf(out, "BufferType{%v, Kind: BufferBlobRange, RangeBegin: %v, RangeEnd: %v}", common(), begin, end) + fmt.Fprintf(out, "&BufferType{%v, Kind: BufferBlobRange, RangeBegin: %v, RangeEnd: %v}", common(), begin, end) } else { - fmt.Fprintf(out, "ArrayType{%v, Type: %v, Kind: ArrayRangeLen, RangeBegin: %v, RangeEnd: %v}", common(), generateType(a[0], desc, consts), begin, end) + fmt.Fprintf(out, "&ArrayType{%v, Type: %v, Kind: ArrayRangeLen, RangeBegin: %v, RangeEnd: %v}", common(), generateType(a[0], dir, desc, consts), begin, end) } } case "ptr": @@ -560,11 +592,12 @@ func generateArg( if want := 2; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - fmt.Fprintf(out, "PtrType{%v, Type: %v, Dir: %v}", common(), generateType(a[1], desc, consts), fmtDir(a[0])) + dir = "in" + fmt.Fprintf(out, "&PtrType{%v, Type: %v}", common(), generateType(a[1], a[0], desc, consts)) default: if strings.HasPrefix(typ, "unnamed") { if inner, ok := desc.Unnamed[typ]; ok { - generateArg("", "", inner[0], inner[1:], desc, consts, false, isField, out) + generateArg("", "", inner[0], dir, inner[1:], desc, consts, false, isField, out) } else { failf("unknown unnamed type '%v'", typ) } @@ -572,16 +605,12 @@ func generateArg( if len(a) != 0 { failf("struct '%v' has args", typ) } - if parent == "" { - fmt.Fprintf(out, "Structs[\"%v\"]", typ) - } else { - fmt.Fprintf(out, "Structs[\"%v-%v\"]", parent, origName) - } + fmt.Fprintf(out, "Structs[\"%v\"]", structKey{typ, origName, dir}) } else if _, ok := desc.Resources[typ]; ok { if len(a) != 0 { failf("resource '%v' has args", typ) } - fmt.Fprintf(out, "ResourceType{%v, Desc: Resources[\"%v\"]}", common(), typ) + fmt.Fprintf(out, "&ResourceType{%v, Desc: Resources[\"%v\"]}", common(), typ) return } else { failf("unknown arg type \"%v\" for %v", typ, name) @@ -592,9 +621,9 @@ func generateArg( } } -func generateType(typ string, desc *Description, consts map[string]uint64) string { +func generateType(typ, dir string, desc *Description, consts map[string]uint64) string { buf := new(bytes.Buffer) - generateArg("", "", typ, nil, desc, consts, false, true, buf) + generateArg("", "", typ, dir, nil, desc, consts, false, true, buf) return buf.String() } diff --git a/sysparser/lexer.go b/sysparser/lexer.go index 06210a584..a3b8f58ed 100644 --- a/sysparser/lexer.go +++ b/sysparser/lexer.go @@ -18,6 +18,7 @@ type Description struct { Structs map[string]Struct Unnamed map[string][]string Flags map[string][]string + StrFlags map[string][]string Resources map[string]Resource } @@ -51,6 +52,7 @@ func Parse(in io.Reader) *Description { structs := make(map[string]Struct) unnamed := make(map[string][]string) flags := make(map[string][]string) + strflags := make(map[string][]string) resources := make(map[string]Resource) var str *Struct for p.Scan() { @@ -93,6 +95,9 @@ func Parse(in io.Reader) *Description { } fields := make(map[string]bool) for _, f := range str.Flds { + if f[0] == "parent" { + failf("struct/union %v contains reserved field 'parent'", str.Name) + } if fields[f[0]] { failf("duplicate field %v in struct/union %v", f[0], str.Name) } @@ -189,12 +194,24 @@ func Parse(in io.Reader) *Description { case '=': // flag p.Parse('=') - vals := []string{p.Ident()} - for !p.EOF() { + str := p.Char() == '"' + var vals []string + for { + v := p.Ident() + if str { + v = v[1 : len(v)-1] + } + vals = append(vals, v) + if p.EOF() { + break + } p.Parse(',') - vals = append(vals, p.Ident()) } - flags[name] = vals + if str { + strflags[name] = vals + } else { + flags[name] = vals + } case '{', '[': p.Parse(ch) if _, ok := structs[name]; ok { @@ -221,6 +238,7 @@ func Parse(in io.Reader) *Description { Structs: structs, Unnamed: unnamed, Flags: flags, + StrFlags: strflags, Resources: resources, } } diff --git a/sysparser/parser.go b/sysparser/parser.go index 590847b0e..d5021eee6 100644 --- a/sysparser/parser.go +++ b/sysparser/parser.go @@ -70,11 +70,10 @@ func (p *parser) Ident() string { start, end := p.i, 0 if p.Char() == '"' { p.Parse('"') - start++ for p.Char() != '"' { p.i++ } - end = p.i + end = p.i + 1 p.Parse('"') } else { for p.i < len(p.s) && |
