Beispiel #1
0
func main() {
	flag.Parse()
	if len(flag.Args()) != 1 {
		fmt.Fprintf(os.Stderr, "usage: syz-symbolize [flags] kernel_log_file\n")
		flag.PrintDefaults()
		os.Exit(1)
	}
	text, err := ioutil.ReadFile(flag.Args()[0])
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to open input file: %v\n", err)
		os.Exit(1)
	}
	if _, parsed, _, _ := report.Parse(text, nil); len(parsed) != 0 {
		text = parsed
	}
	text, err = report.Symbolize(filepath.Join(*flagLinux, "vmlinux"), text)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to symbolize: %v\n", err)
		os.Exit(1)
	}
	os.Stdout.Write(text)
}
Beispiel #2
0
func main() {
	if len(os.Args) != 3 {
		fmt.Fprintf(os.Stderr, "usage: syz-report vmlinux report (args %+v)\n", os.Args)
		os.Exit(1)
	}
	output, err := ioutil.ReadFile(os.Args[2])
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to read report file: %v\n", err)
		os.Exit(1)
	}
	desc, text, _, _ := report.Parse(output)
	if desc == "" {
		fmt.Fprintf(os.Stderr, "report file does not contain a crash\n")
		os.Exit(1)
	}
	symbolized, err := report.Symbolize(os.Args[1], text)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to symbolize report: %v\n", err)
	} else {
		text = symbolized
	}
	fmt.Printf("%v\n\n%s", desc, text)
}
Beispiel #3
0
func Run(crashLog []byte, cfg *config.Config, vmIndexes []int) (*Result, error) {
	if len(vmIndexes) == 0 {
		return nil, fmt.Errorf("no VMs provided")
	}
	if _, err := os.Stat(filepath.Join(cfg.Syzkaller, "bin/syz-execprog")); err != nil {
		return nil, fmt.Errorf("bin/syz-execprog is missing (run 'make execprog')")
	}
	entries := prog.ParseLog(crashLog)
	if len(entries) == 0 {
		return nil, fmt.Errorf("crash log does not contain any programs")
	}
	crashDesc, _, crashStart, _ := report.Parse(crashLog, cfg.ParsedIgnores)
	if crashDesc == "" {
		crashStart = len(crashLog) // assuming VM hanged
		crashDesc = "hang"
	}
	Logf(0, "reproducing crash '%v': %v programs, %v VMs", crashDesc, len(entries), len(vmIndexes))

	ctx := &context{
		cfg:          cfg,
		crashDesc:    crashDesc,
		instances:    make(chan *instance, len(vmIndexes)),
		bootRequests: make(chan int, len(vmIndexes)),
	}
	var wg sync.WaitGroup
	wg.Add(len(vmIndexes))
	for _, vmIndex := range vmIndexes {
		ctx.bootRequests <- vmIndex
		go func() {
			defer wg.Done()
			for vmIndex := range ctx.bootRequests {
				var inst *instance
				for try := 0; try < 3; try++ {
					vmCfg, err := config.CreateVMConfig(cfg, vmIndex)
					if err != nil {
						Logf(0, "reproducing crash '%v': failed to create VM config: %v", crashDesc, err)
						time.Sleep(10 * time.Second)
						continue
					}
					vmInst, err := vm.Create(cfg.Type, vmCfg)
					if err != nil {
						Logf(0, "reproducing crash '%v': failed to create VM: %v", crashDesc, err)
						time.Sleep(10 * time.Second)
						continue

					}
					execprogBin, err := vmInst.Copy(filepath.Join(cfg.Syzkaller, "bin/syz-execprog"))
					if err != nil {
						Logf(0, "reproducing crash '%v': failed to copy to VM: %v", crashDesc, err)
						vmInst.Close()
						time.Sleep(10 * time.Second)
						continue
					}
					executorBin, err := vmInst.Copy(filepath.Join(cfg.Syzkaller, "bin/syz-executor"))
					if err != nil {
						Logf(0, "reproducing crash '%v': failed to copy to VM: %v", crashDesc, err)
						vmInst.Close()
						time.Sleep(10 * time.Second)
						continue
					}
					inst = &instance{vmInst, vmIndex, execprogBin, executorBin}
					break
				}
				if inst == nil {
					break
				}
				ctx.instances <- inst
			}
		}()
	}
	go func() {
		wg.Wait()
		close(ctx.instances)
	}()

	res, err := ctx.repro(entries, crashStart)

	close(ctx.bootRequests)
	for inst := range ctx.instances {
		inst.Close()
	}
	return res, err
}
Beispiel #4
0
func main() {
	flag.Parse()
	cfg, _, _, err := config.Parse(*flagConfig)
	if err != nil {
		Fatalf("%v", err)
	}
	if *flagCount > 0 {
		cfg.Count = *flagCount
	}
	if _, err := os.Stat(filepath.Join(cfg.Syzkaller, "bin/syz-execprog")); err != nil {
		Fatalf("bin/syz-execprog is missing (run 'make execprog')")
	}

	if len(flag.Args()) != 1 {
		Fatalf("usage: syz-repro -config=config.file execution.log")
	}
	data, err := ioutil.ReadFile(flag.Args()[0])
	if err != nil {
		Fatalf("failed to open log file: %v", err)
	}
	entries := prog.ParseLog(data)
	Logf(0, "parsed %v programs", len(entries))

	crashDesc, _, crashStart, _ := report.Parse(data)
	if crashDesc == "" {
		crashStart = len(data) // assuming VM hanged
	}

	instances = make(chan VM, cfg.Count)
	bootRequests = make(chan int, cfg.Count)
	for i := 0; i < cfg.Count; i++ {
		bootRequests <- i
		go func() {
			for index := range bootRequests {
				vmCfg, err := config.CreateVMConfig(cfg, index)
				if err != nil {
					Fatalf("failed to create VM config: %v", err)
				}
				inst, err := vm.Create(cfg.Type, vmCfg)
				if err != nil {
					Fatalf("failed to create VM: %v", err)
				}
				execprogBin, err := inst.Copy(filepath.Join(cfg.Syzkaller, "bin/syz-execprog"))
				if err != nil {
					Fatalf("failed to copy to VM: %v", err)
				}
				executorBin, err := inst.Copy(filepath.Join(cfg.Syzkaller, "bin/syz-executor"))
				if err != nil {
					Fatalf("failed to copy to VM: %v", err)
				}
				instances <- VM{inst, index, execprogBin, executorBin}
			}
		}()
	}

	go func() {
		c := make(chan os.Signal, 2)
		signal.Notify(c, syscall.SIGINT)
		<-c
		close(shutdown)
		Logf(-1, "shutting down...")
		<-c
		Fatalf("terminating")
	}()

	repro(cfg, entries, crashStart)
	exit()
}
Beispiel #5
0
func MonitorExecution(outc <-chan []byte, errc <-chan error, local, needOutput bool) (desc string, text, output []byte, crashed, timedout bool) {
	waitForOutput := func() {
		dur := time.Second
		if needOutput {
			dur = 10 * time.Second
		}
		timer := time.NewTimer(dur).C
		for {
			select {
			case out, ok := <-outc:
				if !ok {
					return
				}
				output = append(output, out...)
			case <-timer:
				return
			}
		}
	}

	matchPos := 0
	const (
		beforeContext = 256 << 10
		afterContext  = 128 << 10
	)
	extractError := func(defaultError string) (string, []byte, []byte, bool, bool) {
		// Give it some time to finish writing the error message.
		waitForOutput()
		if !report.ContainsCrash(output[matchPos:]) {
			return defaultError, nil, output, true, false
		}
		desc, text, start, end := report.Parse(output[matchPos:])
		start = start + matchPos - beforeContext
		if start < 0 {
			start = 0
		}
		end = end + matchPos + afterContext
		if end > len(output) {
			end = len(output)
		}
		return desc, text, output[start:end], true, false
	}

	lastExecuteTime := time.Now()
	ticker := time.NewTimer(3 * time.Minute)
	tickerFired := false
	for {
		if !tickerFired && !ticker.Stop() {
			<-ticker.C
		}
		tickerFired = false
		ticker.Reset(3 * time.Minute)
		select {
		case err := <-errc:
			switch err {
			case nil:
				waitForOutput()
				return "", nil, output, false, false
			case TimeoutErr:
				return err.Error(), nil, nil, false, true
			default:
				// Note: connection lost can race with a kernel oops message.
				// In such case we want to return the kernel oops.
				return extractError("lost connection to test machine")
			}
		case out := <-outc:
			output = append(output, out...)
			if bytes.Index(output[matchPos:], []byte("executing program")) != -1 { // syz-fuzzer output
				lastExecuteTime = time.Now()
			}
			if bytes.Index(output[matchPos:], []byte("executed programs:")) != -1 { // syz-execprog output
				lastExecuteTime = time.Now()
			}
			if report.ContainsCrash(output[matchPos:]) {
				return extractError("")
			}
			if len(output) > 2*beforeContext {
				copy(output, output[len(output)-beforeContext:])
				output = output[:beforeContext]
			}
			matchPos = len(output) - 128
			if matchPos < 0 {
				matchPos = 0
			}
			// In some cases kernel constantly prints something to console,
			// but fuzzer is not actually executing programs.
			if !local && time.Since(lastExecuteTime) > 3*time.Minute {
				return "test machine is not executing programs", nil, output, true, false
			}
		case <-ticker.C:
			tickerFired = true
			if !local {
				return "no output from test machine", nil, output, true, false
			}
		case <-Shutdown:
			return "", nil, nil, false, false
		}
	}
}