• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2016 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	"bytes"
8	"encoding/binary"
9	"fmt"
10	"reflect"
11	"testing"
12)
13
14func TestSerializeForExecRandom(t *testing.T) {
15	target, rs, iters := initTest(t)
16	buf := make([]byte, ExecBufferSize)
17	for i := 0; i < iters; i++ {
18		p := target.Generate(rs, 10, nil)
19		n, err := p.SerializeForExec(buf)
20		if err != nil {
21			t.Fatalf("failed to serialize: %v", err)
22		}
23		_, err = target.DeserializeExec(buf[:n])
24		if err != nil {
25			t.Fatal(err)
26		}
27	}
28}
29
30func TestSerializeForExec(t *testing.T) {
31	target := initTargetTest(t, "test", "64")
32	var (
33		dataOffset = target.DataOffset
34		ptrSize    = target.PtrSize
35	)
36	callID := func(name string) uint64 {
37		c := target.SyscallMap[name]
38		if c == nil {
39			t.Fatalf("unknown syscall %v", name)
40		}
41		return uint64(c.ID)
42	}
43	tests := []struct {
44		prog       string
45		serialized []uint64
46		decoded    *ExecProg
47	}{
48		{
49			"test()",
50			[]uint64{
51				callID("test"), ExecNoCopyout, 0,
52				execInstrEOF,
53			},
54			&ExecProg{
55				Calls: []ExecCall{
56					{
57						Meta:  target.SyscallMap["test"],
58						Index: ExecNoCopyout,
59					},
60				},
61			},
62		},
63		{
64			"test$int(0x1, 0x2, 0x3, 0x4, 0x5)",
65			[]uint64{
66				callID("test$int"), ExecNoCopyout, 5,
67				execArgConst, 8, 1,
68				execArgConst, 1, 2,
69				execArgConst, 2, 3,
70				execArgConst, 4, 4,
71				execArgConst, 8, 5,
72				execInstrEOF,
73			},
74			nil,
75		},
76		{
77			"test$align0(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})",
78			[]uint64{
79				execInstrCopyin, dataOffset + 0, execArgConst, 2, 1,
80				execInstrCopyin, dataOffset + 4, execArgConst, 4, 2,
81				execInstrCopyin, dataOffset + 8, execArgConst, 1, 3,
82				execInstrCopyin, dataOffset + 10, execArgConst, 2, 4,
83				execInstrCopyin, dataOffset + 16, execArgConst, 8, 5,
84				callID("test$align0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
85				execInstrEOF,
86			},
87			nil,
88		},
89		{
90			"test$align1(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})",
91			[]uint64{
92				execInstrCopyin, dataOffset + 0, execArgConst, 2, 1,
93				execInstrCopyin, dataOffset + 2, execArgConst, 4, 2,
94				execInstrCopyin, dataOffset + 6, execArgConst, 1, 3,
95				execInstrCopyin, dataOffset + 7, execArgConst, 2, 4,
96				execInstrCopyin, dataOffset + 9, execArgConst, 8, 5,
97				callID("test$align1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
98				execInstrEOF,
99			},
100			nil,
101		},
102		{
103			"test$align2(&(0x7f0000000000)={0x42, {[0x43]}, {[0x44]}})",
104			[]uint64{
105				execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
106				execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x43,
107				execInstrCopyin, dataOffset + 4, execArgConst, 2, 0x44,
108				callID("test$align2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
109				execInstrEOF,
110			},
111			nil,
112		},
113		{
114			"test$align3(&(0x7f0000000000)={0x42, {0x43}, {0x44}})",
115			[]uint64{
116				execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
117				execInstrCopyin, dataOffset + 1, execArgConst, 1, 0x43,
118				execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x44,
119				callID("test$align3"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
120				execInstrEOF,
121			},
122			nil,
123		},
124		{
125			"test$align4(&(0x7f0000000000)={{0x42, 0x43}, 0x44})",
126			[]uint64{
127				execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
128				execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x43,
129				execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x44,
130				callID("test$align4"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
131				execInstrEOF,
132			},
133			nil,
134		},
135		{
136			"test$align5(&(0x7f0000000000)={{0x42, []}, {0x43, [0x44, 0x45, 0x46]}, 0x47})",
137			[]uint64{
138				execInstrCopyin, dataOffset + 0, execArgConst, 8, 0x42,
139				execInstrCopyin, dataOffset + 8, execArgConst, 8, 0x43,
140				execInstrCopyin, dataOffset + 16, execArgConst, 2, 0x44,
141				execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x45,
142				execInstrCopyin, dataOffset + 20, execArgConst, 2, 0x46,
143				execInstrCopyin, dataOffset + 22, execArgConst, 1, 0x47,
144				callID("test$align5"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
145				execInstrEOF,
146			},
147			nil,
148		},
149		{
150			"test$align6(&(0x7f0000000000)={0x42, [0x43]})",
151			[]uint64{
152				execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
153				execInstrCopyin, dataOffset + 4, execArgConst, 4, 0x43,
154				callID("test$align6"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
155				execInstrEOF,
156			},
157			nil,
158		},
159		{
160			"test$union0(&(0x7f0000000000)={0x1, @f2=0x2})",
161			[]uint64{
162				execInstrCopyin, dataOffset + 0, execArgConst, 8, 1,
163				execInstrCopyin, dataOffset + 8, execArgConst, 1, 2,
164				callID("test$union0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
165				execInstrEOF,
166			},
167			nil,
168		},
169		{
170			"test$union1(&(0x7f0000000000)={@f1=0x42, 0x43})",
171			[]uint64{
172				execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42,
173				execInstrCopyin, dataOffset + 8, execArgConst, 1, 0x43,
174				callID("test$union1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
175				execInstrEOF,
176			},
177			nil,
178		},
179		{
180			"test$union2(&(0x7f0000000000)={@f1=0x42, 0x43})",
181			[]uint64{
182				execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42,
183				execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x43,
184				callID("test$union2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
185				execInstrEOF,
186			},
187			nil,
188		},
189		{
190			"test$array0(&(0x7f0000000000)={0x1, [@f0=0x2, @f1=0x3], 0x4})",
191			[]uint64{
192				execInstrCopyin, dataOffset + 0, execArgConst, 1, 1,
193				execInstrCopyin, dataOffset + 1, execArgConst, 2, 2,
194				execInstrCopyin, dataOffset + 3, execArgConst, 8, 3,
195				execInstrCopyin, dataOffset + 11, execArgConst, 8, 4,
196				callID("test$array0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
197				execInstrEOF,
198			},
199			nil,
200		},
201		{
202			"test$array1(&(0x7f0000000000)={0x42, \"0102030405\"})",
203			[]uint64{
204				execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
205				execInstrCopyin, dataOffset + 1, execArgData, 5, 0x0504030201,
206				callID("test$array1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
207				execInstrEOF,
208			},
209			nil,
210		},
211		{
212			"test$array2(&(0x7f0000000000)={0x42, \"aaaaaaaabbbbbbbbccccccccdddddddd\", 0x43})",
213			[]uint64{
214				execInstrCopyin, dataOffset + 0, execArgConst, 2, 0x42,
215				execInstrCopyin, dataOffset + 2, execArgData, 16, 0xbbbbbbbbaaaaaaaa, 0xddddddddcccccccc,
216				execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x43,
217				callID("test$array2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
218				execInstrEOF,
219			},
220			nil,
221		},
222		{
223			"test$end0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42})",
224			[]uint64{
225				execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
226				execInstrCopyin, dataOffset + 1, execArgConst, 2 | 1<<8, 0x42,
227				execInstrCopyin, dataOffset + 3, execArgConst, 4 | 1<<8, 0x42,
228				execInstrCopyin, dataOffset + 7, execArgConst, 8 | 1<<8, 0x42,
229				callID("test$end0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
230				execInstrEOF,
231			},
232			nil,
233		},
234		{
235			"test$end1(&(0x7f0000000000)={0xe, 0x42, 0x1})",
236			[]uint64{
237				execInstrCopyin, dataOffset + 0, execArgConst, 2 | 1<<8, 0xe,
238				execInstrCopyin, dataOffset + 2, execArgConst, 4 | 1<<8, 0x42,
239				execInstrCopyin, dataOffset + 6, execArgConst, 8 | 1<<8, 0x1,
240				callID("test$end1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
241				execInstrEOF,
242			},
243			nil,
244		},
245		{
246			"test$bf0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42})",
247			[]uint64{
248				execInstrCopyin, dataOffset + 0, execArgConst, 2 | 0<<16 | 10<<24, 0x42,
249				execInstrCopyin, dataOffset + 8, execArgConst, 8, 0x42,
250				execInstrCopyin, dataOffset + 16, execArgConst, 2 | 0<<16 | 5<<24, 0x42,
251				execInstrCopyin, dataOffset + 16, execArgConst, 2 | 5<<16 | 6<<24, 0x42,
252				execInstrCopyin, dataOffset + 20, execArgConst, 4 | 0<<16 | 15<<24, 0x42,
253				execInstrCopyin, dataOffset + 24, execArgConst, 2 | 0<<16 | 11<<24, 0x42,
254				execInstrCopyin, dataOffset + 26, execArgConst, 2 | 1<<8 | 0<<16 | 11<<24, 0x42,
255				execInstrCopyin, dataOffset + 28, execArgConst, 1, 0x42,
256				callID("test$bf0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
257				execInstrEOF,
258			},
259			&ExecProg{
260				Calls: []ExecCall{
261					{
262						Meta:  target.SyscallMap["test$bf0"],
263						Index: ExecNoCopyout,
264						Args: []ExecArg{
265							ExecArgConst{
266								Size:  ptrSize,
267								Value: dataOffset,
268							},
269						},
270						Copyin: []ExecCopyin{
271							{
272								Addr: dataOffset + 0,
273								Arg: ExecArgConst{
274									Size:           2,
275									Value:          0x42,
276									BitfieldOffset: 0,
277									BitfieldLength: 10,
278								},
279							},
280							{
281								Addr: dataOffset + 8,
282								Arg: ExecArgConst{
283									Size:  8,
284									Value: 0x42,
285								},
286							},
287							{
288								Addr: dataOffset + 16,
289								Arg: ExecArgConst{
290									Size:           2,
291									Value:          0x42,
292									BitfieldOffset: 0,
293									BitfieldLength: 5,
294								},
295							},
296							{
297								Addr: dataOffset + 16,
298								Arg: ExecArgConst{
299									Size:           2,
300									Value:          0x42,
301									BitfieldOffset: 5,
302									BitfieldLength: 6,
303								},
304							},
305							{
306								Addr: dataOffset + 20,
307								Arg: ExecArgConst{
308									Size:           4,
309									Value:          0x42,
310									BitfieldOffset: 0,
311									BitfieldLength: 15,
312								},
313							},
314							{
315								Addr: dataOffset + 24,
316								Arg: ExecArgConst{
317									Size:           2,
318									Value:          0x42,
319									BitfieldOffset: 0,
320									BitfieldLength: 11,
321								},
322							},
323							{
324								Addr: dataOffset + 26,
325								Arg: ExecArgConst{
326									Size:           2,
327									Format:         FormatBigEndian,
328									Value:          0x42,
329									BitfieldOffset: 0,
330									BitfieldLength: 11,
331								},
332							},
333							{
334								Addr: dataOffset + 28,
335								Arg: ExecArgConst{
336									Size:  1,
337									Value: 0x42,
338								},
339							},
340						},
341					},
342				},
343			},
344		},
345		{
346			"test$bf1(&(0x7f0000000000)={{0x42, 0x42, 0x42}, 0x42})",
347			[]uint64{
348				execInstrCopyin, dataOffset + 0, execArgConst, 4 | 0<<16 | 10<<24, 0x42,
349				execInstrCopyin, dataOffset + 0, execArgConst, 4 | 10<<16 | 10<<24, 0x42,
350				execInstrCopyin, dataOffset + 0, execArgConst, 4 | 20<<16 | 10<<24, 0x42,
351				execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x42,
352				callID("test$bf1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
353				execInstrEOF,
354			},
355			nil,
356		},
357		{
358			"test$res1(0xffff)",
359			[]uint64{
360				callID("test$res1"), ExecNoCopyout, 1, execArgConst, 4, 0xffff,
361				execInstrEOF,
362			},
363			nil,
364		},
365		{
366			"test$opt3(0x0)",
367			[]uint64{
368				callID("test$opt3"), ExecNoCopyout, 1, execArgConst, 8 | 4<<32, 0x64,
369				execInstrEOF,
370			},
371			nil,
372		},
373		{
374			// Special value that translates to 0 for all procs.
375			"test$opt3(0xffffffffffffffff)",
376			[]uint64{
377				callID("test$opt3"), ExecNoCopyout, 1, execArgConst, 8, 0,
378				execInstrEOF,
379			},
380			nil,
381		},
382		{
383			// NULL pointer must be encoded os 0.
384			"test$opt1(0x0)",
385			[]uint64{
386				callID("test$opt1"), ExecNoCopyout, 1, execArgConst, 8, 0,
387				execInstrEOF,
388			},
389			nil,
390		},
391		{
392			"test$align7(&(0x7f0000000000)={{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}, 0x42})",
393			[]uint64{
394				execInstrCopyin, dataOffset + 0, execArgConst, 1 | 0<<16 | 1<<24, 0x1,
395				execInstrCopyin, dataOffset + 0, execArgConst, 1 | 1<<16 | 1<<24, 0x2,
396				execInstrCopyin, dataOffset + 0, execArgConst, 1 | 2<<16 | 1<<24, 0x3,
397				execInstrCopyin, dataOffset + 1, execArgConst, 2 | 0<<16 | 1<<24, 0x4,
398				execInstrCopyin, dataOffset + 1, execArgConst, 2 | 1<<16 | 1<<24, 0x5,
399				execInstrCopyin, dataOffset + 1, execArgConst, 2 | 2<<16 | 1<<24, 0x6,
400				execInstrCopyin, dataOffset + 8, execArgConst, 1, 0x42,
401				callID("test$align7"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
402				execInstrEOF,
403			},
404			nil,
405		},
406	}
407
408	buf := make([]byte, ExecBufferSize)
409	for i, test := range tests {
410		i, test := i, test
411		t.Run(fmt.Sprintf("%v:%v", i, test.prog), func(t *testing.T) {
412			p, err := target.Deserialize([]byte(test.prog))
413			if err != nil {
414				t.Fatalf("failed to deserialize prog %v: %v", i, err)
415			}
416			n, err := p.SerializeForExec(buf)
417			if err != nil {
418				t.Fatalf("failed to serialize: %v", err)
419			}
420			w := new(bytes.Buffer)
421			binary.Write(w, binary.LittleEndian, test.serialized)
422			data := buf[:n]
423			if !bytes.Equal(data, w.Bytes()) {
424				got := make([]uint64, len(data)/8)
425				binary.Read(bytes.NewReader(data), binary.LittleEndian, &got)
426				t.Logf("want: %v", test.serialized)
427				t.Logf("got:  %v", got)
428				t.Fatalf("mismatch")
429			}
430			decoded, err := target.DeserializeExec(data)
431			if err != nil {
432				t.Fatal(err)
433			}
434			if test.decoded != nil && !reflect.DeepEqual(decoded, *test.decoded) {
435				t.Logf("want: %#v", *test.decoded)
436				t.Logf("got:  %#v", decoded)
437				t.Fatalf("decoded mismatch")
438			}
439		})
440	}
441}
442