github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/tools/syz-mutate/mutate.go (about)

     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  
     4  // mutates mutates a given program and prints result.
     5  package main
     6  
     7  import (
     8  	"flag"
     9  	"fmt"
    10  	"math/rand"
    11  	"os"
    12  	"runtime"
    13  	"strings"
    14  	"time"
    15  
    16  	"github.com/google/syzkaller/pkg/db"
    17  	"github.com/google/syzkaller/pkg/mgrconfig"
    18  	"github.com/google/syzkaller/prog"
    19  	_ "github.com/google/syzkaller/sys"
    20  )
    21  
    22  var (
    23  	flagOS       = flag.String("os", runtime.GOOS, "target os")
    24  	flagArch     = flag.String("arch", runtime.GOARCH, "target arch")
    25  	flagSeed     = flag.Int("seed", -1, "prng seed")
    26  	flagLen      = flag.Int("len", prog.RecommendedCalls, "number of calls in programs")
    27  	flagEnable   = flag.String("enable", "", "comma-separated list of enabled syscalls")
    28  	flagCorpus   = flag.String("corpus", "", "name of the corpus file")
    29  	flagHintCall = flag.Int("hint-call", -1, "mutate the specified call with hints in hint-src/cmp flags")
    30  	flagHintSrc  = flag.Uint64("hint-src", 0, "compared value in the program")
    31  	flagHintCmp  = flag.Uint64("hint-cmp", 0, "compare operand in the kernel")
    32  	flagStrict   = flag.Bool("strict", true, "parse input program in strict mode")
    33  )
    34  
    35  func main() {
    36  	flag.Parse()
    37  	target, err := prog.GetTarget(*flagOS, *flagArch)
    38  	if err != nil {
    39  		fmt.Fprintf(os.Stderr, "%v\n", err)
    40  		os.Exit(1)
    41  	}
    42  	var syscalls map[*prog.Syscall]bool
    43  	if *flagEnable != "" {
    44  		enabled := strings.Split(*flagEnable, ",")
    45  		syscallsIDs, err := mgrconfig.ParseEnabledSyscalls(target, enabled, nil)
    46  		if err != nil {
    47  			fmt.Fprintf(os.Stderr, "failed to parse enabled syscalls: %v\n", err)
    48  			os.Exit(1)
    49  		}
    50  		syscalls = make(map[*prog.Syscall]bool)
    51  		for _, id := range syscallsIDs {
    52  			syscalls[target.Syscalls[id]] = true
    53  		}
    54  		var disabled map[*prog.Syscall]string
    55  		syscalls, disabled = target.TransitivelyEnabledCalls(syscalls)
    56  		for c, reason := range disabled {
    57  			fmt.Fprintf(os.Stderr, "disabling %v: %v\n", c.Name, reason)
    58  		}
    59  	}
    60  	seed := time.Now().UnixNano()
    61  	if *flagSeed != -1 {
    62  		seed = int64(*flagSeed)
    63  	}
    64  	corpus, err := db.ReadCorpus(*flagCorpus, target)
    65  	if err != nil {
    66  		fmt.Fprintf(os.Stderr, "failed to read corpus: %v\n", err)
    67  		os.Exit(1)
    68  	}
    69  	rs := rand.NewSource(seed)
    70  	ct := target.BuildChoiceTable(corpus, syscalls)
    71  	var p *prog.Prog
    72  	if flag.NArg() == 0 {
    73  		p = target.Generate(rs, *flagLen, ct)
    74  	} else {
    75  		data, err := os.ReadFile(flag.Arg(0))
    76  		if err != nil {
    77  			fmt.Fprintf(os.Stderr, "failed to read prog file: %v\n", err)
    78  			os.Exit(1)
    79  		}
    80  		mode := prog.NonStrict
    81  		if *flagStrict {
    82  			mode = prog.Strict
    83  		}
    84  		p, err = target.Deserialize(data, mode)
    85  		if err != nil {
    86  			fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err)
    87  			os.Exit(1)
    88  		}
    89  		if *flagHintCall != -1 {
    90  			comps := make(prog.CompMap)
    91  			comps.AddComp(*flagHintSrc, *flagHintCmp)
    92  			p.MutateWithHints(*flagHintCall, comps, func(p *prog.Prog) bool {
    93  				fmt.Printf("%s\n\n", p.Serialize())
    94  				return true
    95  			})
    96  			return
    97  		} else {
    98  			p.Mutate(rs, *flagLen, ct, nil, corpus)
    99  		}
   100  	}
   101  	fmt.Printf("%s\n", p.Serialize())
   102  }