func main() { flag.Parse() corpus := readCorpus() Logf(0, "parsed %v programs", len(corpus)) calls := buildCallList() prios := prog.CalculatePriorities(corpus) ct := prog.BuildChoiceTable(prios, calls) flags, timeout, err := ipc.DefaultFlags() if err != nil { Fatalf("%v", err) } gate = ipc.NewGate(2**flagProcs, nil) for pid := 0; pid < *flagProcs; pid++ { pid := pid go func() { env, err := ipc.MakeEnv(*flagExecutor, timeout, flags, pid) if err != nil { Fatalf("failed to create execution environment: %v", err) } rs := rand.NewSource(time.Now().UnixNano() + int64(pid)*1e12) rnd := rand.New(rs) for i := 0; ; i++ { var p *prog.Prog if len(corpus) == 0 || i%4 != 0 { p = prog.Generate(rs, programLength, ct) execute(pid, env, p) p.Mutate(rs, programLength, ct, corpus) execute(pid, env, p) } else { p = corpus[rnd.Intn(len(corpus))].Clone() p.Mutate(rs, programLength, ct, corpus) execute(pid, env, p) p.Mutate(rs, programLength, ct, corpus) execute(pid, env, p) } } }() } for range time.NewTicker(5 * time.Second).C { Logf(0, "executed %v programs", atomic.LoadUint64(&statExec)) } }
func main() { debug.SetGCPercent(50) flag.Parse() switch *flagOutput { case "none", "stdout", "dmesg", "file": default: fmt.Fprintf(os.Stderr, "-output flag must be one of none/stdout/dmesg/file\n") os.Exit(1) } logf(0, "started") corpusCover = make([]cover.Cover, sys.CallCount) maxCover = make([]cover.Cover, sys.CallCount) corpusHashes = make(map[Sig]struct{}) logf(0, "dialing manager at %v", *flagManager) conn, err := jsonrpc.Dial("tcp", *flagManager) if err != nil { panic(err) } manager = conn a := &ConnectArgs{*flagName} r := &ConnectRes{} if err := manager.Call("Manager.Connect", a, r); err != nil { panic(err) } calls := buildCallList(r.EnabledCalls) ct := prog.BuildChoiceTable(r.Prios, calls) kmemleakInit() flags, timeout := ipc.DefaultFlags() noCover = flags&ipc.FlagCover == 0 if !noCover { fd, err := syscall.Open("/sys/kernel/debug/kcov", syscall.O_RDWR, 0) if err != nil { log.Fatalf("BUG: /sys/kernel/debug/kcov is missing (%v). Enable CONFIG_KCOV and mount debugfs.", err) } syscall.Close(fd) } gate = ipc.NewGate(2 * *flagProcs) envs := make([]*ipc.Env, *flagProcs) for pid := 0; pid < *flagProcs; pid++ { env, err := ipc.MakeEnv(*flagExecutor, timeout, flags) if err != nil { panic(err) } envs[pid] = env pid := pid go func() { rs := rand.NewSource(time.Now().UnixNano() + int64(pid)*1e12) rnd := rand.New(rs) for i := 0; ; i++ { triageMu.RLock() if len(triage) != 0 || len(candidates) != 0 { triageMu.RUnlock() triageMu.Lock() if len(triage) != 0 { last := len(triage) - 1 inp := triage[last] triage = triage[:last] triageMu.Unlock() logf(1, "triaging : %s", inp.p) triageInput(pid, env, inp) continue } else if len(candidates) != 0 { last := len(candidates) - 1 p := candidates[last] candidates = candidates[:last] triageMu.Unlock() execute(pid, env, p, &statExecCandidate) continue } else { triageMu.Unlock() } } else { triageMu.RUnlock() } corpusMu.RLock() if len(corpus) == 0 || i%10 == 0 { corpusMu.RUnlock() p := prog.Generate(rnd, programLength, ct) logf(1, "#%v: generated: %s", i, p) execute(pid, env, p, &statExecGen) p.Mutate(rnd, programLength, ct) logf(1, "#%v: mutated: %s", i, p) execute(pid, env, p, &statExecFuzz) } else { p0 := corpus[rnd.Intn(len(corpus))] corpusMu.RUnlock() p := p0.Clone() p.Mutate(rs, programLength, ct) logf(1, "#%v: mutated: %s <- %s", i, p, p0) execute(pid, env, p, &statExecFuzz) } } }() } var lastPoll time.Time var lastPrint time.Time for range time.NewTicker(3 * time.Second).C { if *flagOutput != "stdout" && time.Since(lastPrint) > 10*time.Second { // Keep-alive for manager. logf(0, "alive") lastPrint = time.Now() } if time.Since(lastPoll) > 10*time.Second { triageMu.RLock() if len(candidates) != 0 { triageMu.RUnlock() continue } triageMu.RUnlock() a := &PollArgs{ Name: *flagName, Stats: make(map[string]uint64), } for _, env := range envs { a.Stats["exec total"] += atomic.SwapUint64(&env.StatExecs, 0) a.Stats["executor restarts"] += atomic.SwapUint64(&env.StatRestarts, 0) } a.Stats["exec gen"] = atomic.SwapUint64(&statExecGen, 0) a.Stats["exec fuzz"] = atomic.SwapUint64(&statExecFuzz, 0) a.Stats["exec candidate"] = atomic.SwapUint64(&statExecCandidate, 0) a.Stats["exec triage"] = atomic.SwapUint64(&statExecTriage, 0) a.Stats["exec minimize"] = atomic.SwapUint64(&statExecMinimize, 0) a.Stats["fuzzer new inputs"] = atomic.SwapUint64(&statNewInput, 0) r := &PollRes{} 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) } if noCover { corpusMu.Lock() corpus = append(corpus, p) corpusMu.Unlock() } else { triageMu.Lock() candidates = append(candidates, p) triageMu.Unlock() } } if len(r.Candidates) == 0 { if atomic.LoadUint32(&allTriaged) == 0 { if *flagLeak { kmemleakScan(false) } atomic.StoreUint32(&allTriaged, 1) } } if len(r.NewInputs) == 0 && len(r.Candidates) == 0 { lastPoll = time.Now() } } } }
func main() { flag.Parse() if len(flag.Args()) == 0 { fmt.Fprintf(os.Stderr, "usage: execprog [flags] file-with-programs+\n") flag.PrintDefaults() os.Exit(1) } var progs []*prog.Prog for _, fn := range flag.Args() { data, err := ioutil.ReadFile(fn) if err != nil { log.Fatalf("failed to read log file: %v", err) } entries := prog.ParseLog(data) for _, ent := range entries { progs = append(progs, ent.P) } } log.Printf("parsed %v programs", len(progs)) if len(progs) == 0 { return } flags, timeout := ipc.DefaultFlags() if *flagCoverFile != "" { flags |= ipc.FlagCover flags &= ^ipc.FlagDedupCover } var wg sync.WaitGroup wg.Add(*flagProcs) var posMu sync.Mutex var pos int var lastPrint time.Time for p := 0; p < *flagProcs; p++ { go func() { env, err := ipc.MakeEnv(*flagExecutor, timeout, flags) if err != nil { log.Fatalf("failed to create ipc env: %v", err) } for { posMu.Lock() idx := pos pos++ if idx%len(progs) == 0 && time.Since(lastPrint) > 5*time.Second { log.Printf("executed %v programs\n", idx) lastPrint = time.Now() } posMu.Unlock() if *flagRepeat > 0 && idx >= len(progs)**flagRepeat { env.Close() wg.Done() return } p := progs[idx%len(progs)] output, cov, _, failed, hanged, err := env.Exec(p) if failed { fmt.Printf("BUG: executor-detected bug:\n%s", output) } if flags&ipc.FlagDebug != 0 || err != nil { fmt.Printf("result: failed=%v hanged=%v err=%v\n\n%s", failed, hanged, err, output) } if *flagCoverFile != "" { // Coverage is dumped in sanitizer format. // github.com/google/sanitizers/tools/sancov command can be used to dump PCs, // then they can be piped via addr2line to symbolize. for i, c := range cov { fmt.Printf("call #%v: coverage %v\n", i, len(c)) if len(c) == 0 { continue } buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, uint64(0xC0BFFFFFFFFFFF64)) for _, pc := range c { binary.Write(buf, binary.LittleEndian, cover.RestorePC(pc)) } err := ioutil.WriteFile(fmt.Sprintf("%v.%v", *flagCoverFile, i), buf.Bytes(), 0660) if err != nil { log.Fatalf("failed to write coverage file: %v", err) } } } } }() } wg.Wait() }
func main() { flag.Parse() if len(flag.Args()) == 0 { fmt.Fprintf(os.Stderr, "usage: execprog [flags] file-with-programs+\n") flag.PrintDefaults() os.Exit(1) } var progs []*prog.Prog for _, fn := range flag.Args() { data, err := ioutil.ReadFile(fn) if err != nil { Fatalf("failed to read log file: %v", err) } entries := prog.ParseLog(data) for _, ent := range entries { progs = append(progs, ent.P) } } Logf(0, "parsed %v programs", len(progs)) if len(progs) == 0 { return } flags, timeout, err := ipc.DefaultFlags() if err != nil { Fatalf("%v", err) } if *flagCoverFile != "" { flags |= ipc.FlagCover flags &= ^ipc.FlagDedupCover } var wg sync.WaitGroup wg.Add(*flagProcs) var posMu, logMu sync.Mutex gate := ipc.NewGate(2**flagProcs, nil) var pos int var lastPrint time.Time var shutdown uint32 for p := 0; p < *flagProcs; p++ { pid := p go func() { defer wg.Done() env, err := ipc.MakeEnv(*flagExecutor, timeout, flags, pid) if err != nil { Fatalf("failed to create ipc env: %v", err) } defer env.Close() for { if !func() bool { // Limit concurrency window. ticket := gate.Enter() defer gate.Leave(ticket) posMu.Lock() idx := pos pos++ if idx%len(progs) == 0 && time.Since(lastPrint) > 5*time.Second { Logf(0, "executed programs: %v", idx) lastPrint = time.Now() } posMu.Unlock() if *flagRepeat > 0 && idx >= len(progs)**flagRepeat { return false } p := progs[idx%len(progs)] switch *flagOutput { case "stdout": data := p.Serialize() logMu.Lock() Logf(0, "executing program %v:\n%s", pid, data) logMu.Unlock() } output, cov, _, failed, hanged, err := env.Exec(p) if atomic.LoadUint32(&shutdown) != 0 { return false } if failed { fmt.Printf("BUG: executor-detected bug:\n%s", output) } if flags&ipc.FlagDebug != 0 || err != nil { fmt.Printf("result: failed=%v hanged=%v err=%v\n\n%s", failed, hanged, err, output) } if *flagCoverFile != "" { // Coverage is dumped in sanitizer format. // github.com/google/sanitizers/tools/sancov command can be used to dump PCs, // then they can be piped via addr2line to symbolize. for i, c := range cov { fmt.Printf("call #%v: coverage %v\n", i, len(c)) if len(c) == 0 { continue } buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, uint64(0xC0BFFFFFFFFFFF64)) for _, pc := range c { binary.Write(buf, binary.LittleEndian, cover.RestorePC(pc, 0xffffffff)) } err := ioutil.WriteFile(fmt.Sprintf("%v.%v", *flagCoverFile, i), buf.Bytes(), 0660) if err != nil { Fatalf("failed to write coverage file: %v", err) } } } return true }() { return } } }() } go func() { c := make(chan os.Signal, 2) signal.Notify(c, syscall.SIGINT) <-c Logf(0, "shutting down...") atomic.StoreUint32(&shutdown, 1) <-c Fatalf("terminating") }() wg.Wait() }
func main() { debug.SetGCPercent(50) flag.Parse() switch *flagOutput { case "none", "stdout", "dmesg", "file": default: fmt.Fprintf(os.Stderr, "-output flag must be one of none/stdout/dmesg/file\n") os.Exit(1) } Logf(0, "fuzzer started") go func() { // Handles graceful preemption on GCE. c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) <-c Logf(0, "SYZ-FUZZER: PREEMPTED") os.Exit(1) }() corpusCover = make([]cover.Cover, sys.CallCount) maxCover = make([]cover.Cover, sys.CallCount) corpusHashes = make(map[Sig]struct{}) Logf(0, "dialing manager at %v", *flagManager) conn, err := jsonrpc.Dial("tcp", *flagManager) if err != nil { panic(err) } manager = conn a := &ConnectArgs{*flagName} r := &ConnectRes{} if err := manager.Call("Manager.Connect", a, r); err != nil { panic(err) } calls := buildCallList(r.EnabledCalls) ct := prog.BuildChoiceTable(r.Prios, calls) if r.NeedCheck { a := &CheckArgs{Name: *flagName} if fd, err := syscall.Open("/sys/kernel/debug/kcov", syscall.O_RDWR, 0); err == nil { syscall.Close(fd) a.Kcov = true } for c := range calls { a.Calls = append(a.Calls, c.Name) } if err := manager.Call("Manager.Check", a, nil); err != nil { panic(err) } } kmemleakInit() flags, timeout, err := ipc.DefaultFlags() if err != nil { panic(err) } if _, ok := calls[sys.CallMap["syz_emit_ethernet"]]; ok { flags |= ipc.FlagEnableTun } noCover = flags&ipc.FlagCover == 0 leakCallback := func() { if atomic.LoadUint32(&allTriaged) != 0 { // Scan for leaks once in a while (it is damn slow). kmemleakScan(true) } } if !*flagLeak { leakCallback = nil } gate = ipc.NewGate(2**flagProcs, leakCallback) needPoll := make(chan struct{}, 1) needPoll <- struct{}{} envs := make([]*ipc.Env, *flagProcs) for pid := 0; pid < *flagProcs; pid++ { env, err := ipc.MakeEnv(*flagExecutor, timeout, flags, pid) if err != nil { panic(err) } envs[pid] = env pid := pid go func() { rs := rand.NewSource(time.Now().UnixNano() + int64(pid)*1e12) rnd := rand.New(rs) for i := 0; ; i++ { triageMu.RLock() if len(triage) != 0 || len(candidates) != 0 { triageMu.RUnlock() triageMu.Lock() if len(triage) != 0 { last := len(triage) - 1 inp := triage[last] triage = triage[:last] wakePoll := len(triage) < *flagProcs triageMu.Unlock() if wakePoll { select { case needPoll <- struct{}{}: default: } } Logf(1, "triaging : %s", inp.p) triageInput(pid, env, inp) continue } else if len(candidates) != 0 { last := len(candidates) - 1 p := candidates[last] candidates = candidates[:last] triageMu.Unlock() execute(pid, env, p, &statExecCandidate) continue } else { triageMu.Unlock() } } else { triageMu.RUnlock() } corpusMu.RLock() if len(corpus) == 0 || i%10 == 0 { // Generate a new prog. corpusMu.RUnlock() p := prog.Generate(rnd, programLength, ct) Logf(1, "#%v: generated: %s", i, p) execute(pid, env, p, &statExecGen) p.Mutate(rnd, programLength, ct, nil) Logf(1, "#%v: mutated: %s", i, p) execute(pid, env, p, &statExecFuzz) } else { // Mutate an existing prog. p0 := corpus[rnd.Intn(len(corpus))] p := p0.Clone() p.Mutate(rs, programLength, ct, corpus) corpusMu.RUnlock() Logf(1, "#%v: mutated: %s <- %s", i, p, p0) execute(pid, env, p, &statExecFuzz) } } }() } var lastPoll time.Time var lastPrint time.Time ticker := time.NewTicker(3 * time.Second).C for { poll := false select { case <-ticker: case <-needPoll: poll = true } if *flagOutput != "stdout" && time.Since(lastPrint) > 10*time.Second { // Keep-alive for manager. Logf(0, "alive") lastPrint = time.Now() } if poll || time.Since(lastPoll) > 10*time.Second { triageMu.RLock() if len(candidates) > *flagProcs { triageMu.RUnlock() continue } triageMu.RUnlock() a := &PollArgs{ Name: *flagName, Stats: make(map[string]uint64), } for _, env := range envs { a.Stats["exec total"] += atomic.SwapUint64(&env.StatExecs, 0) a.Stats["executor restarts"] += atomic.SwapUint64(&env.StatRestarts, 0) } a.Stats["exec gen"] = atomic.SwapUint64(&statExecGen, 0) a.Stats["exec fuzz"] = atomic.SwapUint64(&statExecFuzz, 0) a.Stats["exec candidate"] = atomic.SwapUint64(&statExecCandidate, 0) a.Stats["exec triage"] = atomic.SwapUint64(&statExecTriage, 0) a.Stats["exec minimize"] = atomic.SwapUint64(&statExecMinimize, 0) a.Stats["fuzzer new inputs"] = atomic.SwapUint64(&statNewInput, 0) r := &PollRes{} 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) } if noCover { corpusMu.Lock() corpus = append(corpus, p) corpusMu.Unlock() } else { triageMu.Lock() candidates = append(candidates, p) triageMu.Unlock() } } if len(r.Candidates) == 0 && atomic.LoadUint32(&allTriaged) == 0 { if *flagLeak { kmemleakScan(false) } atomic.StoreUint32(&allTriaged, 1) } if len(r.NewInputs) == 0 && len(r.Candidates) == 0 { lastPoll = time.Now() } } } }