1// Copyright 2015 syzkaller project authors. All rights reserved.
2// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
3
4package prog
5
6import (
7	"fmt"
8	"path/filepath"
9)
10
11var debug = false // enabled in tests
12
13func (p *Prog) debugValidate() {
14	if debug {
15		if err := p.validate(); err != nil {
16			panic(err)
17		}
18	}
19}
20
21type validCtx struct {
22	target *Target
23	args   map[Arg]bool
24	uses   map[Arg]Arg
25}
26
27func (p *Prog) validate() error {
28	ctx := &validCtx{
29		target: p.Target,
30		args:   make(map[Arg]bool),
31		uses:   make(map[Arg]Arg),
32	}
33	for _, c := range p.Calls {
34		if c.Meta == nil {
35			return fmt.Errorf("call does not have meta information")
36		}
37		if err := ctx.validateCall(c); err != nil {
38			return fmt.Errorf("call %v: %v", c.Meta.Name, err)
39		}
40	}
41	for u, orig := range ctx.uses {
42		if !ctx.args[u] {
43			return fmt.Errorf("use of %+v referes to an out-of-tree arg\narg: %#v", orig, u)
44		}
45	}
46	return nil
47}
48
49func (ctx *validCtx) validateCall(c *Call) error {
50	if len(c.Args) != len(c.Meta.Args) {
51		return fmt.Errorf("wrong number of arguments, want %v, got %v",
52			len(c.Meta.Args), len(c.Args))
53	}
54	for i, arg := range c.Args {
55		if err := ctx.validateArg(arg, c.Meta.Args[i]); err != nil {
56			return err
57		}
58	}
59	return ctx.validateRet(c)
60}
61
62func (ctx *validCtx) validateRet(c *Call) error {
63	if c.Meta.Ret == nil {
64		if c.Ret != nil {
65			return fmt.Errorf("return value without type")
66		}
67		return nil
68	}
69	if c.Ret == nil {
70		return fmt.Errorf("return value is absent")
71	}
72	if c.Ret.Type().Dir() != DirOut {
73		return fmt.Errorf("return value %v is not output", c.Ret)
74	}
75	if c.Ret.Res != nil || c.Ret.Val != 0 || c.Ret.OpDiv != 0 || c.Ret.OpAdd != 0 {
76		return fmt.Errorf("return value %v is not empty", c.Ret)
77	}
78	return ctx.validateArg(c.Ret, c.Meta.Ret)
79}
80
81func (ctx *validCtx) validateArg(arg Arg, typ Type) error {
82	if arg == nil {
83		return fmt.Errorf("nil arg")
84	}
85	if ctx.args[arg] {
86		return fmt.Errorf("arg %#v is referenced several times in the tree", arg)
87	}
88	if arg.Type() == nil {
89		return fmt.Errorf("no arg type")
90	}
91	if !ctx.target.isAnyPtr(arg.Type()) && arg.Type() != typ {
92		return fmt.Errorf("bad arg type %#v, expect %#v", arg.Type(), typ)
93	}
94	ctx.args[arg] = true
95	return arg.validate(ctx)
96}
97
98func (arg *ConstArg) validate(ctx *validCtx) error {
99	switch typ := arg.Type().(type) {
100	case *IntType:
101		if typ.Dir() == DirOut && !isDefault(arg) {
102			return fmt.Errorf("out int arg '%v' has bad const value %v", typ.Name(), arg.Val)
103		}
104	case *ProcType:
105		if arg.Val >= typ.ValuesPerProc && !isDefault(arg) {
106			return fmt.Errorf("per proc arg '%v' has bad value %v", typ.Name(), arg.Val)
107		}
108	case *CsumType:
109		if arg.Val != 0 {
110			return fmt.Errorf("csum arg '%v' has nonzero value %v", typ.Name(), arg.Val)
111		}
112	case *ConstType, *FlagsType, *LenType:
113	default:
114		return fmt.Errorf("const arg %v has bad type %v", arg, typ.Name())
115	}
116	if typ := arg.Type(); typ.Dir() == DirOut {
117		// We generate output len arguments, which makes sense since it can be
118		// a length of a variable-length array which is not known otherwise.
119		if _, isLen := typ.(*LenType); !isLen {
120			if !typ.isDefaultArg(arg) {
121				return fmt.Errorf("output arg '%v'/'%v' has non default value '%+v'",
122					typ.FieldName(), typ.Name(), arg)
123			}
124		}
125	}
126	return nil
127}
128
129func (arg *ResultArg) validate(ctx *validCtx) error {
130	typ, ok := arg.Type().(*ResourceType)
131	if !ok {
132		return fmt.Errorf("result arg %v has bad type %v", arg, arg.Type().Name())
133	}
134	for u := range arg.uses {
135		if u == nil {
136			return fmt.Errorf("nil reference in uses for arg %+v", arg)
137		}
138		if u.Res != arg {
139			return fmt.Errorf("result arg '%v' has broken uses link to (%+v)", arg, u)
140		}
141		ctx.uses[u] = arg
142	}
143	if typ.Dir() == DirOut && arg.Val != 0 && arg.Val != typ.Default() {
144		return fmt.Errorf("out resource arg '%v' has bad const value %v", typ.Name(), arg.Val)
145	}
146	if arg.Res != nil {
147		if !ctx.args[arg.Res] {
148			return fmt.Errorf("result arg %v references out-of-tree result: %#v -> %#v",
149				typ.Name(), arg, arg.Res)
150		}
151		if !arg.Res.uses[arg] {
152			return fmt.Errorf("result arg '%v' has broken link (%+v)", typ.Name(), arg.Res.uses)
153		}
154	}
155	return nil
156}
157
158func (arg *DataArg) validate(ctx *validCtx) error {
159	typ, ok := arg.Type().(*BufferType)
160	if !ok {
161		return fmt.Errorf("data arg %v has bad type %v", arg, arg.Type().Name())
162	}
163	if typ.Dir() == DirOut && len(arg.data) != 0 {
164		return fmt.Errorf("output arg '%v' has data", typ.Name())
165	}
166	if !typ.Varlen() && typ.Size() != arg.Size() {
167		return fmt.Errorf("data arg %v has wrong size %v, want %v",
168			typ.Name(), arg.Size(), typ.Size())
169	}
170	switch typ.Kind {
171	case BufferString:
172		if typ.TypeSize != 0 && arg.Size() != typ.TypeSize {
173			return fmt.Errorf("string arg '%v' has size %v, which should be %v",
174				typ.Name(), arg.Size(), typ.TypeSize)
175		}
176	case BufferFilename:
177		file := string(arg.data)
178		for len(file) != 0 && file[len(file)-1] == 0 {
179			file = file[:len(file)-1]
180		}
181		file = filepath.Clean(file)
182		if len(file) > 0 && file[0] == '/' ||
183			len(file) > 1 && file[0] == '.' && file[1] == '.' {
184			return fmt.Errorf("sandbox escaping file name %q", string(arg.data))
185		}
186	}
187	return nil
188}
189
190func (arg *GroupArg) validate(ctx *validCtx) error {
191	switch typ := arg.Type().(type) {
192	case *StructType:
193		if len(arg.Inner) != len(typ.Fields) {
194			return fmt.Errorf("struct arg '%v' has wrong number of fields: want %v, got %v",
195				typ.Name(), len(typ.Fields), len(arg.Inner))
196		}
197		for i, field := range arg.Inner {
198			if err := ctx.validateArg(field, typ.Fields[i]); err != nil {
199				return err
200			}
201		}
202	case *ArrayType:
203		if typ.Kind == ArrayRangeLen && typ.RangeBegin == typ.RangeEnd &&
204			uint64(len(arg.Inner)) != typ.RangeBegin {
205			return fmt.Errorf("array %v has wrong number of elements %v, want %v",
206				typ.Name(), len(arg.Inner), typ.RangeBegin)
207		}
208		for _, elem := range arg.Inner {
209			if err := ctx.validateArg(elem, typ.Type); err != nil {
210				return err
211			}
212		}
213	default:
214		return fmt.Errorf("group arg %v has bad type %v", arg, typ.Name())
215	}
216	return nil
217}
218
219func (arg *UnionArg) validate(ctx *validCtx) error {
220	typ, ok := arg.Type().(*UnionType)
221	if !ok {
222		return fmt.Errorf("union arg %v has bad type %v", arg, arg.Type().Name())
223	}
224	var optType Type
225	for _, typ1 := range typ.Fields {
226		if arg.Option.Type().FieldName() == typ1.FieldName() {
227			optType = typ1
228			break
229		}
230	}
231	if optType == nil {
232		return fmt.Errorf("union arg '%v' has bad option", typ.Name())
233	}
234	return ctx.validateArg(arg.Option, optType)
235}
236
237func (arg *PointerArg) validate(ctx *validCtx) error {
238	switch typ := arg.Type().(type) {
239	case *VmaType:
240		if arg.Res != nil {
241			return fmt.Errorf("vma arg '%v' has data", typ.Name())
242		}
243	case *PtrType:
244		if arg.Res == nil && !arg.Type().Optional() {
245			return fmt.Errorf("non optional pointer arg '%v' is nil", typ.Name())
246		}
247		if arg.Res != nil {
248			if err := ctx.validateArg(arg.Res, typ.Type); err != nil {
249				return err
250			}
251		}
252		if arg.VmaSize != 0 {
253			return fmt.Errorf("pointer arg '%v' has nonzero size", typ.Name())
254		}
255		if typ.Dir() == DirOut {
256			return fmt.Errorf("pointer arg '%v' has output direction", typ.Name())
257		}
258	default:
259		return fmt.Errorf("ptr arg %v has bad type %v", arg, typ.Name())
260	}
261	maxMem := ctx.target.NumPages * ctx.target.PageSize
262	size := arg.VmaSize
263	if size == 0 && arg.Res != nil {
264		size = arg.Res.Size()
265	}
266	if arg.Address >= maxMem || arg.Address+size > maxMem {
267		return fmt.Errorf("ptr %v has bad address %v/%v/%v",
268			arg.Type().Name(), arg.Address, arg.VmaSize, size)
269	}
270	return nil
271}
272