aboutsummaryrefslogtreecommitdiffstats
path: root/tools/syz-usbgen
diff options
context:
space:
mode:
authorAndrey Konovalov <andreyknvl@google.com>2019-07-22 19:25:54 +0200
committerGitHub <noreply@github.com>2019-07-22 19:25:54 +0200
commit55e0c07757deebc0c6094915fae19fc0959849e4 (patch)
treeaef999dbc037a017cdb142fca9911223d0bd1c3f /tools/syz-usbgen
parent6a786da97c822c3ad536290c412f472e58342c91 (diff)
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
Diffstat (limited to 'tools/syz-usbgen')
-rw-r--r--tools/syz-usbgen/usb_ids.patch98
-rw-r--r--tools/syz-usbgen/usbgen.go55
2 files changed, 119 insertions, 34 deletions
diff --git a/tools/syz-usbgen/usb_ids.patch b/tools/syz-usbgen/usb_ids.patch
index dde9935c4..4a28f72bf 100644
--- a/tools/syz-usbgen/usb_ids.patch
+++ b/tools/syz-usbgen/usb_ids.patch
@@ -1,39 +1,109 @@
-commit dcdaff7e78ec4647fdaa4892dd7fdc6b470ee491
+commit 17edce0094c7d7b78b05748d5ce54d68d9bcb419
Author: Andrey Konovalov <andreyknvl@google.com>
Date: Wed Sep 27 17:06:15 2017 +0200
usb-fuzzer: dump usb device ids on enumeration
+diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
+index 210b81a56e1a..6547515b8a2d 100644
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -2114,11 +2114,45 @@ static void hid_free_dynids(struct hid_driver *hdrv)
+ spin_unlock(&hdrv->dyn_lock);
+ }
+
++static void hid_device_id_dump_one(const struct hid_device_id *id)
++{
++ char buffer[128];
++ int size = (char *)&id->product + sizeof(id->product) - (char *)id;
++
++ if (id->bus != HID_BUS_ANY && id->bus != BUS_USB)
++ return;
++
++ bin2hex((char *)&buffer[0], (const char *)id, size);
++ buffer[size * 2] = 0;
++ pr_err("HIDID: %s\n", &buffer[0]);
++}
++
++static void hid_device_id_dump_static(struct hid_driver *hdrv)
++{
++ const struct hid_device_id *id = hdrv->id_table;
++
++ for (; id->bus; id++)
++ hid_device_id_dump_one(id);
++}
++
++static void hid_device_id_dump_dynamic(struct hid_driver *hdrv)
++{
++ struct hid_dynid *dynid;
++
++ spin_lock(&hdrv->dyn_lock);
++ list_for_each_entry(dynid, &hdrv->dyn_list, list)
++ hid_device_id_dump_one(&dynid->id);
++ spin_unlock(&hdrv->dyn_lock);
++}
++
+ const struct hid_device_id *hid_match_device(struct hid_device *hdev,
+ struct hid_driver *hdrv)
+ {
+ struct hid_dynid *dynid;
+
++ hid_device_id_dump_static(hdrv);
++ hid_device_id_dump_dynamic(hdrv);
++
+ spin_lock(&hdrv->dyn_lock);
+ list_for_each_entry(dynid, &hdrv->dyn_list, list) {
+ if (hid_match_one_id(hdev, &dynid->id)) {
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
-index 8987cec9549d..166f2b6486af 100644
+index ebcadaad89d1..44e2d797bb6a 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
-@@ -795,6 +795,19 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface,
+@@ -790,6 +790,39 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface,
}
EXPORT_SYMBOL_GPL(usb_match_id);
-+void usb_device_id_dump(const struct usb_device_id *id)
++static void usb_device_id_dump_one(const struct usb_device_id *id)
+{
++ char buffer[128];
++ int size = (char *)&id->bInterfaceNumber + sizeof(id->bInterfaceNumber)
++ - (char *)id;
++
++ bin2hex((char *)&buffer[0], (const char *)id, size);
++ buffer[size * 2] = 0;
++ pr_err("USBID: %s\n", &buffer[0]);
++}
++
++static void usb_device_id_dump_static(struct usb_driver *drv)
++{
++ const struct usb_device_id *id = drv->id_table;
++
++ if (id == NULL)
++ return;
++
+ for (; id->idVendor || id->idProduct || id->bDeviceClass ||
-+ id->bInterfaceClass || id->driver_info; id++) {
-+ char buffer[128];
-+ int size = (char *)&id->driver_info - (char *)id;
-+ bin2hex((char *)&buffer[0], (const char *)id, size);
-+ buffer[size * 2] = 0;
-+ pr_err("USBID: %s\n", &buffer[0]);
-+ }
++ id->bInterfaceClass || id->driver_info; id++)
++ usb_device_id_dump_one(id);
+}
+
++static void usb_device_id_dump_dynamic(struct usb_driver *drv)
++{
++ struct usb_dynid *dynid;
++
++ spin_lock(&drv->dynids.lock);
++ list_for_each_entry(dynid, &drv->dynids.list, node)
++ usb_device_id_dump_one(&dynid->id);
++ spin_unlock(&drv->dynids.lock);
++}
+
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
/* devices and interfaces are handled separately */
-@@ -819,6 +832,9 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
+@@ -814,6 +847,9 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
intf = to_usb_interface(dev);
usb_drv = to_usb_driver(drv);
-+ if (usb_drv->id_table != NULL)
-+ usb_device_id_dump(usb_drv->id_table);
++ usb_device_id_dump_static(usb_drv);
++ usb_device_id_dump_dynamic(usb_drv);
+
id = usb_match_id(intf, usb_drv->id_table);
if (id)
diff --git a/tools/syz-usbgen/usbgen.go b/tools/syz-usbgen/usbgen.go
index 6c437cddb..61943f039 100644
--- a/tools/syz-usbgen/usbgen.go
+++ b/tools/syz-usbgen/usbgen.go
@@ -27,7 +27,27 @@ func main() {
failf("failed to read file %v: %v", args[0], err)
}
- r := regexp.MustCompile(`usbID: [0-9a-f]{48}`)
+ 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 {
@@ -35,41 +55,36 @@ func main() {
}
sortedMatches := make([]string, 0)
for match := range uniqueMatches {
- match = match[len("usbID: "):]
- match = match[:34]
+ match = match[len(prefix+": "):]
+ match = match[:size]
sortedMatches = append(sortedMatches, match)
}
sort.Strings(sortedMatches)
+ return sortedMatches
+}
- usbIDs := make([]byte, 0)
- usbIDs = append(usbIDs, []byte("// AUTOGENERATED FILE\n")...)
- usbIDs = append(usbIDs, []byte("// See docs/linux/external_fuzzing_usb.md\n")...)
- usbIDs = append(usbIDs, []byte("\n")...)
- usbIDs = append(usbIDs, []byte("package linux\n")...)
- usbIDs = append(usbIDs, []byte("\n")...)
- usbIDs = append(usbIDs, []byte("var usbIDs = ")...)
- for i, match := range sortedMatches {
- decodedMatch, err := hex.DecodeString(match)
+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 hes string %v: %v", match, err)
+ failf("failed to decode hex string %v: %v", id, err)
}
prefix := "\t"
suffix := " +"
if i == 0 {
prefix = ""
}
- if i == len(sortedMatches)-1 {
+ if i == len(ids)-1 {
suffix = ""
}
- usbID := fmt.Sprintf("%v%#v%v\n", prefix, string(decodedMatch), suffix)
- usbIDs = append(usbIDs, []byte(usbID)...)
+ outputID := fmt.Sprintf("%v%#v%v\n", prefix, string(decodedID), suffix)
+ output = append(output, []byte(outputID)...)
}
- if err := osutil.WriteFile(args[1], usbIDs); err != nil {
- failf("failed to output file %v: %v", args[1], err)
- }
+ fmt.Printf("%v %s ids written\n", len(ids), name)
- fmt.Printf("%v ids written\n", len(sortedMatches))
+ return output
}
func usage() {