mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-23 11:29:46 +00:00
remove master and naming overhaul
Remove master process entirely, it is not useful in its current form. We first need to understand what we want from it, and them re-implement it. Prefix all binaries with syz- to avoid name clashes.
This commit is contained in:
parent
06e6726537
commit
8e7ca7c5ff
22
Makefile
22
Makefile
@ -1,24 +1,18 @@
|
|||||||
# Copyright 2015 syzkaller project authors. All rights reserved.
|
# Copyright 2015 syzkaller project authors. All rights reserved.
|
||||||
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
||||||
|
|
||||||
.PHONY: all bin format clean master manager fuzzer executor
|
.PHONY: all format clean master manager fuzzer executor
|
||||||
|
|
||||||
all: master manager fuzzer executor
|
all: manager fuzzer executor
|
||||||
|
|
||||||
bin:
|
manager:
|
||||||
mkdir -p bin
|
go build -o ./bin/syz-manager github.com/google/syzkaller/syz-manager
|
||||||
|
|
||||||
master: bin
|
fuzzer:
|
||||||
go build -o ./bin/master github.com/google/syzkaller/master
|
go build -o ./bin/syz-fuzzer github.com/google/syzkaller/syz-fuzzer
|
||||||
|
|
||||||
manager: bin
|
executor:
|
||||||
go build -o ./bin/manager github.com/google/syzkaller/manager
|
gcc -o ./bin/syz-executor executor/executor.cc -lpthread -static -Wall -O1 -g
|
||||||
|
|
||||||
fuzzer: bin
|
|
||||||
go build -o ./bin/fuzzer github.com/google/syzkaller/fuzzer
|
|
||||||
|
|
||||||
executor: bin
|
|
||||||
gcc executor/executor.cc -o ./bin/executor -lpthread -static -Wall -O1 -g
|
|
||||||
|
|
||||||
format:
|
format:
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
// Copyright 2015 syzkaller project authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"html/template"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (m *Master) httpInfo(w http.ResponseWriter, r *http.Request) {
|
|
||||||
m.mu.Lock()
|
|
||||||
defer m.mu.Unlock()
|
|
||||||
|
|
||||||
data := &UIData{
|
|
||||||
CorpusLen: len(m.corpus.m),
|
|
||||||
}
|
|
||||||
for _, mgr := range m.managers {
|
|
||||||
data.Managers = append(data.Managers, UIManager{
|
|
||||||
Name: mgr.name,
|
|
||||||
Http: mgr.http,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if err := htmlTemplate.Execute(w, data); err != nil {
|
|
||||||
http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Master) httpMinimize(w http.ResponseWriter, r *http.Request) {
|
|
||||||
corpus := make(map[string]bool)
|
|
||||||
for _, mgr := range m.managers {
|
|
||||||
resp, err := http.Get("http://" + mgr.http + "/current_corpus")
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, fmt.Sprintf("failed to query corpus from %v: %v", mgr.name, err), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
data, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, fmt.Sprintf("failed to query corpus from %v: %v", mgr.name, err), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var hashes []string
|
|
||||||
err = json.Unmarshal(data, &hashes)
|
|
||||||
if err != nil || len(hashes) == 0 {
|
|
||||||
http.Error(w, fmt.Sprintf("failed to parse corpus from %v: %v", mgr.name, err), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, hash := range hashes {
|
|
||||||
corpus[hash] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m.mu.Lock()
|
|
||||||
defer m.mu.Unlock()
|
|
||||||
|
|
||||||
orig := len(m.corpus.m)
|
|
||||||
m.corpus.minimize(corpus)
|
|
||||||
fmt.Printf("minimized: %v -> %v -> %v\n", orig, len(corpus), len(m.corpus.m))
|
|
||||||
for _, mgr := range m.managers {
|
|
||||||
mgr.input = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type UIData struct {
|
|
||||||
CorpusLen int
|
|
||||||
Managers []UIManager
|
|
||||||
}
|
|
||||||
|
|
||||||
type UIManager struct {
|
|
||||||
Name string
|
|
||||||
Http string
|
|
||||||
}
|
|
||||||
|
|
||||||
var htmlTemplate = template.Must(template.New("").Parse(`
|
|
||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>syzkaller master</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
Corpus: {{.CorpusLen}} <br>
|
|
||||||
{{if .Managers}}
|
|
||||||
Managers:<br>
|
|
||||||
{{range $mgr := $.Managers}}
|
|
||||||
<a href='http://{{$mgr.Http}}'>{{$mgr.Name}}</a><br>
|
|
||||||
{{end}}
|
|
||||||
{{else}}
|
|
||||||
No managers connected<br>
|
|
||||||
{{end}}
|
|
||||||
</body></html>
|
|
||||||
`))
|
|
170
master/master.go
170
master/master.go
@ -1,170 +0,0 @@
|
|||||||
// Copyright 2015 syzkaller project authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/rpc"
|
|
||||||
"path/filepath"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/syzkaller/prog"
|
|
||||||
. "github.com/google/syzkaller/rpctype"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
flagWorkdir = flag.String("workdir", "", "dir with persistent artifacts")
|
|
||||||
flagAddr = flag.String("addr", "", "RPC listen address to connect managers")
|
|
||||||
flagHTTP = flag.String("http", "", "HTTP server listen address")
|
|
||||||
flagV = flag.Int("v", 0, "verbosity")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Master manages persistent fuzzer state (input corpus and crashers).
|
|
||||||
type Master struct {
|
|
||||||
mu sync.Mutex
|
|
||||||
managers map[string]*Manager
|
|
||||||
corpus *PersistentSet
|
|
||||||
crashers *PersistentSet
|
|
||||||
startTime time.Time
|
|
||||||
lastInput time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type Manager struct {
|
|
||||||
name string
|
|
||||||
http string
|
|
||||||
input int
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.Parse()
|
|
||||||
if *flagWorkdir == "" {
|
|
||||||
fatalf("-workdir is not set")
|
|
||||||
}
|
|
||||||
if *flagAddr == "" {
|
|
||||||
fatalf("-addr is not set")
|
|
||||||
}
|
|
||||||
if *flagHTTP == "" {
|
|
||||||
fatalf("-http is not set")
|
|
||||||
}
|
|
||||||
ln, err := net.Listen("tcp", *flagAddr)
|
|
||||||
if err != nil {
|
|
||||||
fatalf("failed to listen: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
m := &Master{}
|
|
||||||
m.managers = make(map[string]*Manager)
|
|
||||||
m.startTime = time.Now()
|
|
||||||
m.lastInput = time.Now()
|
|
||||||
logf(0, "loading corpus...")
|
|
||||||
m.corpus = newPersistentSet(filepath.Join(*flagWorkdir, "corpus"), func(data []byte) bool {
|
|
||||||
if _, err := prog.Deserialize(data); err != nil {
|
|
||||||
logf(0, "deleting broken program: %v\n%s", err, data)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
m.crashers = newPersistentSet(filepath.Join(*flagWorkdir, "crashers"), nil)
|
|
||||||
|
|
||||||
http.HandleFunc("/", m.httpInfo)
|
|
||||||
http.HandleFunc("/minimize", m.httpMinimize)
|
|
||||||
go func() {
|
|
||||||
logf(0, "serving http on http://%v", *flagHTTP)
|
|
||||||
panic(http.ListenAndServe(*flagHTTP, nil))
|
|
||||||
}()
|
|
||||||
|
|
||||||
logf(0, "serving rpc on tcp://%v", *flagAddr)
|
|
||||||
s := rpc.NewServer()
|
|
||||||
s.Register(m)
|
|
||||||
go s.Accept(ln)
|
|
||||||
|
|
||||||
m.loop()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Master) loop() {
|
|
||||||
for range time.NewTicker(1 * time.Second).C {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect attaches new manager to master.
|
|
||||||
func (m *Master) Connect(a *MasterConnectArgs, r *MasterConnectRes) error {
|
|
||||||
logf(1, "connect from %v (http://%v)", a.Name, a.Http)
|
|
||||||
m.mu.Lock()
|
|
||||||
defer m.mu.Unlock()
|
|
||||||
|
|
||||||
mgr := &Manager{
|
|
||||||
name: a.Name,
|
|
||||||
http: a.Http,
|
|
||||||
}
|
|
||||||
m.managers[a.Name] = mgr
|
|
||||||
r.Http = *flagHTTP
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInput saves new interesting input on master.
|
|
||||||
func (m *Master) NewInput(a *NewMasterInputArgs, r *int) error {
|
|
||||||
p, err := prog.Deserialize(a.Prog)
|
|
||||||
if err != nil {
|
|
||||||
logf(0, "bogus new input from %v: %v\n%s\n", a.Name, err, a.Prog)
|
|
||||||
return fmt.Errorf("the program is bogus: %v", err)
|
|
||||||
}
|
|
||||||
m.mu.Lock()
|
|
||||||
defer m.mu.Unlock()
|
|
||||||
|
|
||||||
if !m.corpus.add(a.Prog) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
m.lastInput = time.Now()
|
|
||||||
logf(1, "new input from %v: %s", a.Name, p)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type NewCrasherArgs struct {
|
|
||||||
Name string
|
|
||||||
Text []byte
|
|
||||||
Suppression []byte
|
|
||||||
Prog []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCrasher saves new crasher input on master.
|
|
||||||
func (m *Master) NewCrasher(a *NewCrasherArgs, r *int) error {
|
|
||||||
logf(0, "new crasher from %v", a.Name)
|
|
||||||
m.mu.Lock()
|
|
||||||
defer m.mu.Unlock()
|
|
||||||
|
|
||||||
if !m.crashers.add(a.Text) {
|
|
||||||
return nil // Already have this.
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Master) PollInputs(a *MasterPollArgs, r *MasterPollRes) error {
|
|
||||||
logf(2, "poll from %v", a.Name)
|
|
||||||
m.mu.Lock()
|
|
||||||
defer m.mu.Unlock()
|
|
||||||
|
|
||||||
mgr := m.managers[a.Name]
|
|
||||||
if mgr == nil {
|
|
||||||
return fmt.Errorf("manager is not connected")
|
|
||||||
}
|
|
||||||
for i := 0; i < 100 && mgr.input < len(m.corpus.a); i++ {
|
|
||||||
r.Inputs = append(r.Inputs, m.corpus.a[mgr.input])
|
|
||||||
mgr.input++
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func logf(v int, msg string, args ...interface{}) {
|
|
||||||
if *flagV >= v {
|
|
||||||
log.Printf(msg, args...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func fatalf(msg string, args ...interface{}) {
|
|
||||||
log.Fatalf(msg, args...)
|
|
||||||
}
|
|
@ -1,7 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "my-qemu-asan",
|
|
||||||
"http": "myhost.com:56741",
|
"http": "myhost.com:56741",
|
||||||
"master": "myhost.com:48342",
|
|
||||||
"workdir": "/syzkaller/manager/workdir",
|
"workdir": "/syzkaller/manager/workdir",
|
||||||
"vmlinux": "/linux/vmlinux",
|
"vmlinux": "/linux/vmlinux",
|
||||||
"type": "qemu",
|
"type": "qemu",
|
||||||
@ -21,5 +19,8 @@
|
|||||||
"keyctl",
|
"keyctl",
|
||||||
"add_key",
|
"add_key",
|
||||||
"request_key"
|
"request_key"
|
||||||
|
],
|
||||||
|
"suppressions": [
|
||||||
|
"some known bug"
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -4,8 +4,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -23,11 +21,8 @@ func (mgr *Manager) initHttp() {
|
|||||||
http.HandleFunc("/corpus", mgr.httpCorpus)
|
http.HandleFunc("/corpus", mgr.httpCorpus)
|
||||||
http.HandleFunc("/cover", mgr.httpCover)
|
http.HandleFunc("/cover", mgr.httpCover)
|
||||||
http.HandleFunc("/prio", mgr.httpPrio)
|
http.HandleFunc("/prio", mgr.httpPrio)
|
||||||
http.HandleFunc("/current_corpus", mgr.httpCurrentCorpus)
|
logf(0, "serving http on http://%v", mgr.cfg.Http)
|
||||||
go func() {
|
go http.ListenAndServe(mgr.cfg.Http, nil)
|
||||||
logf(0, "serving http on http://%v", mgr.cfg.Http)
|
|
||||||
panic(http.ListenAndServe(mgr.cfg.Http, nil))
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mgr *Manager) httpInfo(w http.ResponseWriter, r *http.Request) {
|
func (mgr *Manager) httpInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -50,12 +45,9 @@ func (mgr *Manager) httpInfo(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
uptime := time.Since(mgr.startTime)
|
uptime := time.Since(mgr.startTime)
|
||||||
data := &UIData{
|
data := &UIData{
|
||||||
Name: mgr.cfg.Name,
|
CorpusSize: len(mgr.corpus),
|
||||||
MasterHttp: mgr.masterHttp,
|
TriageQueue: len(mgr.candidates),
|
||||||
MasterCorpusSize: len(mgr.masterCorpus),
|
Uptime: fmt.Sprintf("%v", uptime),
|
||||||
CorpusSize: len(mgr.corpus),
|
|
||||||
TriageQueue: len(mgr.candidates),
|
|
||||||
Uptime: fmt.Sprintf("%v", uptime),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
secs := uint64(uptime) / 1e9
|
secs := uint64(uptime) / 1e9
|
||||||
@ -164,34 +156,13 @@ func (mgr *Manager) httpPrio(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mgr *Manager) httpCurrentCorpus(w http.ResponseWriter, r *http.Request) {
|
|
||||||
mgr.mu.Lock()
|
|
||||||
defer mgr.mu.Unlock()
|
|
||||||
|
|
||||||
mgr.minimizeCorpus()
|
|
||||||
var hashes []string
|
|
||||||
for _, inp := range mgr.corpus {
|
|
||||||
hash := hash(inp.Prog)
|
|
||||||
hashes = append(hashes, hex.EncodeToString(hash[:]))
|
|
||||||
}
|
|
||||||
data, err := json.Marshal(&hashes)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, fmt.Sprintf("failed to marshal corpus: %v", err), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Write(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
type UIData struct {
|
type UIData struct {
|
||||||
Name string
|
CorpusSize int
|
||||||
MasterHttp string
|
TriageQueue int
|
||||||
MasterCorpusSize int
|
CoverSize int
|
||||||
CorpusSize int
|
Uptime string
|
||||||
TriageQueue int
|
Stats []UIStat
|
||||||
CoverSize int
|
Calls []UICallType
|
||||||
Uptime string
|
|
||||||
Stats []UIStat
|
|
||||||
Calls []UICallType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type UIStat struct {
|
type UIStat struct {
|
||||||
@ -235,12 +206,10 @@ var htmlTemplate = template.Must(template.New("").Parse(`
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>syzkaller {{.Name}}</title>
|
<title>syzkaller</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
Manager: {{.Name}} <a href='http://{{.MasterHttp}}'>[master]</a> <br>
|
|
||||||
Uptime: {{.Uptime}}<br>
|
Uptime: {{.Uptime}}<br>
|
||||||
Master corpus: {{.MasterCorpusSize}} <br>
|
|
||||||
Corpus: {{.CorpusSize}}<br>
|
Corpus: {{.CorpusSize}}<br>
|
||||||
Triage queue len: {{.TriageQueue}}<br>
|
Triage queue len: {{.TriageQueue}}<br>
|
||||||
<a href='/cover'>Cover: {{.CoverSize}}</a> <br>
|
<a href='/cover'>Cover: {{.CoverSize}}</a> <br>
|
@ -26,9 +26,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Name string
|
|
||||||
Http string
|
Http string
|
||||||
Master string
|
|
||||||
Workdir string
|
Workdir string
|
||||||
Vmlinux string
|
Vmlinux string
|
||||||
Type string
|
Type string
|
||||||
@ -110,15 +108,9 @@ func parseConfig() (*Config, map[int]bool) {
|
|||||||
if err := json.Unmarshal(data, cfg); err != nil {
|
if err := json.Unmarshal(data, cfg); err != nil {
|
||||||
fatalf("failed to parse config file: %v", err)
|
fatalf("failed to parse config file: %v", err)
|
||||||
}
|
}
|
||||||
if cfg.Name == "" {
|
|
||||||
fatalf("config param name is empty")
|
|
||||||
}
|
|
||||||
if cfg.Http == "" {
|
if cfg.Http == "" {
|
||||||
fatalf("config param http is empty")
|
fatalf("config param http is empty")
|
||||||
}
|
}
|
||||||
if cfg.Master == "" {
|
|
||||||
fatalf("config param master is empty")
|
|
||||||
}
|
|
||||||
if cfg.Workdir == "" {
|
if cfg.Workdir == "" {
|
||||||
fatalf("config param workdir is empty")
|
fatalf("config param workdir is empty")
|
||||||
}
|
}
|
@ -4,10 +4,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha1"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/rpc"
|
"net/rpc"
|
||||||
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -18,26 +18,17 @@ import (
|
|||||||
"github.com/google/syzkaller/vm"
|
"github.com/google/syzkaller/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Sig [sha1.Size]byte
|
|
||||||
|
|
||||||
func hash(data []byte) Sig {
|
|
||||||
return Sig(sha1.Sum(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
cfg *Config
|
cfg *Config
|
||||||
master *rpc.Client
|
persistentCorpus *PersistentSet
|
||||||
masterHttp string
|
instances []vm.Instance
|
||||||
instances []vm.Instance
|
startTime time.Time
|
||||||
startTime time.Time
|
stats map[string]uint64
|
||||||
stats map[string]uint64
|
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
masterCorpus [][]byte // mirror of master corpus
|
syscalls map[int]bool
|
||||||
masterHashes map[Sig]struct{} // hashes of master corpus
|
|
||||||
candidates [][]byte // new untriaged inputs from master
|
|
||||||
syscalls map[int]bool
|
|
||||||
|
|
||||||
|
candidates [][]byte // untriaged inputs
|
||||||
corpus []RpcInput
|
corpus []RpcInput
|
||||||
corpusCover []cover.Cover
|
corpusCover []cover.Cover
|
||||||
prios [][]float32
|
prios [][]float32
|
||||||
@ -51,31 +42,29 @@ type Fuzzer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RunManager(cfg *Config, syscalls map[int]bool, instances []vm.Instance) {
|
func RunManager(cfg *Config, syscalls map[int]bool, instances []vm.Instance) {
|
||||||
// Connect to master.
|
|
||||||
master, err := rpc.Dial("tcp", cfg.Master)
|
|
||||||
if err != nil {
|
|
||||||
fatalf("failed to dial mastger: %v", err)
|
|
||||||
}
|
|
||||||
a := &MasterConnectArgs{cfg.Name, cfg.Http}
|
|
||||||
r := &MasterConnectRes{}
|
|
||||||
if err := master.Call("Master.Connect", a, r); err != nil {
|
|
||||||
fatalf("failed to connect to master: %v", err)
|
|
||||||
}
|
|
||||||
logf(0, "connected to master at %v", cfg.Master)
|
|
||||||
|
|
||||||
mgr := &Manager{
|
mgr := &Manager{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
master: master,
|
startTime: time.Now(),
|
||||||
masterHttp: r.Http,
|
stats: make(map[string]uint64),
|
||||||
startTime: time.Now(),
|
instances: instances,
|
||||||
stats: make(map[string]uint64),
|
syscalls: syscalls,
|
||||||
instances: instances,
|
corpusCover: make([]cover.Cover, sys.CallCount),
|
||||||
masterHashes: make(map[Sig]struct{}),
|
fuzzers: make(map[string]*Fuzzer),
|
||||||
syscalls: syscalls,
|
|
||||||
corpusCover: make([]cover.Cover, sys.CallCount),
|
|
||||||
fuzzers: make(map[string]*Fuzzer),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logf(0, "loading corpus...")
|
||||||
|
mgr.persistentCorpus = newPersistentSet(filepath.Join(cfg.Workdir, "corpus"), func(data []byte) bool {
|
||||||
|
if _, err := prog.Deserialize(data); err != nil {
|
||||||
|
logf(0, "deleting broken program: %v\n%s", err, data)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
for _, prog := range mgr.persistentCorpus.a {
|
||||||
|
mgr.candidates = append(mgr.candidates, prog)
|
||||||
|
}
|
||||||
|
logf(0, "loaded %v programs", len(mgr.persistentCorpus.m))
|
||||||
|
|
||||||
// Create HTTP server.
|
// Create HTTP server.
|
||||||
mgr.initHttp()
|
mgr.initHttp()
|
||||||
|
|
||||||
@ -85,64 +74,15 @@ func RunManager(cfg *Config, syscalls map[int]bool, instances []vm.Instance) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf("failed to listen on port %v: %v", cfg.Port, err)
|
fatalf("failed to listen on port %v: %v", cfg.Port, err)
|
||||||
}
|
}
|
||||||
|
logf(0, "serving rpc on tcp://%v", rpcAddr)
|
||||||
s := rpc.NewServer()
|
s := rpc.NewServer()
|
||||||
s.Register(mgr)
|
s.Register(mgr)
|
||||||
go s.Accept(ln)
|
go s.Accept(ln)
|
||||||
logf(0, "serving rpc on tcp://%v", rpcAddr)
|
|
||||||
|
|
||||||
mgr.run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mgr *Manager) run() {
|
|
||||||
mgr.pollMaster()
|
|
||||||
for _, inst := range mgr.instances {
|
for _, inst := range mgr.instances {
|
||||||
go inst.Run()
|
go inst.Run()
|
||||||
}
|
}
|
||||||
pollTicker := time.NewTicker(10 * time.Second).C
|
select {}
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-pollTicker:
|
|
||||||
mgr.mu.Lock()
|
|
||||||
mgr.pollMaster()
|
|
||||||
mgr.mu.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mgr *Manager) pollMaster() {
|
|
||||||
for {
|
|
||||||
a := &MasterPollArgs{mgr.cfg.Name}
|
|
||||||
r := &MasterPollRes{}
|
|
||||||
if err := mgr.master.Call("Master.PollInputs", a, r); err != nil {
|
|
||||||
fatalf("failed to poll master: %v", err)
|
|
||||||
}
|
|
||||||
logf(3, "polling master, got %v inputs", len(r.Inputs))
|
|
||||||
if len(r.Inputs) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
nextProg:
|
|
||||||
for _, prg := range r.Inputs {
|
|
||||||
p, err := prog.Deserialize(prg)
|
|
||||||
if err != nil {
|
|
||||||
logf(0, "failed to deserialize master program: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if mgr.syscalls != nil {
|
|
||||||
for _, c := range p.Calls {
|
|
||||||
if !mgr.syscalls[c.Meta.ID] {
|
|
||||||
continue nextProg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sig := hash(prg)
|
|
||||||
if _, ok := mgr.masterHashes[sig]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
mgr.masterHashes[sig] = struct{}{}
|
|
||||||
mgr.masterCorpus = append(mgr.masterCorpus, prg)
|
|
||||||
mgr.candidates = append(mgr.candidates, prg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mgr *Manager) minimizeCorpus() {
|
func (mgr *Manager) minimizeCorpus() {
|
||||||
@ -178,6 +118,16 @@ func (mgr *Manager) minimizeCorpus() {
|
|||||||
corpus = append(corpus, p)
|
corpus = append(corpus, p)
|
||||||
}
|
}
|
||||||
mgr.prios = prog.CalculatePriorities(corpus)
|
mgr.prios = prog.CalculatePriorities(corpus)
|
||||||
|
|
||||||
|
// Don't minimize persistent corpus until fuzzers have triaged all inputs from it.
|
||||||
|
if len(mgr.candidates) == 0 {
|
||||||
|
hashes := make(map[string]bool)
|
||||||
|
for _, inp := range mgr.corpus {
|
||||||
|
h := hash(inp.Prog)
|
||||||
|
hashes[string(h[:])] = true
|
||||||
|
}
|
||||||
|
mgr.persistentCorpus.minimize(hashes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mgr *Manager) Connect(a *ManagerConnectArgs, r *ManagerConnectRes) error {
|
func (mgr *Manager) Connect(a *ManagerConnectArgs, r *ManagerConnectRes) error {
|
||||||
@ -208,18 +158,7 @@ func (mgr *Manager) NewInput(a *NewManagerInputArgs, r *int) error {
|
|||||||
mgr.corpusCover[call] = cover.Union(mgr.corpusCover[call], a.Cover)
|
mgr.corpusCover[call] = cover.Union(mgr.corpusCover[call], a.Cover)
|
||||||
mgr.corpus = append(mgr.corpus, a.RpcInput)
|
mgr.corpus = append(mgr.corpus, a.RpcInput)
|
||||||
mgr.stats["manager new inputs"]++
|
mgr.stats["manager new inputs"]++
|
||||||
|
mgr.persistentCorpus.add(a.RpcInput.Prog)
|
||||||
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -258,8 +258,8 @@ func (inst *Instance) Run() {
|
|||||||
inst.Logf("started vm")
|
inst.Logf("started vm")
|
||||||
|
|
||||||
// Copy the binaries into the instance.
|
// Copy the binaries into the instance.
|
||||||
if !inst.CreateSCPCommand(inst.Fuzzer, "/syzkaller_fuzzer").Wait(1*time.Minute) ||
|
if !inst.CreateSCPCommand(inst.Fuzzer, "/syz-fuzzer").Wait(1*time.Minute) ||
|
||||||
!inst.CreateSCPCommand(inst.Executor, "/syzkaller_executor").Wait(1*time.Minute) {
|
!inst.CreateSCPCommand(inst.Executor, "/syz-executor").Wait(1*time.Minute) {
|
||||||
outputMu.Lock()
|
outputMu.Lock()
|
||||||
output = append(output, "\nfailed to scp binaries into the instance\n"...)
|
output = append(output, "\nfailed to scp binaries into the instance\n"...)
|
||||||
inst.SaveCrasher(output)
|
inst.SaveCrasher(output)
|
||||||
@ -280,7 +280,7 @@ func (inst *Instance) Run() {
|
|||||||
if inst.cfg.NoDropPrivs {
|
if inst.cfg.NoDropPrivs {
|
||||||
dropprivs = "-dropprivs=0"
|
dropprivs = "-dropprivs=0"
|
||||||
}
|
}
|
||||||
cmd := inst.CreateSSHCommand(fmt.Sprintf("/syzkaller_fuzzer -name %v -executor /syzkaller_executor -manager %v:%v -procs %v -leak=%v %v %v %v",
|
cmd := inst.CreateSSHCommand(fmt.Sprintf("/syz-fuzzer -name %v -executor /syz-executor -manager %v:%v -procs %v -leak=%v %v %v %v",
|
||||||
inst.name, hostAddr, inst.cfg.ManagerPort, inst.cfg.Procs, inst.cfg.Leak, cover, dropprivs, inst.callsFlag))
|
inst.name, hostAddr, inst.cfg.ManagerPort, inst.cfg.Procs, inst.cfg.Leak, cover, dropprivs, inst.callsFlag))
|
||||||
|
|
||||||
deadline := start.Add(time.Hour)
|
deadline := start.Add(time.Hour)
|
||||||
|
Loading…
Reference in New Issue
Block a user