syzkaller/tools/syz-usbgen/usbgen.go
Andrey Konovalov 55e0c07757
sys/linux: extract USB HID ids (#1294)
* sys/linux: extract USB HID ids

As it turns out the HID kernel subsystem registers only one USB driver that
checks that the interface of the connected device has HID class and then looks
up its own list of vendor/device ids to find a matching driver. This means
that we currently don't generate proper vendor/device ids for USB HID devices.

This patch updates the syz-usbgen tool to also extract USB HID vendor/device
ids from a running kernel and makes the generated descriptions for HID devices
to be patched using the extracted ids.

This patch also contains some minor improvements to USB descriptions
(better HID descriptions and more replies for some USB classes/drivers).

* sys/linux: run make generate
2019-07-22 19:25:54 +02:00

100 lines
2.5 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 (
"encoding/hex"
"flag"
"fmt"
"io/ioutil"
"os"
"regexp"
"sort"
"github.com/google/syzkaller/pkg/osutil"
)
func main() {
flag.Parse()
args := flag.Args()
if len(args) != 2 {
usage()
}
syslog, err := ioutil.ReadFile(args[0])
if err != nil {
failf("failed to read file %v: %v", args[0], err)
}
usbIds := extractIds(syslog, "USBID", 34)
hidIds := extractIds(syslog, "HIDID", 24)
output := make([]byte, 0)
output = append(output, []byte("// AUTOGENERATED FILE\n")...)
output = append(output, []byte("// See docs/linux/external_fuzzing_usb.md\n")...)
output = append(output, []byte("\n")...)
output = append(output, []byte("package linux\n")...)
output = append(output, []byte("\n")...)
output = append(output, generateIdsVar(usbIds, "usbIds")...)
output = append(output, []byte("\n")...)
output = append(output, generateIdsVar(hidIds, "hidIds")...)
if err := osutil.WriteFile(args[1], output); err != nil {
failf("failed to output file %v: %v", args[1], err)
}
}
func extractIds(syslog []byte, prefix string, size int) []string {
re := fmt.Sprintf("%s: [0-9a-f]{%d}", prefix, size)
r := regexp.MustCompile(re)
matches := r.FindAll(syslog, -1)
uniqueMatches := make(map[string]bool)
for _, match := range matches {
uniqueMatches[string(match)] = true
}
sortedMatches := make([]string, 0)
for match := range uniqueMatches {
match = match[len(prefix+": "):]
match = match[:size]
sortedMatches = append(sortedMatches, match)
}
sort.Strings(sortedMatches)
return sortedMatches
}
func generateIdsVar(ids []string, name string) []byte {
output := []byte(fmt.Sprintf("var %s = ", name))
for i, id := range ids {
decodedID, err := hex.DecodeString(id)
if err != nil {
failf("failed to decode hex string %v: %v", id, err)
}
prefix := "\t"
suffix := " +"
if i == 0 {
prefix = ""
}
if i == len(ids)-1 {
suffix = ""
}
outputID := fmt.Sprintf("%v%#v%v\n", prefix, string(decodedID), suffix)
output = append(output, []byte(outputID)...)
}
fmt.Printf("%v %s ids written\n", len(ids), name)
return output
}
func usage() {
fmt.Fprintf(os.Stderr, "usage:\n")
fmt.Fprintf(os.Stderr, " syz-usbgen syslog.txt sys/linux/init_vusb_ids.go\n")
os.Exit(1)
}
func failf(msg string, args ...interface{}) {
fmt.Fprintf(os.Stderr, msg+"\n", args...)
os.Exit(1)
}