The attached program, which acts via usbip as a USB device or hub, causes my linux machines to dereference some NULL pointers in drivers/usb/core/hub.c. These are places where udev->maxchild > 0, but either usb_hub_to_struct_hub(udev) returns NULL, or the returned hub has hub->ports == NULL. This is one such place: static void recursively_mark_NOTATTACHED(struct usb_device *udev) { struct usb_hub *hub = usb_hub_to_struct_hub(udev); int i; for (i = 0; i < udev->maxchild; ++i) { if (hub->ports[i]->child) And this: static void hub_disconnect_children(struct usb_device *udev) { struct usb_hub *hub = usb_hub_to_struct_hub(udev); int i; /* Free up all the children before we remove this device */ for (i = 0; i < udev->maxchild; i++) { if (hub->ports[i]->child) This can see NULL hub->ports: void usb_hub_adjust_deviceremovable(struct usb_device *hdev, struct usb_hub_descriptor *desc) { struct usb_hub *hub = usb_hub_to_struct_hub(hdev); enum usb_port_connect_type connect_type; int i; if (!hub) return; if (!hub_is_superspeed(hdev)) { for (i = 1; i <= hdev->maxchild; i++) { struct usb_port *port_dev = hub->ports[i - 1]; This can see a NULL hub: static int hub_set_address(struct usb_device *udev, int devnum) { int retval; unsigned int timeout_ms = USB_CTRL_SET_TIMEOUT; struct usb_hcd *hcd = bus_to_hcd(udev->bus); struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); if (hub->hdev->quirks & USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT) I've attached a demo that runs into some of these NULL dereferences. It depends on being able to run usbip (and modeprobe vhci-hcd). # uname -a Linux xxx 6.13.0-rc3-00017-gf44d154d6e3d #14 SMP Mon Jan 20 04:52:59 EST 2025 x86_64 x86_64 x86_64 GNU/Linux # cc usbhub11b.c # ./a.out ... hub 1-1:1.16: bad descriptor, ignoring hub hub 1-1:1.16: probe with driver hub failed with error -5 BUG: kernel NULL pointer dereference, address: 0000000000000250 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 0 P4D 0 Oops: Oops: 0000 [#1] SMP DEBUG_PAGEALLOC PTI CPU: 8 UID: 0 PID: 302 Comm: kworker/8:1 Not tainted 6.13.0-rc3-00017-gf44d154d6 e3d #14 Hardware name: FreeBSD BHYVE/BHYVE, BIOS 14.0 10/17/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:recursively_mark_NOTATTACHED+0x37/0x90 Code: 48 85 ff 74 71 4c 8b a7 18 04 00 00 4d 85 e4 74 13 85 c0 74 3a 49 8b 94 24 98 00 00 00 4c 8b a2 c8 00 00 00 85 c0 7e 27 31 db <49> 8b 84 24 50 02 00 00 48 8b 04 d8 48 8b 38 48 85 ff 74 05 e8 b0 RSP: 0018:ffffc9000096bd28 EFLAGS: 00010046 RAX: 0000000000000001 RBX: 0000000000000000 RCX: ffff888106224c00 RDX: ffff8881037bc000 RSI: 0000000000000007 RDI: ffff88810a502000 RBP: ffff88810a502000 R08: 000000000000005a R09: 0000000000000000 R10: ffff88810a502000 R11: ffff88810a502000 R12: 0000000000000000 R13: ffff88810a502000 R14: ffff8881062241f0 R15: 0000000000000001 FS: 0000000000000000(0000) GS:ffff88842dc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000250 CR3: 0000000003636001 CR4: 00000000003706f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: <TASK> ? __die+0x1e/0x60 ? page_fault_oops+0x157/0x450 ? set_track_prepare+0x3b/0x60 ? usb_control_msg+0xfd/0x150 ? check_bytes_and_report.isra.0+0x48/0x120 ? exc_page_fault+0x66/0x140 ? asm_exc_page_fault+0x26/0x30 ? recursively_mark_NOTATTACHED+0x37/0x90 ? usb_control_msg+0xfd/0x150 usb_disconnect+0x37/0x2c0 hub_event+0xc8f/0x1870 usb_disconnect+0x37/0x2c0 hub_event+0xc8f/0x1870 ? trace_event_raw_event_sched_switch+0x51/0x150 process_one_work+0x13f/0x330 worker_thread+0x25a/0x370 ? _raw_spin_unlock_irqrestore+0xd/0x20 ? __pfx_worker_thread+0x10/0x10 kthread+0xdc/0x110 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x2f/0x50 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK> Robert Morris rtm@xxxxxxx
Attachment:
usbhub11b.c
Description: Binary data