aboutsummaryrefslogtreecommitdiffstats
path: root/tools/syz-mutate/mutate.go
blob: aa812a447d70c520feaba63aac1d320916e46f4c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// mutates mutates a given program and prints result.
package main

import (
	"flag"
	"fmt"
	"math/rand"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/google/syzkaller/pkg/db"
	"github.com/google/syzkaller/pkg/mgrconfig"
	"github.com/google/syzkaller/prog"
	_ "github.com/google/syzkaller/sys"
)

var (
	flagOS       = flag.String("os", runtime.GOOS, "target os")
	flagArch     = flag.String("arch", runtime.GOARCH, "target arch")
	flagSeed     = flag.Int("seed", -1, "prng seed")
	flagLen      = flag.Int("len", prog.RecommendedCalls, "number of calls in programs")
	flagEnable   = flag.String("enable", "", "comma-separated list of enabled syscalls")
	flagCorpus   = flag.String("corpus", "", "name of the corpus file")
	flagHintCall = flag.Int("hint-call", -1, "mutate the specified call with hints in hint-src/cmp flags")
	flagHintSrc  = flag.Uint64("hint-src", 0, "compared value in the program")
	flagHintCmp  = flag.Uint64("hint-cmp", 0, "compare operand in the kernel")
	flagStrict   = flag.Bool("strict", true, "parse input program in strict mode")
)

func main() {
	flag.Parse()
	target, err := prog.GetTarget(*flagOS, *flagArch)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
	var syscalls map[*prog.Syscall]bool
	if *flagEnable != "" {
		enabled := strings.Split(*flagEnable, ",")
		syscallsIDs, err := mgrconfig.ParseEnabledSyscalls(target, enabled, nil, mgrconfig.AnyDescriptions)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to parse enabled syscalls: %v\n", err)
			os.Exit(1)
		}
		syscalls = make(map[*prog.Syscall]bool)
		for _, id := range syscallsIDs {
			syscalls[target.Syscalls[id]] = true
		}
		var disabled map[*prog.Syscall]string
		syscalls, disabled = target.TransitivelyEnabledCalls(syscalls)
		for c, reason := range disabled {
			fmt.Fprintf(os.Stderr, "disabling %v: %v\n", c.Name, reason)
		}
	}
	seed := time.Now().UnixNano()
	if *flagSeed != -1 {
		seed = int64(*flagSeed)
	}
	corpus, err := db.ReadCorpus(*flagCorpus, target)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to read corpus: %v\n", err)
		os.Exit(1)
	}
	rs := rand.NewSource(seed)
	ct := target.BuildChoiceTable(corpus, syscalls)
	var p *prog.Prog
	if flag.NArg() == 0 {
		p = target.Generate(rs, *flagLen, ct)
	} else {
		data, err := os.ReadFile(flag.Arg(0))
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to read prog file: %v\n", err)
			os.Exit(1)
		}
		mode := prog.NonStrict
		if *flagStrict {
			mode = prog.Strict
		}
		p, err = target.Deserialize(data, mode)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err)
			os.Exit(1)
		}
		if *flagHintCall != -1 {
			comps := make(prog.CompMap)
			comps.Add(0, *flagHintSrc, *flagHintCmp, true)
			p.MutateWithHints(*flagHintCall, comps, func(p *prog.Prog) bool {
				fmt.Printf("%s\n\n", p.Serialize())
				return true
			})
			return
		} else {
			p.Mutate(rs, *flagLen, ct, nil, corpus)
		}
	}
	fmt.Printf("%s\n", p.Serialize())
}