func main() { flag.Parse() corpus := readCorpus() flags := ipc.FlagThreaded if *flagDebug { flags |= ipc.FlagDebug } env, err := ipc.MakeEnv(*flagExecutor, 4*time.Second, flags) if err != nil { failf("failed to create execution environment: %v", err) } rs := rand.NewSource(time.Now().UnixNano()) rnd := rand.New(rs) for i := 0; ; i++ { var p *prog.Prog if len(corpus) == 0 || i%10 != 0 { p = prog.Generate(rs, 50, nil) execute(env, p) p.Mutate(rs, 50, nil) execute(env, p) } else { p = corpus[rnd.Intn(len(corpus))].Clone() p.Mutate(rs, 50, nil) execute(env, p) } } }
func main() { flag.Parse() data, err := ioutil.ReadFile(*flagProg) if err != nil { fmt.Fprintf(os.Stderr, "failed to read prog file: %v\n", err) os.Exit(1) } p, err := prog.Deserialize(data) if err != nil { fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err) os.Exit(1) } var flags uint64 if *flagThreaded { flags |= ipc.FlagThreaded } if *flagDebug { flags |= ipc.FlagDebug } if *flagStrace { flags |= ipc.FlagStrace } if *flagCover != "" { flags |= ipc.FlagCover } if *flagDedup { flags |= ipc.FlagDedupCover } env, err := ipc.MakeEnv(*flagExecutor, *flagTimeout, flags) if err != nil { fmt.Fprintf(os.Stderr, "failed to create execution environment: %v\n", err) os.Exit(1) } defer env.Close() output, strace, cov, failed, hanged, err := env.Exec(p) fmt.Printf("result: failed=%v hanged=%v err=%v\n\n%s", failed, hanged, err, output) if *flagStrace { fmt.Printf("strace output:\n%s", strace) } // 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", *flagCover, i), buf.Bytes(), 0660) if err != nil { fmt.Fprintf(os.Stderr, "failed to write coverage file: %v\n", err) os.Exit(1) } } }
func main() { flag.Parse() var progs []*prog.Prog for _, fn := range strings.Split(*flagLog, ",") { logf, err := os.Open(fn) if err != nil { log.Fatalf("failed to open log file: %v", err) } log.Printf("parsing log %v", fn) s := bufio.NewScanner(logf) var cur []byte var last *prog.Prog for s.Scan() { ln := s.Text() tmp := append(cur, ln...) tmp = append(tmp, '\n') p, err := prog.Deserialize(tmp) if err == nil { cur = tmp last = p continue } if last != nil { progs = append(progs, last) last = nil cur = cur[:0] } } if last != nil { progs = append(progs, last) } } log.Printf("parsed %v programs", len(progs)) if len(progs) == 0 { return } var pos uint32 for p := 0; p < 16; p++ { go func() { env, err := ipc.MakeEnv(*flagExecutor, 5*time.Second, 0) if err != nil { log.Fatalf("failed to create ipc env: %v", err) } for { idx := int(atomic.AddUint32(&pos, 1) - 1) if idx%1000 == 0 { log.Printf("executing %v\n", idx) } _, _, _, _, _, err := env.Exec(progs[idx%len(progs)]) if err != nil { log.Printf("failed to execute program: %v", err) } } }() } select {} }
func main() { flag.Parse() corpus := readCorpus() log.Printf("parsed %v programs", len(corpus)) calls := buildCallList() prios := prog.CalculatePriorities(corpus) ct := prog.BuildChoiceTable(prios, calls) var flags uint64 if *flagThreaded { flags |= ipc.FlagThreaded } if *flagCollide { flags |= ipc.FlagCollide } if *flagNobody { flags |= ipc.FlagDropPrivs } if *flagDebug { flags |= ipc.FlagDebug } if *flagNoPgid { flags |= ipc.FlagNoSetpgid } gate = ipc.NewGate(2 * *flagProcs) for pid := 0; pid < *flagProcs; pid++ { pid := pid go func() { env, err := ipc.MakeEnv(*flagExecutor, *flagTimeout, flags) if err != nil { failf("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) execute(pid, env, p) } else { p = corpus[rnd.Intn(len(corpus))].Clone() p.Mutate(rs, programLength, ct) execute(pid, env, p) p.Mutate(rs, programLength, ct) execute(pid, env, p) } } }() } for range time.NewTicker(5 * time.Second).C { log.Printf("executed %v programs", atomic.LoadUint64(&statExec)) } }
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() { flag.Parse() corpus := readCorpus() var flags uint64 if *flagThreaded { flags |= ipc.FlagThreaded } if *flagCollide { flags |= ipc.FlagCollide } if *flagNobody { flags |= ipc.FlagDropPrivs } if *flagDebug { flags |= ipc.FlagDebug } for p := 0; p < *flagProcs; p++ { go func() { env, err := ipc.MakeEnv(*flagExecutor, 10*time.Second, flags) if err != nil { failf("failed to create execution environment: %v", err) } rs := rand.NewSource(time.Now().UnixNano()) rnd := rand.New(rs) for i := 0; ; i++ { var p *prog.Prog if len(corpus) == 0 || i%10 != 0 { p = prog.Generate(rs, 50, nil) execute(env, p) p.Mutate(rs, 50, nil) execute(env, p) } else { p = corpus[rnd.Intn(len(corpus))].Clone() p.Mutate(rs, 50, nil) execute(env, p) } } }() } select {} }
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) flags := ipc.FlagCover | ipc.FlagDedupCover if *flagStrace { flags |= ipc.FlagStrace } 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 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) } execute(env, p) } if len(r.NewInputs) == 0 && len(r.Candidates) == 0 { lastPoll = time.Now() } continue } if len(corpus) == 0 || i%10 == 0 { p := prog.Generate(rnd, programLength, ct) logf(1, "#%v: generated: %s", i, p) execute(env, p) p.Mutate(rnd, programLength, ct) logf(1, "#%v: mutated: %s", i, p) execute(env, p) } 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) execute(env, p) } } }
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() { 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) } } }
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() { 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() { 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() } } } }
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() { progs = append(progs, parseFile(fn)...) } log.Printf("parsed %v programs", len(progs)) if len(progs) == 0 { return } var flags uint64 if *flagThreaded { flags |= ipc.FlagThreaded } if *flagCollide { flags |= ipc.FlagCollide } if *flagDebug { flags |= ipc.FlagDebug } if *flagStrace { flags |= ipc.FlagStrace } if *flagCover || *flagCoverFile != "" { flags |= ipc.FlagCover } if *flagDedup { flags |= ipc.FlagDedupCover } if *flagNobody { flags |= ipc.FlagDropPrivs } var wg sync.WaitGroup wg.Add(*flagProcs) var pos uint32 for p := 0; p < *flagProcs; p++ { go func() { env, err := ipc.MakeEnv(*flagExecutor, *flagTimeout, flags) if err != nil { log.Fatalf("failed to create ipc env: %v", err) } for { idx := int(atomic.AddUint32(&pos, 1) - 1) if idx%len(progs) == 0 { log.Printf("executed %v programs\n", idx) } if !*flagLoop && idx >= len(progs) { env.Close() wg.Done() return } p := progs[idx%len(progs)] output, strace, cov, failed, hanged, err := env.Exec(p) if *flagDebug || err != nil { fmt.Printf("result: failed=%v hanged=%v err=%v\n\n%s", failed, hanged, err, output) } if *flagStrace { fmt.Printf("strace output:\n%s", strace) } 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() }