diff options
| author | Andrey Konovalov <andreyknvl@gmail.com> | 2025-08-20 12:49:45 +0000 |
|---|---|---|
| committer | Aleksandr Nogikh <nogikh@google.com> | 2025-08-21 12:29:58 +0000 |
| commit | a083215dfb83bea8c632990cd5232c159ebcc676 (patch) | |
| tree | 2956df08e38295503485e3aa39b905f123deaeb1 /sys/linux/init_vusb.go | |
| parent | c908ebc6718922bde328972729832db68dd6bfa7 (diff) | |
sys/linux: patch in auto-extracted USB IDs for printer class
This allows exercising driver quirks that might be defined in the matching
rules (the printer driver does not actually define any yet, but this
change serves as a reference for doing this for other drivers).
Only patch in the IDs that are used in the matching rules of the printer
driver in the kernel. Patching other IDs might subvert the kernel into
matching the emulated device to a different driver.
Diffstat (limited to 'sys/linux/init_vusb.go')
| -rw-r--r-- | sys/linux/init_vusb.go | 85 |
1 files changed, 69 insertions, 16 deletions
diff --git a/sys/linux/init_vusb.go b/sys/linux/init_vusb.go index 29ec51e7e..caa050763 100644 --- a/sys/linux/init_vusb.go +++ b/sys/linux/init_vusb.go @@ -62,22 +62,62 @@ func (arch *arch) generateUsbDeviceDescriptor(g *prog.Gen, typ0 prog.Type, dir p return } - patchUsbDeviceID(g, &arg, calls, usbIdsAll) + patchUsbDeviceID(g, &arg, calls, usbIdsAll, true) return } -func patchUsbDeviceID(g *prog.Gen, arg *prog.Arg, calls []*prog.Call, ids string) { - id := randUsbDeviceID(g, ids) - bcdDevice := id.BcdDeviceLo + uint16(g.Rand().Intn(int(id.BcdDeviceHi-id.BcdDeviceLo)+1)) +func (arch *arch) generateUsbPrinterDeviceDescriptor(g *prog.Gen, typ0 prog.Type, dir prog.Dir, old prog.Arg) ( + arg prog.Arg, calls []*prog.Call) { + if old == nil { + arg = g.GenerateSpecialArg(typ0, dir, &calls) + } else { + arg = prog.CloneArg(old) + calls = g.MutateArg(arg) + } + if g.Target().ArgContainsAny(arg) { + return + } + + // syzlang descriptions already contain passable IDs. + // Roll the dice to decide if we want to patch them. + if g.Rand().Intn(2) == 0 { + return + } + + // Patch in IDs specific to the USB printer class. + // Only patch IDs that are used in the driver matching rules. + if ids, ok := usbIds["usblp"]; ok { + patchUsbDeviceID(g, &arg, calls, ids, false) + } + + return +} + +func patchUsbDeviceID(g *prog.Gen, arg *prog.Arg, calls []*prog.Call, ids string, patchNonMatching bool) { + id := randUsbDeviceID(g, ids, patchNonMatching) devArg := (*arg).(*prog.GroupArg).Inner[0] - patchGroupArg(devArg, 7, "idVendor", uint64(id.IDVendor)) - patchGroupArg(devArg, 8, "idProduct", uint64(id.IDProduct)) - patchGroupArg(devArg, 9, "bcdDevice", uint64(bcdDevice)) - patchGroupArg(devArg, 3, "bDeviceClass", uint64(id.BDeviceClass)) - patchGroupArg(devArg, 4, "bDeviceSubClass", uint64(id.BDeviceSubClass)) - patchGroupArg(devArg, 5, "bDeviceProtocol", uint64(id.BDeviceProtocol)) + if (id.MatchFlags&USB_DEVICE_ID_MATCH_VENDOR) != 0 || patchNonMatching { + patchGroupArg(devArg, 7, "idVendor", uint64(id.IDVendor)) + } + if (id.MatchFlags&USB_DEVICE_ID_MATCH_PRODUCT) != 0 || patchNonMatching { + patchGroupArg(devArg, 8, "idProduct", uint64(id.IDProduct)) + } + if (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_LO) != 0 || + (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_HI) != 0 || patchNonMatching { + bcdDevice := id.BcdDeviceLo + uint16(g.Rand().Intn(int(id.BcdDeviceHi-id.BcdDeviceLo)+1)) + patchGroupArg(devArg, 9, "bcdDevice", uint64(bcdDevice)) + } + if (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_CLASS) != 0 || patchNonMatching { + patchGroupArg(devArg, 3, "bDeviceClass", uint64(id.BDeviceClass)) + } + if (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS) != 0 || patchNonMatching { + patchGroupArg(devArg, 4, "bDeviceSubClass", uint64(id.BDeviceSubClass)) + } + if (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL) != 0 || patchNonMatching { + patchGroupArg(devArg, 5, "bDeviceProtocol", uint64(id.BDeviceProtocol)) + } configArg := devArg.(*prog.GroupArg).Inner[14].(*prog.GroupArg).Inner[0].(*prog.GroupArg).Inner[0] interfacesArg := configArg.(*prog.GroupArg).Inner[8] @@ -86,16 +126,24 @@ func patchUsbDeviceID(g *prog.Gen, arg *prog.Arg, calls []*prog.Call, ids string interfaceArg = interfaceArg.(*prog.GroupArg).Inner[0] if i > 0 { // Generate new IDs for every interface after the first one. - id = randUsbDeviceID(g, ids) + id = randUsbDeviceID(g, ids, patchNonMatching) + } + if (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_CLASS) != 0 || patchNonMatching { + patchGroupArg(interfaceArg, 5, "bInterfaceClass", uint64(id.BInterfaceClass)) + } + if (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS) != 0 || patchNonMatching { + patchGroupArg(interfaceArg, 6, "bInterfaceSubClass", uint64(id.BInterfaceSubClass)) + } + if (id.MatchFlags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL) != 0 || patchNonMatching { + patchGroupArg(interfaceArg, 7, "bInterfaceProtocol", uint64(id.BInterfaceProtocol)) + } + if (id.MatchFlags&USB_DEVICE_ID_MATCH_INT_NUMBER) != 0 || patchNonMatching { + patchGroupArg(interfaceArg, 2, "bInterfaceNumber", uint64(id.BInterfaceNumber)) } - patchGroupArg(interfaceArg, 5, "bInterfaceClass", uint64(id.BInterfaceClass)) - patchGroupArg(interfaceArg, 6, "bInterfaceSubClass", uint64(id.BInterfaceSubClass)) - patchGroupArg(interfaceArg, 7, "bInterfaceProtocol", uint64(id.BInterfaceProtocol)) - patchGroupArg(interfaceArg, 2, "bInterfaceNumber", uint64(id.BInterfaceNumber)) } } -func randUsbDeviceID(g *prog.Gen, ids string) UsbDeviceID { +func randUsbDeviceID(g *prog.Gen, ids string, patchNonMatching bool) UsbDeviceID { totalIds := len(ids) / BytesPerUsbID idNum := g.Rand().Intn(totalIds) base := ids[idNum*BytesPerUsbID : (idNum+1)*BytesPerUsbID] @@ -106,6 +154,11 @@ func randUsbDeviceID(g *prog.Gen, ids string) UsbDeviceID { panic("not enough data to read") } + // Don't generate values for IDs that won't be patched in. + if !patchNonMatching { + return id + } + if (id.MatchFlags & USB_DEVICE_ID_MATCH_VENDOR) == 0 { id.IDVendor = uint16(g.Rand().Intn(0xffff + 1)) } |
