github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/tools/syz-usbgen/usbgen.go (about) 1 // Copyright 2019 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package main 5 6 import ( 7 "encoding/hex" 8 "flag" 9 "fmt" 10 "os" 11 "regexp" 12 "sort" 13 14 "github.com/google/syzkaller/pkg/osutil" 15 "github.com/google/syzkaller/pkg/tool" 16 ) 17 18 func main() { 19 flag.Parse() 20 args := flag.Args() 21 if len(args) != 2 { 22 usage() 23 } 24 25 syslog, err := os.ReadFile(args[0]) 26 if err != nil { 27 tool.Failf("failed to read file %v: %v", args[0], err) 28 } 29 30 usbIds := extractIds(syslog, "USBID", 34) 31 hidIds := extractIds(syslog, "HIDID", 24) 32 33 output := []byte(`// Code generated by tools/syz-usbgen. DO NOT EDIT. 34 // See docs/linux/external_fuzzing_usb.md 35 36 package linux 37 38 `) 39 output = append(output, generateIdsVar(usbIds, "usbIds")...) 40 output = append(output, []byte("\n")...) 41 output = append(output, generateIdsVar(hidIds, "hidIds")...) 42 43 if err := osutil.WriteFile(args[1], output); err != nil { 44 tool.Failf("failed to output file %v: %v", args[1], err) 45 } 46 } 47 48 func extractIds(syslog []byte, prefix string, size int) map[string][]string { 49 re := fmt.Sprintf("%s: ([0-9a-f]{%d}) \\((.+)\\)", prefix, size) 50 r := regexp.MustCompile(re) 51 matches := r.FindAllSubmatch(syslog, -1) 52 // Map from matching substring to capture groups. 53 uniqueMatches := make(map[string][][]byte) 54 for _, match := range matches { 55 uniqueMatches[string(match[0])] = match[1:] 56 } 57 // Map from driver name to slice of USB IDs. 58 driverIDs := make(map[string][]string, 0) 59 for _, groups := range uniqueMatches { 60 id := string(groups[0]) 61 driver := string(groups[1]) 62 driverIDs[driver] = append(driverIDs[driver], id) 63 } 64 // Keep IDs sorted for consistent output between runs. 65 for driver := range driverIDs { 66 sort.Strings(driverIDs[driver]) 67 } 68 return driverIDs 69 } 70 71 func generateIdsVar(driverIDs map[string][]string, name string) []byte { 72 // Sort driver names for consistent output between runs. 73 drivers := make([]string, 0, len(driverIDs)) 74 for driver := range driverIDs { 75 drivers = append(drivers, driver) 76 } 77 sort.Strings(drivers) 78 79 // Generate a map variable that stores USB IDs for each driver. 80 totalIDs := 0 81 output := []byte(fmt.Sprintf("var %s = map[string]string{\n", name)) 82 for _, driver := range drivers { 83 ids := driverIDs[driver] 84 outputDriver := fmt.Sprintf("\t\"%s\": ", driver) 85 output = append(output, []byte(outputDriver)...) 86 for i, id := range ids { 87 decodedID, err := hex.DecodeString(id) 88 if err != nil { 89 tool.Failf("failed to decode hex string %v: %v", id, err) 90 } 91 prefix := "\t\t" 92 suffix := " +" 93 if i == 0 { 94 prefix = "" 95 } 96 if i == len(ids)-1 { 97 suffix = "," 98 } 99 outputID := fmt.Sprintf("%v%#v%v\n", prefix, string(decodedID), suffix) 100 output = append(output, []byte(outputID)...) 101 } 102 totalIDs += len(ids) 103 } 104 output = append(output, []byte("}\n\n")...) 105 106 // Generate a variable that stores all USB IDs together. 107 output = append(output, []byte(fmt.Sprintf("var %sAll = ", name))...) 108 for i, driver := range drivers { 109 prefix := "\t" 110 suffix := " +" 111 if i == 0 { 112 prefix = "" 113 } 114 if i == len(drivers)-1 { 115 suffix = "" 116 } 117 outputDriver := fmt.Sprintf("%v%s[\"%s\"]%v\n", prefix, name, driver, suffix) 118 output = append(output, []byte(outputDriver)...) 119 } 120 if len(drivers) == 0 { 121 output = append(output, []byte("\"\"")...) 122 } 123 124 fmt.Printf("%v %s ids written\n", totalIDs, name) 125 126 return output 127 } 128 129 func usage() { 130 fmt.Fprintf(os.Stderr, "usage:\n") 131 fmt.Fprintf(os.Stderr, " syz-usbgen syslog.txt sys/linux/init_vusb_ids.go\n") 132 os.Exit(1) 133 }