aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2015-12-31 13:47:20 +0100
committerDmitry Vyukov <dvyukov@google.com>2015-12-31 16:03:01 +0100
commit62351e3ea53211036203a3cb5d4049a05f2f2eff (patch)
tree78d92098e428f857bb61042be97cb0b01bde0100
parent84916f2fc692c2ac9bbc2aebf621572e4aa3b7c1 (diff)
fuzzer: allow to write programs to dmesg
Mostly useful for local VM.
-rw-r--r--config/config.go9
-rw-r--r--syz-fuzzer/fuzzer.go34
-rw-r--r--syz-manager/manager.go4
3 files changed, 35 insertions, 12 deletions
diff --git a/config/config.go b/config/config.go
index 74b2a4755..6ae3baa36 100644
--- a/config/config.go
+++ b/config/config.go
@@ -30,6 +30,7 @@ type Config struct {
Port int // VM ssh port to use
Bin string // qemu/lkvm binary name
Debug bool // dump all VM output to console
+ Output string // one of stdout/dmesg/file (useful only for local VM)
Syzkaller string // path to syzkaller checkout (syz-manager will look for binaries in bin subdir)
Type string // VM type (qemu, kvm, local)
@@ -84,6 +85,14 @@ func Parse(filename string) (*Config, map[int]bool, []*regexp.Regexp, error) {
if cfg.Procs <= 0 {
cfg.Procs = 1
}
+ if cfg.Output == "" {
+ cfg.Output = "stdout"
+ }
+ switch cfg.Output {
+ case "stdout", "dmesg", "file":
+ default:
+ return nil, nil, nil, fmt.Errorf("config param output must contain one of stdout/dmesg/file")
+ }
syscalls, err := parseSyscalls(cfg)
if err != nil {
diff --git a/syz-fuzzer/fuzzer.go b/syz-fuzzer/fuzzer.go
index faa8dde1d..edc6a3b21 100644
--- a/syz-fuzzer/fuzzer.go
+++ b/syz-fuzzer/fuzzer.go
@@ -8,6 +8,7 @@ package main
// i.e. aim at cracking new branches and triggering bugs in that new piece of code.
import (
+ "bytes"
"crypto/sha1"
"flag"
"fmt"
@@ -36,13 +37,13 @@ var (
flagExecutor = flag.String("executor", "", "path to executor binary")
flagManager = flag.String("manager", "", "manager rpc address")
flagStrace = flag.Bool("strace", false, "run executor under strace")
- flagSaveProg = flag.Bool("saveprog", false, "save programs into local file before executing")
flagSyscalls = flag.String("calls", "", "comma-delimited list of enabled syscall IDs (empty string for all syscalls)")
flagNoCover = flag.Bool("nocover", false, "disable coverage collection/handling")
flagDropPrivs = flag.Bool("dropprivs", true, "impersonate into nobody")
flagProcs = flag.Int("procs", 1, "number of parallel test processes")
flagLeak = flag.Bool("leak", false, "detect memory leaks")
flagV = flag.Int("v", 0, "verbosity")
+ flagOutput = flag.String("output", "stdout", "write programs to stdout/dmesg/file")
)
const (
@@ -92,6 +93,10 @@ var (
func main() {
debug.SetGCPercent(50)
flag.Parse()
+ if *flagOutput != "stdout" && *flagOutput != "dmesg" && *flagOutput != "file" {
+ fmt.Fprintf(os.Stderr, "-output flag must be one of stdout/dmesg/file\n")
+ os.Exit(1)
+ }
logf(0, "started")
corpusCover = make([]cover.Cover, sys.CallCount)
@@ -193,7 +198,7 @@ func main() {
var lastPoll time.Time
var lastPrint time.Time
for range time.NewTicker(3 * time.Second).C {
- if *flagSaveProg && time.Since(lastPrint) > 10*time.Second {
+ if *flagOutput != "stdout" && time.Since(lastPrint) > 10*time.Second {
// Keep-alive for manager.
logf(0, "alive")
lastPrint = time.Now()
@@ -456,19 +461,28 @@ func execute1(pid int, env *ipc.Env, p *prog.Prog, stat *uint64) []cover.Cover {
}
})
- if *flagSaveProg {
+ // The following output helps to understand what program crashed kernel.
+ // It must not be intermixed.
+ switch *flagOutput {
+ case "stdout":
+ data := p.Serialize()
+ logMu.Lock()
+ log.Printf("executing program %v:\n%s", pid, data)
+ logMu.Unlock()
+ case "dmesg":
+ fd, err := syscall.Open("/dev/kmsg", syscall.O_WRONLY, 0)
+ if err == nil {
+ buf := new(bytes.Buffer)
+ fmt.Fprintf(buf, "syzkaller: executing program %v:\n%s", pid, p.Serialize())
+ syscall.Write(fd, buf.Bytes())
+ syscall.Close(fd)
+ }
+ case "file":
f, err := os.Create(fmt.Sprintf("%v-%v.prog", *flagName, pid))
if err == nil {
f.Write(p.Serialize())
f.Close()
}
- } else {
- // The following output helps to understand what program crashed kernel.
- // It must not be intermixed.
- data := p.Serialize()
- logMu.Lock()
- log.Printf("executing program %v:\n%s", pid, data)
- logMu.Unlock()
}
try := 0
diff --git a/syz-manager/manager.go b/syz-manager/manager.go
index f422c1328..50e8d172b 100644
--- a/syz-manager/manager.go
+++ b/syz-manager/manager.go
@@ -181,8 +181,8 @@ func (mgr *Manager) runInstance(vmCfg *vm.Config, first bool) bool {
// Leak detection significantly slows down fuzzing, so detect leaks only on the first instance.
leak := first && mgr.cfg.Leak
- outputC, errorC, err := inst.Run(time.Hour, fmt.Sprintf("/syz-fuzzer -name %v -executor /syz-executor -manager %v:%v -procs %v -leak=%v %v %v %v",
- vmCfg.Name, inst.HostAddr(), mgr.port, mgr.cfg.Procs, leak, cover, dropprivs, calls))
+ outputC, errorC, err := inst.Run(time.Hour, fmt.Sprintf("/syz-fuzzer -name %v -executor /syz-executor -manager %v:%v -output=%v -procs %v -leak=%v %v %v %v",
+ vmCfg.Name, inst.HostAddr(), mgr.port, mgr.cfg.Output, mgr.cfg.Procs, leak, cover, dropprivs, calls))
if err != nil {
logf(0, "failed to run fuzzer: %v", err)
return false