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 }