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  }