Beispiel #1
0
func addInput(inp RpcInput) {
	corpusMu.Lock()
	defer corpusMu.Unlock()
	coverMu.Lock()
	defer coverMu.Unlock()

	if noCover {
		panic("should not be called when coverage is disabled")
	}
	p, err := prog.Deserialize(inp.Prog)
	if err != nil {
		panic(err)
	}
	if inp.CallIndex < 0 || inp.CallIndex >= len(p.Calls) {
		panic("bad call index")
	}
	call := p.Calls[inp.CallIndex].Meta
	sig := hash(inp.Prog)
	if _, ok := corpusHashes[sig]; ok {
		return
	}
	cov := cover.Canonicalize(inp.Cover)
	diff := cover.Difference(cov, maxCover[call.CallID])
	diff = cover.Difference(diff, flakes)
	if len(diff) == 0 {
		return
	}
	corpus = append(corpus, p)
	corpusCover[call.CallID] = cover.Union(corpusCover[call.CallID], cov)
	maxCover[call.CallID] = cover.Union(maxCover[call.CallID], cov)
	corpusHashes[hash(inp.Prog)] = struct{}{}
}
Beispiel #2
0
func addInput(inp RpcInput) {
	p, err := prog.Deserialize(inp.Prog)
	if err != nil {
		panic(err)
	}
	if inp.CallIndex < 0 || inp.CallIndex >= len(p.Calls) {
		panic("bad call index")
	}
	call := p.Calls[inp.CallIndex].Meta
	sig := hash(inp.Prog)
	if _, ok := corpusHashes[sig]; ok {
		return
	}
	cov := cover.Canonicalize(inp.Cover)
	diff := cover.Difference(cov, maxCover[call.CallID])
	diff = cover.Difference(diff, flakes)
	if len(diff) == 0 {
		return
	}
	inp1 := Input{p, inp.CallIndex, cov}
	corpus = append(corpus, inp1)
	corpusCover[call.CallID] = cover.Union(corpusCover[call.CallID], cov)
	maxCover[call.CallID] = cover.Union(maxCover[call.CallID], cov)
	corpusHashes[hash(inp.Prog)] = struct{}{}
}
Beispiel #3
0
func triageInput(env *ipc.Env, inp Input) {
	if *flagNoCover {
		panic("should not be called when coverage is disabled")
	}
	call := inp.p.Calls[inp.call].Meta
	newCover := cover.Difference(inp.cover, corpusCover[call.CallID])
	newCover = cover.Difference(newCover, flakes)
	if len(newCover) == 0 {
		return
	}

	if _, ok := corpusHashes[hash(inp.p.Serialize())]; ok {
		return
	}

	minCover := inp.cover
	for i := 0; i < 3; i++ {
		allCover := execute1(env, inp.p, &statExecTriage)
		if len(allCover[inp.call]) == 0 {
			// The call was not executed. Happens sometimes, reason unknown.
			continue
		}
		cov := allCover[inp.call]
		diff := cover.SymmetricDifference(inp.cover, cov)
		if len(diff) != 0 {
			flakes = cover.Union(flakes, diff)
		}
		minCover = cover.Intersection(minCover, cov)
	}
	stableNewCover := cover.Intersection(newCover, minCover)
	if len(stableNewCover) == 0 {
		return
	}
	inp.p, inp.call = prog.Minimize(inp.p, inp.call, func(p1 *prog.Prog, call1 int) bool {
		allCover := execute1(env, p1, &statExecMinimize)
		if len(allCover[call1]) == 0 {
			return false // The call was not executed.
		}
		cov := allCover[call1]
		if len(cover.Intersection(stableNewCover, cov)) != len(stableNewCover) {
			return false
		}
		minCover = cover.Intersection(minCover, cov)
		return true
	})
	inp.cover = minCover
	corpusCover[call.CallID] = cover.Union(corpusCover[call.CallID], minCover)
	corpus = append(corpus, inp)
	data := inp.p.Serialize()
	corpusHashes[hash(data)] = struct{}{}

	logf(2, "added new input for %v to corpus:\n%s", call.CallName, data)

	statNewInput++
	a := &NewManagerInputArgs{*flagName, RpcInput{call.CallName, inp.p.Serialize(), inp.call, []uint32(inp.cover)}}
	if err := manager.Call("Manager.NewInput", a, nil); err != nil {
		panic(err)
	}
}
Beispiel #4
0
func (mgr *Manager) httpInfo(w http.ResponseWriter, r *http.Request) {
	mgr.mu.Lock()
	defer mgr.mu.Unlock()

	uptime := time.Since(mgr.startTime)
	data := &UIData{
		CorpusSize:  len(mgr.corpus),
		TriageQueue: len(mgr.candidates),
		Uptime:      fmt.Sprintf("%v", uptime),
	}

	type CallCov struct {
		count int
		cov   cover.Cover
	}
	calls := make(map[string]*CallCov)
	for _, inp := range mgr.corpus {
		if calls[inp.Call] == nil {
			calls[inp.Call] = new(CallCov)
		}
		cc := calls[inp.Call]
		cc.count++
		cc.cov = cover.Union(cc.cov, cover.Cover(inp.Cover))
		data.CorpusCoverMem += len(inp.Cover) * int(unsafe.Sizeof(inp.Cover[0]))
	}
	for _, cov := range mgr.corpusCover {
		data.CallCoverMem += len(cov) * int(unsafe.Sizeof(cov[0]))
	}

	secs := uint64(uptime) / 1e9
	for k, v := range mgr.stats {
		val := ""
		if x := v / secs; x >= 10 {
			val = fmt.Sprintf("%v/sec", x)
		} else if x := v * 60 / secs; x >= 10 {
			val = fmt.Sprintf("%v/min", x)
		} else {
			x := v * 60 * 60 / secs
			val = fmt.Sprintf("%v/hour", x)
		}
		data.Stats = append(data.Stats, UIStat{Name: k, Value: val})
	}
	sort.Sort(UIStatArray(data.Stats))

	var cov cover.Cover
	for c, cc := range calls {
		cov = cover.Union(cov, cc.cov)
		data.Calls = append(data.Calls, UICallType{c, cc.count, len(cc.cov)})
	}
	sort.Sort(UICallTypeArray(data.Calls))
	data.CoverSize = len(cov)

	if err := htmlTemplate.Execute(w, data); err != nil {
		http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError)
	}
}
Beispiel #5
0
func execute(pid int, env *ipc.Env, p *prog.Prog, stat *uint64) {
	allCover := execute1(pid, env, p, stat)
	coverMu.RLock()
	defer coverMu.RUnlock()
	for i, cov := range allCover {
		if len(cov) == 0 {
			continue
		}
		c := p.Calls[i].Meta
		diff := cover.Difference(cov, maxCover[c.CallID])
		diff = cover.Difference(diff, flakes)
		if len(diff) != 0 {
			coverMu.RUnlock()
			coverMu.Lock()
			maxCover[c.CallID] = cover.Union(maxCover[c.CallID], diff)
			coverMu.Unlock()
			coverMu.RLock()

			inp := Input{p.Clone(), i, cover.Copy(cov)}
			triageMu.Lock()
			triage = append(triage, inp)
			triageMu.Unlock()
		}
	}
}
Beispiel #6
0
func (mgr *Manager) NewInput(a *NewManagerInputArgs, r *int) error {
	logf(2, "new input from fuzzer %v", a.Name)
	mgr.mu.Lock()
	defer mgr.mu.Unlock()

	call := sys.CallID[a.Call]
	if len(cover.Difference(a.Cover, mgr.corpusCover[call])) == 0 {
		return nil
	}
	mgr.corpusCover[call] = cover.Union(mgr.corpusCover[call], a.Cover)
	mgr.corpus = append(mgr.corpus, a.RpcInput)
	mgr.stats["manager new inputs"]++

	sig := hash(a.Prog)
	if _, ok := mgr.masterHashes[sig]; !ok {
		mgr.masterHashes[sig] = struct{}{}
		mgr.masterCorpus = append(mgr.masterCorpus, a.Prog)

		a1 := &NewMasterInputArgs{mgr.cfg.Name, a.Prog}
		if err := mgr.master.Call("Master.NewInput", a1, nil); err != nil {
			fatalf("call Master.NewInput failed: %v", err)
		}
	}

	return nil
}
Beispiel #7
0
func (mgr *Manager) NewInput(a *NewInputArgs, r *int) error {
	Logf(2, "new input from %v for syscall %v", a.Name, a.Call)
	mgr.mu.Lock()
	defer mgr.mu.Unlock()

	f := mgr.fuzzers[a.Name]
	if f == nil {
		Fatalf("fuzzer %v is not connected", a.Name)
	}

	call := sys.CallID[a.Call]
	if len(cover.Difference(a.Cover, mgr.corpusCover[call])) == 0 {
		return nil
	}
	mgr.corpusCover[call] = cover.Union(mgr.corpusCover[call], a.Cover)
	mgr.corpus = append(mgr.corpus, a.RpcInput)
	mgr.stats["manager new inputs"]++
	mgr.persistentCorpus.add(a.RpcInput.Prog)
	for _, f1 := range mgr.fuzzers {
		if f1 == f {
			continue
		}
		f1.inputs = append(f1.inputs, a.RpcInput)
	}
	return nil
}
Beispiel #8
0
func (mgr *Manager) httpCover(w http.ResponseWriter, r *http.Request) {
	mgr.mu.Lock()
	defer mgr.mu.Unlock()

	var cov cover.Cover
	call := r.FormValue("call")
	unique := r.FormValue("unique") != "" && call != ""
	perCall := false
	if n, err := strconv.Atoi(call); err == nil && n < len(mgr.corpus) {
		cov = mgr.corpus[n].Cover
	} else {
		perCall = true
		for _, inp := range mgr.corpus {
			if call == "" || call == inp.Call {
				cov = cover.Union(cov, cover.Cover(inp.Cover))
			}
		}
	}
	if unique {
		cov = cover.Intersection(cov, mgr.uniqueCover(perCall))
	}

	if err := generateCoverHtml(w, mgr.cfg.Vmlinux, cov); err != nil {
		http.Error(w, fmt.Sprintf("failed to generate coverage profile: %v", err), http.StatusInternalServerError)
		return
	}
	runtime.GC()
}
Beispiel #9
0
func (mgr *Manager) httpInfo(w http.ResponseWriter, r *http.Request) {
	mgr.mu.Lock()
	defer mgr.mu.Unlock()

	type CallCov struct {
		count int
		cov   cover.Cover
	}
	calls := make(map[string]*CallCov)
	for _, inp := range mgr.corpus {
		if calls[inp.Call] == nil {
			calls[inp.Call] = new(CallCov)
		}
		cc := calls[inp.Call]
		cc.count++
		cc.cov = cover.Union(cc.cov, cover.Cover(inp.Cover))
	}

	data := &UIData{
		Name:             mgr.cfg.Name,
		MasterHttp:       mgr.masterHttp,
		MasterCorpusSize: len(mgr.masterCorpus),
		CorpusSize:       len(mgr.corpus),
	}

	var cov cover.Cover
	for c, cc := range calls {
		cov = cover.Union(cov, cc.cov)
		data.Calls = append(data.Calls, UICallType{c, cc.count, len(cc.cov)})
	}
	sort.Sort(UICallTypeArray(data.Calls))
	data.CoverSize = len(cov)

	if err := htmlTemplate.Execute(w, data); err != nil {
		http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError)
	}
}
Beispiel #10
0
func (mgr *Manager) NewInput(a *NewInputArgs, r *int) error {
	Logf(2, "new input from %v for syscall %v", a.Name, a.Call)
	mgr.mu.Lock()
	defer mgr.mu.Unlock()

	call := sys.CallID[a.Call]
	if len(cover.Difference(a.Cover, mgr.corpusCover[call])) == 0 {
		return nil
	}
	mgr.corpusCover[call] = cover.Union(mgr.corpusCover[call], a.Cover)
	mgr.corpus = append(mgr.corpus, a.RpcInput)
	mgr.stats["manager new inputs"]++
	mgr.persistentCorpus.add(a.RpcInput.Prog)
	return nil
}
Beispiel #11
0
func main() {
	debug.SetGCPercent(50)
	flag.Parse()
	logf(0, "started")

	var calls []*sys.Call
	if *flagSyscalls != "" {
		for _, id := range strings.Split(*flagSyscalls, ",") {
			n, err := strconv.ParseUint(id, 10, 64)
			if err != nil || n >= uint64(len(sys.Calls)) {
				panic(fmt.Sprintf("invalid syscall in -calls flag: '%v", id))
			}
			calls = append(calls, sys.Calls[n])
		}
	}

	corpusCover = make([]cover.Cover, sys.CallCount)
	maxCover = make([]cover.Cover, sys.CallCount)
	corpusHashes = make(map[Sig]struct{})

	conn, err := rpc.Dial("tcp", *flagManager)
	if err != nil {
		panic(err)
	}
	manager = conn
	a := &ManagerConnectArgs{*flagName}
	r := &ManagerConnectRes{}
	if err := manager.Call("Manager.Connect", a, r); err != nil {
		panic(err)
	}
	ct = prog.BuildChoiceTable(r.Prios, calls)

	if *flagParallel <= 0 {
		*flagParallel = 1
	}
	flags := ipc.FlagCover | ipc.FlagDedupCover
	if *flagStrace {
		flags |= ipc.FlagStrace
	}
	workerIn = make(chan *prog.Prog, *flagParallel+10)
	workerOut = make(chan []Input, *flagParallel)
	for i := 0; i < *flagParallel; i++ {
		env, err := ipc.MakeEnv(*flagExecutor, 4*time.Second, flags)
		if err != nil {
			panic(err)
		}
		workerId := i + 1
		go func() {
			for p := range workerIn {
				workerOut <- execute(env, p, workerId)
			}
		}()
	}
	env, err := ipc.MakeEnv(*flagExecutor, 4*time.Second, flags)
	if err != nil {
		panic(err)
	}
	rs := rand.NewSource(time.Now().UnixNano())
	rnd := rand.New(rs)
	var lastPoll time.Time
	var lastPrint time.Time
	secondTicker := time.NewTicker(100 * time.Millisecond).C
	for i := 0; ; i++ {
		if !*flagSaveProg && time.Since(lastPrint) > 10*time.Second {
			// Keep-alive for manager.
			logf(0, "#%v: alive", i)
			lastPrint = time.Now()
		}
		if len(triage) != 0 {
			last := len(triage) - 1
			inp := triage[last]
			triage = triage[:last]
			logf(1, "#%v: triaging : %s", i, inp.p)
			triageInput(env, inp)
			continue
		}
		if time.Since(lastPoll) > 10*time.Second {
			a := &ManagerPollArgs{*flagName}
			r := &ManagerPollRes{}
			if err := manager.Call("Manager.Poll", a, r); err != nil {
				panic(err)
			}
			for _, inp := range r.NewInputs {
				addInput(inp)
			}
			for _, data := range r.Candidates {
				p, err := prog.Deserialize(data)
				if err != nil {
					panic(err)
				}
				inputs := execute(env, p, 0)
				for _, inp := range inputs {
					call := inp.p.Calls[inp.call].Meta
					maxCover[call.CallID] = cover.Union(maxCover[call.CallID], inp.cover)
					triage = append(triage, inp)
				}
			}
			if len(r.NewInputs) == 0 && len(r.Candidates) == 0 {
				lastPoll = time.Now()
			}
			continue
		}
		// Parallel part.
		pending := 0
		for ; ; i++ {
			if !(!*flagSaveProg && time.Since(lastPrint) > 10*time.Second) &&
				!(len(triage) != 0) &&
				!(time.Since(lastPoll) > 10*time.Second) {
				// No need to do any work above.
				// Send new inputs to workers, if they need some.
				for len(workerIn) < *flagParallel {
					if len(corpus) == 0 || i%10 == 0 {
						p := prog.Generate(rnd, programLength, ct)
						logf(1, "#%v: generated: %s", i, p)
						workerIn <- p
						pending++
						p = p.Clone()
						p.Mutate(rnd, programLength, ct)
						logf(1, "#%v: mutated: %s", i, p)
						workerIn <- p
						pending++
					} else {
						inp := corpus[rnd.Intn(len(corpus))]
						p := inp.p.Clone()
						p.Mutate(rs, programLength, ct)
						logf(1, "#%v: mutated: %s <- %s", i, p, inp.p)
						workerIn <- p
						pending++
					}
				}
			} else if pending == 0 {
				// Need to do some work above.
				// Break if collected all pending results.
				break
			}
			// Collect results.
			select {
			case inputs := <-workerOut:
				pending--
				for _, inp := range inputs {
					triage = append(triage, inp)
				}
			case <-secondTicker:
			}
		}
		// Do this after the parallel section because workers access maxCover.
		for _, inp := range triage {
			call := inp.p.Calls[inp.call].Meta
			maxCover[call.CallID] = cover.Union(maxCover[call.CallID], inp.cover)
		}
	}
}
Beispiel #12
0
func triageInput(pid int, env *ipc.Env, inp Input) {
	if noCover {
		panic("should not be called when coverage is disabled")
	}

	call := inp.p.Calls[inp.call].Meta
	coverMu.RLock()
	newCover := cover.Difference(inp.cover, corpusCover[call.CallID])
	newCover = cover.Difference(newCover, flakes)
	coverMu.RUnlock()
	if len(newCover) == 0 {
		return
	}

	corpusMu.RLock()
	if _, ok := corpusHashes[hash(inp.p.Serialize())]; ok {
		corpusMu.RUnlock()
		return
	}
	corpusMu.RUnlock()

	minCover := inp.cover
	for i := 0; i < 3; i++ {
		allCover := execute1(pid, env, inp.p, &statExecTriage)
		if len(allCover[inp.call]) == 0 {
			// The call was not executed. Happens sometimes, reason unknown.
			continue
		}
		coverMu.RLock()
		cov := allCover[inp.call]
		diff := cover.SymmetricDifference(inp.cover, cov)
		minCover = cover.Intersection(minCover, cov)
		updateFlakes := len(diff) != 0 && len(cover.Difference(diff, flakes)) != 0
		coverMu.RUnlock()
		if updateFlakes {
			coverMu.Lock()
			flakes = cover.Union(flakes, diff)
			coverMu.Unlock()
		}
	}
	stableNewCover := cover.Intersection(newCover, minCover)
	if len(stableNewCover) == 0 {
		return
	}
	inp.p, inp.call = prog.Minimize(inp.p, inp.call, func(p1 *prog.Prog, call1 int) bool {
		allCover := execute1(pid, env, p1, &statExecMinimize)
		coverMu.RLock()
		defer coverMu.RUnlock()

		if len(allCover[call1]) == 0 {
			return false // The call was not executed.
		}
		cov := allCover[call1]
		if len(cover.Intersection(stableNewCover, cov)) != len(stableNewCover) {
			return false
		}
		minCover = cover.Intersection(minCover, cov)
		return true
	}, false)
	inp.cover = minCover

	atomic.AddUint64(&statNewInput, 1)
	data := inp.p.Serialize()
	Logf(2, "added new input for %v to corpus:\n%s", call.CallName, data)
	a := &NewInputArgs{*flagName, RpcInput{call.CallName, data, inp.call, []uint32(inp.cover)}}
	if err := manager.Call("Manager.NewInput", a, nil); err != nil {
		panic(err)
	}

	corpusMu.Lock()
	defer corpusMu.Unlock()
	coverMu.Lock()
	defer coverMu.Unlock()

	corpusCover[call.CallID] = cover.Union(corpusCover[call.CallID], minCover)
	corpus = append(corpus, inp.p)
	corpusHashes[hash(data)] = struct{}{}
}
Beispiel #13
0
func (mgr *Manager) httpSummary(w http.ResponseWriter, r *http.Request) {
	mgr.mu.Lock()
	defer mgr.mu.Unlock()

	data := &UISummaryData{
		Name: mgr.cfg.Name,
	}
	data.Stats = append(data.Stats, UIStat{Name: "uptime", Value: fmt.Sprint(time.Since(mgr.startTime) / 1e9 * 1e9)})
	data.Stats = append(data.Stats, UIStat{Name: "corpus", Value: fmt.Sprint(len(mgr.corpus))})
	data.Stats = append(data.Stats, UIStat{Name: "triage queue", Value: fmt.Sprint(len(mgr.candidates))})

	var err error
	if data.Crashes, err = mgr.collectCrashes(); err != nil {
		http.Error(w, fmt.Sprintf("failed to collect crashes: %v", err), http.StatusInternalServerError)
		return
	}

	type CallCov struct {
		count int
		cov   cover.Cover
	}
	calls := make(map[string]*CallCov)
	for _, inp := range mgr.corpus {
		if calls[inp.Call] == nil {
			calls[inp.Call] = new(CallCov)
		}
		cc := calls[inp.Call]
		cc.count++
		cc.cov = cover.Union(cc.cov, cover.Cover(inp.Cover))
	}

	secs := uint64(1)
	if !mgr.firstConnect.IsZero() {
		secs = uint64(time.Since(mgr.firstConnect))/1e9 + 1
	}

	var cov cover.Cover
	totalUnique := mgr.uniqueCover(true)
	for c, cc := range calls {
		cov = cover.Union(cov, cc.cov)
		unique := cover.Intersection(cc.cov, totalUnique)
		data.Calls = append(data.Calls, UICallType{
			Name:        c,
			Inputs:      cc.count,
			Cover:       len(cc.cov),
			UniqueCover: len(unique),
		})
	}
	sort.Sort(UICallTypeArray(data.Calls))
	data.Stats = append(data.Stats, UIStat{Name: "cover", Value: fmt.Sprint(len(cov)), Link: "/cover"})

	var intStats []UIStat
	for k, v := range mgr.stats {
		val := fmt.Sprintf("%v", v)
		if x := v / secs; x >= 10 {
			val += fmt.Sprintf(" (%v/sec)", x)
		} else if x := v * 60 / secs; x >= 10 {
			val += fmt.Sprintf(" (%v/min)", x)
		} else {
			x := v * 60 * 60 / secs
			val += fmt.Sprintf(" (%v/hour)", x)
		}
		intStats = append(intStats, UIStat{Name: k, Value: val})
	}
	sort.Sort(UIStatArray(intStats))
	data.Stats = append(data.Stats, intStats...)
	data.Log = CachedLogOutput()

	if err := summaryTemplate.Execute(w, data); err != nil {
		http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError)
		return
	}
}