diff options
| author | Andrey Konovalov <andreyknvl@google.com> | 2019-07-22 19:25:54 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-07-22 19:25:54 +0200 |
| commit | 55e0c07757deebc0c6094915fae19fc0959849e4 (patch) | |
| tree | aef999dbc037a017cdb142fca9911223d0bd1c3f /tools/syz-usbgen | |
| parent | 6a786da97c822c3ad536290c412f472e58342c91 (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.patch | 98 | ||||
| -rw-r--r-- | tools/syz-usbgen/usbgen.go | 55 |
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() { |
