• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2017 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)
9
10type ExecProg struct {
11	Calls []ExecCall
12	Vars  []uint64
13}
14
15type ExecCall struct {
16	Meta    *Syscall
17	Index   uint64
18	Args    []ExecArg
19	Copyin  []ExecCopyin
20	Copyout []ExecCopyout
21}
22
23type ExecCopyin struct {
24	Addr uint64
25	Arg  ExecArg
26}
27
28type ExecCopyout struct {
29	Index uint64
30	Addr  uint64
31	Size  uint64
32}
33
34type ExecArg interface{} // one of ExecArg*
35
36type ExecArgConst struct {
37	Size           uint64
38	Format         BinaryFormat
39	Value          uint64
40	BitfieldOffset uint64
41	BitfieldLength uint64
42	PidStride      uint64
43}
44
45type ExecArgResult struct {
46	Size    uint64
47	Format  BinaryFormat
48	Index   uint64
49	DivOp   uint64
50	AddOp   uint64
51	Default uint64
52}
53
54type ExecArgData struct {
55	Data []byte
56}
57
58type ExecArgCsum struct {
59	Size   uint64
60	Kind   uint64
61	Chunks []ExecCsumChunk
62}
63
64type ExecCsumChunk struct {
65	Kind  uint64
66	Value uint64
67	Size  uint64
68}
69
70func (target *Target) DeserializeExec(exec []byte) (ExecProg, error) {
71	dec := &execDecoder{target: target, data: exec}
72	dec.parse()
73	if dec.err != nil {
74		return ExecProg{}, dec.err
75	}
76	if uint64(len(dec.vars)) != dec.numVars {
77		return ExecProg{}, fmt.Errorf("mismatching number of vars: %v/%v",
78			len(dec.vars), dec.numVars)
79	}
80	p := ExecProg{
81		Calls: dec.calls,
82		Vars:  dec.vars,
83	}
84	return p, nil
85}
86
87type execDecoder struct {
88	target  *Target
89	data    []byte
90	err     error
91	numVars uint64
92	vars    []uint64
93	call    ExecCall
94	calls   []ExecCall
95}
96
97func (dec *execDecoder) parse() {
98	for dec.err == nil {
99		switch instr := dec.read(); instr {
100		case execInstrCopyin:
101			dec.commitCall()
102			dec.call.Copyin = append(dec.call.Copyin, ExecCopyin{
103				Addr: dec.read(),
104				Arg:  dec.readArg(),
105			})
106		case execInstrCopyout:
107			dec.call.Copyout = append(dec.call.Copyout, ExecCopyout{
108				Index: dec.read(),
109				Addr:  dec.read(),
110				Size:  dec.read(),
111			})
112		default:
113			dec.commitCall()
114			if instr >= uint64(len(dec.target.Syscalls)) {
115				dec.setErr(fmt.Errorf("bad syscall %v", instr))
116				return
117			}
118			dec.call.Meta = dec.target.Syscalls[instr]
119			dec.call.Index = dec.read()
120			for i := dec.read(); i > 0; i-- {
121				switch arg := dec.readArg(); arg.(type) {
122				case ExecArgConst, ExecArgResult:
123					dec.call.Args = append(dec.call.Args, arg)
124				default:
125					dec.setErr(fmt.Errorf("bad call arg %+v", arg))
126					return
127				}
128			}
129		case execInstrEOF:
130			dec.commitCall()
131			return
132		}
133	}
134}
135
136func (dec *execDecoder) readArg() ExecArg {
137	switch typ := dec.read(); typ {
138	case execArgConst:
139		meta := dec.read()
140		return ExecArgConst{
141			Value:          dec.read(),
142			Size:           meta & 0xff,
143			Format:         BinaryFormat((meta >> 8) & 0xff),
144			BitfieldOffset: (meta >> 16) & 0xff,
145			BitfieldLength: (meta >> 24) & 0xff,
146			PidStride:      meta >> 32,
147		}
148	case execArgResult:
149		meta := dec.read()
150		arg := ExecArgResult{
151			Size:    meta & 0xff,
152			Format:  BinaryFormat((meta >> 8) & 0xff),
153			Index:   dec.read(),
154			DivOp:   dec.read(),
155			AddOp:   dec.read(),
156			Default: dec.read(),
157		}
158		for uint64(len(dec.vars)) <= arg.Index {
159			dec.vars = append(dec.vars, 0)
160		}
161		dec.vars[arg.Index] = arg.Default
162		return arg
163	case execArgData:
164		return ExecArgData{
165			Data: dec.readBlob(dec.read()),
166		}
167	case execArgCsum:
168		size := dec.read()
169		switch kind := dec.read(); kind {
170		case ExecArgCsumInet:
171			chunks := make([]ExecCsumChunk, dec.read())
172			for i := range chunks {
173				chunks[i] = ExecCsumChunk{
174					Kind:  dec.read(),
175					Value: dec.read(),
176					Size:  dec.read(),
177				}
178			}
179			return ExecArgCsum{
180				Size:   size,
181				Kind:   kind,
182				Chunks: chunks,
183			}
184		default:
185			dec.setErr(fmt.Errorf("unknown csum kind %v", kind))
186			return nil
187		}
188	default:
189		dec.setErr(fmt.Errorf("bad argument type %v", typ))
190		return nil
191	}
192}
193
194func (dec *execDecoder) read() uint64 {
195	if len(dec.data) < 8 {
196		dec.setErr(fmt.Errorf("exec program overflow"))
197	}
198	if dec.err != nil {
199		return 0
200	}
201	var v uint64
202	for i := 0; i < 8; i++ {
203		v |= uint64(dec.data[i]) << uint(i*8)
204	}
205	dec.data = dec.data[8:]
206	return v
207}
208
209func (dec *execDecoder) readBlob(size uint64) []byte {
210	padded := (size + 7) / 8 * 8
211	if uint64(len(dec.data)) < padded {
212		dec.setErr(fmt.Errorf("exec program overflow"))
213	}
214	if dec.err != nil {
215		return nil
216	}
217	data := dec.data[:size]
218	dec.data = dec.data[padded:]
219	return data
220}
221
222func (dec *execDecoder) setErr(err error) {
223	if dec.err == nil {
224		dec.err = err
225	}
226}
227
228func (dec *execDecoder) commitCall() {
229	if dec.call.Meta == nil {
230		return
231	}
232	if dec.call.Index != ExecNoCopyout && dec.numVars < dec.call.Index+1 {
233		dec.numVars = dec.call.Index + 1
234	}
235	for _, copyout := range dec.call.Copyout {
236		if dec.numVars < copyout.Index+1 {
237			dec.numVars = copyout.Index + 1
238		}
239	}
240	dec.calls = append(dec.calls, dec.call)
241	dec.call = ExecCall{}
242}
243