mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-26 21:00:30 +00:00
9133037195
Two virtual wireless devices are instantiated during network devices initialization. A new flag (-wifi) is added that controls whether these virtual wifi devices are instantiated and configured during proc initialization. Also, two new pseudo syscalls are added: 1. syz_80211_inject_frame(mac_addr, packet, packet_len) -- injects an arbitrary packet into the wireless stack. It is injected as if it originated from the device identitied by mac_addr. 2. syz_80211_join_ibss(interface_name, ssid, ssid_len, mode) -- puts a specific network interface into IBSS state and joins an IBSS network. Arguments of syz_80211_join_ibss: 1) interface_name -- null-terminated string that identifies a wireless interface 2) ssid, ssid_len -- SSID of an IBSS network to join to 3) mode -- mode of syz_80211_join_ibss operation (see below) Modes of operation: JOIN_IBSS_NO_SCAN (0x0) -- channel scan is not performed and syz_80211_join_ibss waits until the interface reaches IF_OPER_UP. JOIN_IBSS_BG_SCAN (0x1) -- channel scan is performed (takes ~ 9 seconds), syz_80211_join_ibss does not await IF_OPER_UP. JOIN_IBSS_BG_NO_SCAN (0x2) -- channel scan is not performed, syz_80211_join_ibss does not await IF_OPER_UP. Local testing ensured that these syscalls are indeed able to set up an operating network and inject packets into mac80211.
253 lines
7.2 KiB
Go
253 lines
7.2 KiB
Go
// Copyright 2019 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"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/google/syzkaller/dashboard/dashapi"
|
|
"github.com/google/syzkaller/pkg/csource"
|
|
"github.com/google/syzkaller/pkg/osutil"
|
|
"github.com/google/syzkaller/pkg/vcs"
|
|
)
|
|
|
|
var (
|
|
flagDashboard = flag.String("dashboard", "https://syzkaller.appspot.com", "dashboard address")
|
|
flagAPIClient = flag.String("client", "", "api client")
|
|
flagAPIKey = flag.String("key", "", "api key")
|
|
flagOutputDir = flag.String("output", "repros", "output dir")
|
|
flagSyzkallerDir = flag.String("syzkaller", ".", "syzkaller dir")
|
|
flagOS = flag.String("os", runtime.GOOS, "target OS")
|
|
)
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
if *flagAPIClient == "" || *flagAPIKey == "" {
|
|
log.Fatalf("api client and key are required")
|
|
}
|
|
if err := os.MkdirAll(*flagOutputDir, 0755); err != nil {
|
|
log.Fatalf("failed to create output dir: %v", err)
|
|
}
|
|
dash := dashapi.New(*flagAPIClient, *flagDashboard, *flagAPIKey)
|
|
resp, err := dash.BugList()
|
|
if err != nil {
|
|
log.Fatalf("api call failed: %v", err)
|
|
}
|
|
log.Printf("loading %v bugs", len(resp.List))
|
|
const P = 10
|
|
idchan := make(chan string, 10*P)
|
|
bugchan := make(chan *dashapi.LoadBugResp, 10*P)
|
|
go func() {
|
|
for _, id := range resp.List {
|
|
if _, err := os.Stat(filepath.Join(*flagOutputDir, id+".c")); err == nil {
|
|
log.Printf("%v: already present", id)
|
|
continue
|
|
}
|
|
if _, err := os.Stat(filepath.Join(*flagOutputDir, id+".norepro")); err == nil {
|
|
log.Printf("%v: no repro (cached)", id)
|
|
continue
|
|
}
|
|
if _, err := os.Stat(filepath.Join(*flagOutputDir, id+".error")); err == nil {
|
|
log.Printf("%v: error (cached)", id)
|
|
continue
|
|
}
|
|
idchan <- id
|
|
}
|
|
close(idchan)
|
|
}()
|
|
var wg sync.WaitGroup
|
|
wg.Add(P)
|
|
for p := 0; p < P; p++ {
|
|
go func() {
|
|
defer wg.Done()
|
|
for id := range idchan {
|
|
resp, err := dash.LoadBug(id)
|
|
if err != nil {
|
|
log.Printf("%v: failed to load bug: %v", id, err)
|
|
continue
|
|
}
|
|
if resp.ID == "" {
|
|
continue
|
|
}
|
|
bugchan <- resp
|
|
}
|
|
}()
|
|
}
|
|
go func() {
|
|
wg.Wait()
|
|
close(bugchan)
|
|
}()
|
|
writeRepros(bugchan)
|
|
}
|
|
|
|
func writeRepros(bugchan chan *dashapi.LoadBugResp) {
|
|
for bug := range bugchan {
|
|
if len(bug.ReproSyz) == 0 {
|
|
log.Printf("%v: %v: no repro", bug.ID, bug.Status)
|
|
file := filepath.Join(*flagOutputDir, bug.ID+".norepro")
|
|
if err := ioutil.WriteFile(file, nil, 0644); err != nil {
|
|
log.Fatalf("failed to write file: %v", err)
|
|
}
|
|
continue
|
|
}
|
|
if len(bug.ReproC) == 0 {
|
|
log.Printf("%v: %v: syz repro on %v", bug.ID, bug.Status, bug.SyzkallerCommit)
|
|
if err := createCRepro(bug); err != nil {
|
|
log.Print(err)
|
|
errText := []byte(err.Error())
|
|
file := filepath.Join(*flagOutputDir, bug.ID+".error")
|
|
if err := ioutil.WriteFile(file, errText, 0644); err != nil {
|
|
log.Fatalf("failed to write file: %v", err)
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
log.Printf("%v: %v: C repro", bug.ID, bug.Status)
|
|
arch := ""
|
|
if bug.Arch != "" && bug.Arch != "amd64" {
|
|
arch = fmt.Sprintf(" arch:%v", bug.Arch)
|
|
}
|
|
repro := []byte(fmt.Sprintf("// %v\n// %v/bug?id=%v\n// status:%v%v\n",
|
|
bug.Title, *flagDashboard, bug.ID, bug.Status, arch))
|
|
repro = append(repro, bug.ReproC...)
|
|
file := filepath.Join(*flagOutputDir, bug.ID+".c")
|
|
if err := ioutil.WriteFile(file, repro, 0644); err != nil {
|
|
log.Fatalf("failed to write file: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func createCRepro(bug *dashapi.LoadBugResp) error {
|
|
opts, err := csource.DeserializeOptions(bug.ReproOpts)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to deserialize opts: %v", err)
|
|
}
|
|
file := filepath.Join(*flagOutputDir, bug.ID+".syz")
|
|
if err := ioutil.WriteFile(file, bug.ReproSyz, 0644); err != nil {
|
|
return fmt.Errorf("failed to write file: %v", err)
|
|
}
|
|
repo := vcs.NewSyzkallerRepo(*flagSyzkallerDir)
|
|
if _, err := repo.SwitchCommit(bug.SyzkallerCommit); err != nil {
|
|
return fmt.Errorf("failed to checkout commit %v: %v", bug.SyzkallerCommit, err)
|
|
}
|
|
if _, err := osutil.RunCmd(time.Hour, *flagSyzkallerDir, "make", "prog2c"); err != nil {
|
|
return err
|
|
}
|
|
bin := filepath.Join(*flagSyzkallerDir, "bin", "syz-prog2c")
|
|
args := createProg2CArgs(bug, opts, file)
|
|
output, err := osutil.RunCmd(time.Hour, "", bin, args...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
bug.ReproC = output
|
|
return err
|
|
}
|
|
|
|
// Although liter complains about this function, it does not seem complex.
|
|
// nolint: gocyclo
|
|
func createProg2CArgs(bug *dashapi.LoadBugResp, opts csource.Options, file string) []string {
|
|
haveEnableFlag := containsCommit("dfd609eca1871f01757d6b04b19fc273c87c14e5")
|
|
haveRepeatFlag := containsCommit("b25fc7b83119e8dca728a199fd92e24dd4c33fa4")
|
|
haveCgroupFlag := containsCommit("9753d3be5e6c79e271ed128795039f161ee339b7")
|
|
haveWaitRepeatFlag := containsCommit("c99b02d2248fbdcd6f44037326b16c928f4423f1")
|
|
haveWaitRepeatRemoved := containsCommit("9fe4bdc5f1037a409e82299f36117030114c7b94")
|
|
haveCloseFDs := containsCommit("5c51045d28eb1ad9465a51487d436133ce7b98d2")
|
|
haveOSFlag := containsCommit("aa2533b98d21ebcad5777310215159127bfe3573")
|
|
args := []string{
|
|
"-prog", file,
|
|
"-sandbox", opts.Sandbox,
|
|
fmt.Sprintf("-segv=%v", opts.HandleSegv),
|
|
fmt.Sprintf("-collide=%v", opts.Collide),
|
|
fmt.Sprintf("-threaded=%v", opts.Threaded),
|
|
}
|
|
if haveOSFlag {
|
|
args = append(args, "-os", *flagOS)
|
|
}
|
|
if bug.Arch != "" && bug.Arch != "amd64" {
|
|
args = append(args, "-arch", bug.Arch)
|
|
}
|
|
if opts.Fault {
|
|
args = append(args, []string{
|
|
fmt.Sprintf("-fault_call=%v", opts.FaultCall),
|
|
fmt.Sprintf("-fault_nth=%v", opts.FaultNth),
|
|
}...)
|
|
}
|
|
if opts.Repeat {
|
|
if haveRepeatFlag {
|
|
args = append(args, fmt.Sprintf("-repeat=%v", opts.RepeatTimes))
|
|
} else {
|
|
args = append(args, "-repeat")
|
|
}
|
|
}
|
|
if opts.Procs > 0 {
|
|
args = append(args, fmt.Sprintf("-procs=%v", opts.Procs))
|
|
}
|
|
if opts.UseTmpDir {
|
|
args = append(args, "-tmpdir")
|
|
}
|
|
if opts.Leak {
|
|
args = append(args, "-leak")
|
|
}
|
|
var enable, flags []string
|
|
if opts.NetInjection {
|
|
enable = append(enable, "tun")
|
|
flags = append(flags, "-tun")
|
|
}
|
|
if opts.NetDevices {
|
|
enable = append(enable, "net_dev")
|
|
flags = append(flags, "-netdev")
|
|
}
|
|
if opts.NetReset {
|
|
enable = append(enable, "net_reset")
|
|
flags = append(flags, "-resetnet")
|
|
}
|
|
if opts.Cgroups {
|
|
enable = append(enable, "cgroups")
|
|
if haveCgroupFlag {
|
|
flags = append(flags, "-cgroups")
|
|
if haveWaitRepeatFlag && !haveWaitRepeatRemoved {
|
|
flags = append(flags, "-waitrepeat")
|
|
}
|
|
}
|
|
}
|
|
if opts.BinfmtMisc {
|
|
enable = append(enable, "binfmt_misc")
|
|
}
|
|
if opts.CloseFDs && haveCloseFDs {
|
|
enable = append(enable, "close_fds")
|
|
}
|
|
if opts.DevlinkPCI {
|
|
enable = append(enable, "devlink_pci")
|
|
flags = append(flags, "-devlinkpci")
|
|
}
|
|
if opts.VhciInjection {
|
|
enable = append(enable, "vhci")
|
|
flags = append(flags, "-vhci")
|
|
}
|
|
if opts.Wifi {
|
|
enable = append(enable, "wifi")
|
|
flags = append(flags, "-wifi")
|
|
}
|
|
if !haveEnableFlag {
|
|
args = append(args, flags...)
|
|
} else if len(enable) != 0 {
|
|
args = append(args, "-enable", strings.Join(enable, ","))
|
|
}
|
|
return args
|
|
}
|
|
|
|
func containsCommit(hash string) bool {
|
|
_, err := osutil.RunCmd(time.Hour, *flagSyzkallerDir, "git", "merge-base", "--is-ancestor", hash, "HEAD")
|
|
return err == nil
|
|
}
|