aboutsummaryrefslogtreecommitdiffstats
path: root/sys/linux
diff options
context:
space:
mode:
authorAndrey Konovalov <andreyknvl@gmail.com>2025-08-20 12:49:45 +0000
committerAleksandr Nogikh <nogikh@google.com>2025-08-21 12:29:58 +0000
commita083215dfb83bea8c632990cd5232c159ebcc676 (patch)
tree2956df08e38295503485e3aa39b905f123deaeb1 /sys/linux
parentc908ebc6718922bde328972729832db68dd6bfa7 (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')
-rw-r--r--sys/linux/init.go27
-rw-r--r--sys/linux/init_vusb.go85
2 files changed, 83 insertions, 29 deletions
diff --git a/sys/linux/init.go b/sys/linux/init.go
index 4cf539023..1427cebb1 100644
--- a/sys/linux/init.go
+++ b/sys/linux/init.go
@@ -50,19 +50,20 @@ func InitTarget(target *prog.Target) {
target.Neutralize = arch.neutralize
target.SpecialTypes = map[string]func(g *prog.Gen, typ prog.Type, dir prog.Dir, old prog.Arg) (
prog.Arg, []*prog.Call){
- "timespec": arch.generateTimespec,
- "timeval": arch.generateTimespec,
- "sockaddr_alg": arch.generateSockaddrAlg,
- "alg_name": arch.generateAlgName,
- "alg_aead_name": arch.generateAlgAeadName,
- "alg_hash_name": arch.generateAlgHashName,
- "alg_skcipher_name": arch.generateAlgSkcipherhName,
- "ipt_replace": arch.generateIptables,
- "ip6t_replace": arch.generateIptables,
- "arpt_replace": arch.generateArptables,
- "ebt_replace": arch.generateEbtables,
- "usb_device_descriptor": arch.generateUsbDeviceDescriptor,
- "usb_device_descriptor_hid": arch.generateUsbHidDeviceDescriptor,
+ "timespec": arch.generateTimespec,
+ "timeval": arch.generateTimespec,
+ "sockaddr_alg": arch.generateSockaddrAlg,
+ "alg_name": arch.generateAlgName,
+ "alg_aead_name": arch.generateAlgAeadName,
+ "alg_hash_name": arch.generateAlgHashName,
+ "alg_skcipher_name": arch.generateAlgSkcipherhName,
+ "ipt_replace": arch.generateIptables,
+ "ip6t_replace": arch.generateIptables,
+ "arpt_replace": arch.generateArptables,
+ "ebt_replace": arch.generateEbtables,
+ "usb_device_descriptor": arch.generateUsbDeviceDescriptor,
+ "usb_device_descriptor_printer": arch.generateUsbPrinterDeviceDescriptor,
+ "usb_device_descriptor_hid": arch.generateUsbHidDeviceDescriptor,
}
target.AuxResources = map[string]bool{
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))
}