github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/sys/linux/init_vusb.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 linux
     5  
     6  import (
     7  	"encoding/binary"
     8  	"fmt"
     9  	"strings"
    10  
    11  	"github.com/google/syzkaller/prog"
    12  )
    13  
    14  const (
    15  	USB_DEVICE_ID_MATCH_VENDOR = 1 << iota
    16  	USB_DEVICE_ID_MATCH_PRODUCT
    17  	USB_DEVICE_ID_MATCH_DEV_LO
    18  	USB_DEVICE_ID_MATCH_DEV_HI
    19  	USB_DEVICE_ID_MATCH_DEV_CLASS
    20  	USB_DEVICE_ID_MATCH_DEV_SUBCLASS
    21  	USB_DEVICE_ID_MATCH_DEV_PROTOCOL
    22  	USB_DEVICE_ID_MATCH_INT_CLASS
    23  	USB_DEVICE_ID_MATCH_INT_SUBCLASS
    24  	USB_DEVICE_ID_MATCH_INT_PROTOCOL
    25  	USB_DEVICE_ID_MATCH_INT_NUMBER
    26  
    27  	BytesPerUsbID = 17
    28  	BytesPerHidID = 12
    29  )
    30  
    31  type UsbDeviceID struct {
    32  	MatchFlags         uint16
    33  	IDVendor           uint16
    34  	IDProduct          uint16
    35  	BcdDeviceLo        uint16
    36  	BcdDeviceHi        uint16
    37  	BDeviceClass       uint8
    38  	BDeviceSubClass    uint8
    39  	BDeviceProtocol    uint8
    40  	BInterfaceClass    uint8
    41  	BInterfaceSubClass uint8
    42  	BInterfaceProtocol uint8
    43  	BInterfaceNumber   uint8
    44  }
    45  
    46  type HidDeviceID struct {
    47  	Bus     uint16
    48  	Group   uint16
    49  	Vendor  uint32
    50  	Product uint32
    51  }
    52  
    53  func (arch *arch) generateUsbDeviceDescriptor(g *prog.Gen, typ0 prog.Type, dir prog.Dir, old prog.Arg) (
    54  	arg prog.Arg, calls []*prog.Call) {
    55  	if old == nil {
    56  		arg = g.GenerateSpecialArg(typ0, dir, &calls)
    57  	} else {
    58  		arg = prog.CloneArg(old)
    59  		calls = g.MutateArg(arg)
    60  	}
    61  	if g.Target().ArgContainsAny(arg) {
    62  		return
    63  	}
    64  
    65  	patchUsbDeviceID(g, &arg, calls, usbIdsAll, true)
    66  
    67  	return
    68  }
    69  
    70  func (arch *arch) generateUsbPrinterDeviceDescriptor(g *prog.Gen, typ0 prog.Type, dir prog.Dir, old prog.Arg) (
    71  	arg prog.Arg, calls []*prog.Call) {
    72  	if old == nil {
    73  		arg = g.GenerateSpecialArg(typ0, dir, &calls)
    74  	} else {
    75  		arg = prog.CloneArg(old)
    76  		calls = g.MutateArg(arg)
    77  	}
    78  	if g.Target().ArgContainsAny(arg) {
    79  		return
    80  	}
    81  
    82  	// Roll the dice to decide if and how we want to patch printer USB IDs.
    83  	switch {
    84  	case g.Rand().Intn(3) == 0:
    85  		// Syzlang descriptions already contain passable IDs, leave them as is.
    86  		return
    87  	case g.Rand().Intn(2) == 0:
    88  		// Patch in quirk IDs that are hardcoded in the USB printer class driver
    89  		// (and thus are not auto-extractable) to allow exercising driver quirks;
    90  		// see quirk_printers in drivers/usb/class/usblp.c.
    91  		var idVendor int16
    92  		var idProduct int16
    93  		if g.Rand().Intn(2) == 0 { // USBLP_QUIRK_BIDIR
    94  			idVendor = 0x03f0
    95  			idProduct = 0x0004
    96  		} else { // USBLP_QUIRK_BAD_CLASS
    97  			idVendor = 0x04b8
    98  			idProduct = 0x0202
    99  		}
   100  		devArg := arg.(*prog.GroupArg).Inner[0]
   101  		patchGroupArg(devArg, 7, "idVendor", uint64(idVendor))
   102  		patchGroupArg(devArg, 8, "idProduct", uint64(idProduct))
   103  	default:
   104  		// Patch in IDs auto-extracted from the matching rules for the USB printer class.
   105  		// Do not patch IDs that are not used in the matching rules to avoid subverting
   106  		// the kernel into matching the device to a different driver.
   107  		if ids, ok := usbIds["usblp"]; ok {
   108  			patchUsbDeviceID(g, &arg, calls, ids, false)
   109  		}
   110  	}
   111  
   112  	return
   113  }
   114  
   115  func patchUsbDeviceID(g *prog.Gen, arg *prog.Arg, calls []*prog.Call, ids string, patchNonMatching bool) {
   116  	id := randUsbDeviceID(g, ids, patchNonMatching)
   117  
   118  	devArg := (*arg).(*prog.GroupArg).Inner[0]
   119  	if (id.MatchFlags&USB_DEVICE_ID_MATCH_VENDOR) != 0 || patchNonMatching {
   120  		patchGroupArg(devArg, 7, "idVendor", uint64(id.IDVendor))
   121  	}
   122  	if (id.MatchFlags&USB_DEVICE_ID_MATCH_PRODUCT) != 0 || patchNonMatching {
   123  		patchGroupArg(devArg, 8, "idProduct", uint64(id.IDProduct))
   124  	}
   125  	if (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_LO) != 0 ||
   126  		(id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_HI) != 0 || patchNonMatching {
   127  		bcdDevice := id.BcdDeviceLo + uint16(g.Rand().Intn(int(id.BcdDeviceHi-id.BcdDeviceLo)+1))
   128  		patchGroupArg(devArg, 9, "bcdDevice", uint64(bcdDevice))
   129  	}
   130  	if (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_CLASS) != 0 || patchNonMatching {
   131  		patchGroupArg(devArg, 3, "bDeviceClass", uint64(id.BDeviceClass))
   132  	}
   133  	if (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS) != 0 || patchNonMatching {
   134  		patchGroupArg(devArg, 4, "bDeviceSubClass", uint64(id.BDeviceSubClass))
   135  	}
   136  	if (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL) != 0 || patchNonMatching {
   137  		patchGroupArg(devArg, 5, "bDeviceProtocol", uint64(id.BDeviceProtocol))
   138  	}
   139  
   140  	configArg := devArg.(*prog.GroupArg).Inner[14].(*prog.GroupArg).Inner[0].(*prog.GroupArg).Inner[0]
   141  	interfacesArg := configArg.(*prog.GroupArg).Inner[8]
   142  
   143  	for i, interfaceArg := range interfacesArg.(*prog.GroupArg).Inner {
   144  		interfaceArg = interfaceArg.(*prog.GroupArg).Inner[0]
   145  		if i > 0 {
   146  			// Generate new IDs for every interface after the first one.
   147  			id = randUsbDeviceID(g, ids, patchNonMatching)
   148  		}
   149  		if (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_CLASS) != 0 || patchNonMatching {
   150  			patchGroupArg(interfaceArg, 5, "bInterfaceClass", uint64(id.BInterfaceClass))
   151  		}
   152  		if (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS) != 0 || patchNonMatching {
   153  			patchGroupArg(interfaceArg, 6, "bInterfaceSubClass", uint64(id.BInterfaceSubClass))
   154  		}
   155  		if (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL) != 0 || patchNonMatching {
   156  			patchGroupArg(interfaceArg, 7, "bInterfaceProtocol", uint64(id.BInterfaceProtocol))
   157  		}
   158  		if (id.MatchFlags&USB_DEVICE_ID_MATCH_INT_NUMBER) != 0 || patchNonMatching {
   159  			patchGroupArg(interfaceArg, 2, "bInterfaceNumber", uint64(id.BInterfaceNumber))
   160  		}
   161  	}
   162  }
   163  
   164  func randUsbDeviceID(g *prog.Gen, ids string, patchNonMatching bool) UsbDeviceID {
   165  	totalIds := len(ids) / BytesPerUsbID
   166  	idNum := g.Rand().Intn(totalIds)
   167  	base := ids[idNum*BytesPerUsbID : (idNum+1)*BytesPerUsbID]
   168  
   169  	p := strings.NewReader(base)
   170  	var id UsbDeviceID
   171  	if binary.Read(p, binary.LittleEndian, &id) != nil {
   172  		panic("not enough data to read")
   173  	}
   174  
   175  	// Don't generate values for IDs that won't be patched in.
   176  	if !patchNonMatching {
   177  		return id
   178  	}
   179  
   180  	if (id.MatchFlags & USB_DEVICE_ID_MATCH_VENDOR) == 0 {
   181  		id.IDVendor = uint16(g.Rand().Intn(0xffff + 1))
   182  	}
   183  	if (id.MatchFlags & USB_DEVICE_ID_MATCH_PRODUCT) == 0 {
   184  		id.IDProduct = uint16(g.Rand().Intn(0xffff + 1))
   185  	}
   186  	if (id.MatchFlags & USB_DEVICE_ID_MATCH_DEV_LO) == 0 {
   187  		id.BcdDeviceLo = 0x0
   188  	}
   189  	if (id.MatchFlags & USB_DEVICE_ID_MATCH_DEV_HI) == 0 {
   190  		id.BcdDeviceHi = 0xffff
   191  	}
   192  	if (id.MatchFlags & USB_DEVICE_ID_MATCH_DEV_CLASS) == 0 {
   193  		id.BDeviceClass = uint8(g.Rand().Intn(0xff + 1))
   194  	}
   195  	if (id.MatchFlags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) == 0 {
   196  		id.BDeviceSubClass = uint8(g.Rand().Intn(0xff + 1))
   197  	}
   198  	if (id.MatchFlags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) == 0 {
   199  		id.BDeviceProtocol = uint8(g.Rand().Intn(0xff + 1))
   200  	}
   201  	if (id.MatchFlags & USB_DEVICE_ID_MATCH_INT_CLASS) == 0 {
   202  		id.BInterfaceClass = uint8(g.Rand().Intn(0xff + 1))
   203  	}
   204  	if (id.MatchFlags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) == 0 {
   205  		id.BInterfaceSubClass = uint8(g.Rand().Intn(0xff + 1))
   206  	}
   207  	if (id.MatchFlags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) == 0 {
   208  		id.BInterfaceProtocol = uint8(g.Rand().Intn(0xff + 1))
   209  	}
   210  	if (id.MatchFlags & USB_DEVICE_ID_MATCH_INT_NUMBER) == 0 {
   211  		id.BInterfaceNumber = uint8(g.Rand().Intn(0xff + 1))
   212  	}
   213  
   214  	return id
   215  }
   216  
   217  func (arch *arch) generateUsbHidDeviceDescriptor(g *prog.Gen, typ0 prog.Type, dir prog.Dir, old prog.Arg) (
   218  	arg prog.Arg, calls []*prog.Call) {
   219  	if old == nil {
   220  		arg = g.GenerateSpecialArg(typ0, dir, &calls)
   221  	} else {
   222  		arg = prog.CloneArg(old)
   223  		calls = g.MutateArg(arg)
   224  	}
   225  	if g.Target().ArgContainsAny(arg) {
   226  		return
   227  	}
   228  
   229  	totalIds := len(hidIdsAll) / BytesPerHidID
   230  	idNum := g.Rand().Intn(totalIds)
   231  	base := hidIdsAll[idNum*BytesPerHidID : (idNum+1)*BytesPerHidID]
   232  
   233  	p := strings.NewReader(base)
   234  	var id HidDeviceID
   235  	if binary.Read(p, binary.LittleEndian, &id) != nil {
   236  		panic("not enough data to read")
   237  	}
   238  
   239  	devArg := arg.(*prog.GroupArg).Inner[0]
   240  	patchGroupArg(devArg, 7, "idVendor", uint64(id.Vendor))
   241  	patchGroupArg(devArg, 8, "idProduct", uint64(id.Product))
   242  
   243  	return
   244  }
   245  
   246  func patchGroupArg(arg prog.Arg, index int, field string, value uint64) {
   247  	a := arg.(*prog.GroupArg)
   248  	typ := a.Type().(*prog.StructType)
   249  	if field != typ.Fields[index].Name {
   250  		panic(fmt.Sprintf("bad field, expected %v, found %v", field, typ.Fields[index].Name))
   251  	}
   252  	a.Inner[index].(*prog.ConstArg).Val = value
   253  }