Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xhci: Fix kernel oops in trace_xhci_free_virt_device

commit 44a182b9d177 ("xhci: Fix use-after-free in xhci_free_virt_device")
set dev->udev pointer to NULL in xhci_free_dev(), it will cause kernel
panic in trace_xhci_free_virt_device. This patch reimplement the trace
function trace_xhci_free_virt_device, remove dev->udev dereference and
added more useful parameters to show in the trace function,it also makes
sure dev->udev is not NULL before calling trace_xhci_free_virt_device.
This issue happened when xhci-hcd trace is enabled and USB devices hot
plug test. Original use-after-free patch went to stable so this needs so
be applied there as well.

[ 1092.022457] usb 2-4: USB disconnect, device number 6
[ 1092.092772] BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
[ 1092.101694] PGD 0 P4D 0
[ 1092.104601] Oops: 0000 [#1] SMP
[ 1092.207734] Workqueue: usb_hub_wq hub_event
[ 1092.212507] RIP: 0010:trace_event_raw_event_xhci_log_virt_dev+0x6c/0xf0
[ 1092.220050] RSP: 0018:ffff8c252e883d28 EFLAGS: 00010086
[ 1092.226024] RAX: ffff8c24af86fa84 RBX: 0000000000000003 RCX: ffff8c25255c2a01
[ 1092.234130] RDX: 0000000000000000 RSI: 00000000aef55009 RDI: ffff8c252e883d28
[ 1092.242242] RBP: ffff8c252550e2c0 R08: ffff8c24af86fa84 R09: 0000000000000a70
[ 1092.250364] R10: 0000000000000a70 R11: 0000000000000000 R12: ffff8c251f21a000
[ 1092.258468] R13: 000000000000000c R14: ffff8c251f21a000 R15: ffff8c251f432f60
[ 1092.266572] FS: 0000000000000000(0000) GS:ffff8c252e880000(0000) knlGS:0000000000000000
[ 1092.275757] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1092.282281] CR2: 0000000000000000 CR3: 0000000154209001 CR4: 00000000003606e0
[ 1092.290384] Call Trace:
[ 1092.293156] <IRQ>
[ 1092.295439] xhci_free_virt_device.part.34+0x182/0x1a0
[ 1092.301288] handle_cmd_completion+0x7ac/0xfa0
[ 1092.306336] ? trace_event_raw_event_xhci_log_trb+0x6e/0xa0
[ 1092.312661] xhci_irq+0x3e8/0x1f60
[ 1092.316524] __handle_irq_event_percpu+0x75/0x180
[ 1092.321876] handle_irq_event_percpu+0x20/0x50
[ 1092.326922] handle_irq_event+0x36/0x60
[ 1092.331273] handle_edge_irq+0x6d/0x180
[ 1092.335644] handle_irq+0x16/0x20
[ 1092.339417] do_IRQ+0x41/0xc0
[ 1092.342782] common_interrupt+0xf/0xf
[ 1092.346955] </IRQ>

Fixes: 44a182b9d177 ("xhci: Fix use-after-free in xhci_free_virt_device")
Cc: <stable@vger.kernel.org>
Signed-off-by: Zhengjun Xing <zhengjun.xing@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Zhengjun Xing and committed by
Greg Kroah-Hartman
d850c165 229bc19f

+33 -7
+2 -2
drivers/usb/host/xhci-mem.c
··· 886 886 887 887 dev = xhci->devs[slot_id]; 888 888 889 - trace_xhci_free_virt_device(dev); 890 - 891 889 xhci->dcbaa->dev_context_ptrs[slot_id] = 0; 892 890 if (!dev) 893 891 return; 892 + 893 + trace_xhci_free_virt_device(dev); 894 894 895 895 if (dev->tt_info) 896 896 old_active_eps = dev->tt_info->active_eps;
+31 -5
drivers/usb/host/xhci-trace.h
··· 171 171 TP_ARGS(ring, trb) 172 172 ); 173 173 174 + DECLARE_EVENT_CLASS(xhci_log_free_virt_dev, 175 + TP_PROTO(struct xhci_virt_device *vdev), 176 + TP_ARGS(vdev), 177 + TP_STRUCT__entry( 178 + __field(void *, vdev) 179 + __field(unsigned long long, out_ctx) 180 + __field(unsigned long long, in_ctx) 181 + __field(u8, fake_port) 182 + __field(u8, real_port) 183 + __field(u16, current_mel) 184 + 185 + ), 186 + TP_fast_assign( 187 + __entry->vdev = vdev; 188 + __entry->in_ctx = (unsigned long long) vdev->in_ctx->dma; 189 + __entry->out_ctx = (unsigned long long) vdev->out_ctx->dma; 190 + __entry->fake_port = (u8) vdev->fake_port; 191 + __entry->real_port = (u8) vdev->real_port; 192 + __entry->current_mel = (u16) vdev->current_mel; 193 + ), 194 + TP_printk("vdev %p ctx %llx | %llx fake_port %d real_port %d current_mel %d", 195 + __entry->vdev, __entry->in_ctx, __entry->out_ctx, 196 + __entry->fake_port, __entry->real_port, __entry->current_mel 197 + ) 198 + ); 199 + 200 + DEFINE_EVENT(xhci_log_free_virt_dev, xhci_free_virt_device, 201 + TP_PROTO(struct xhci_virt_device *vdev), 202 + TP_ARGS(vdev) 203 + ); 204 + 174 205 DECLARE_EVENT_CLASS(xhci_log_virt_dev, 175 206 TP_PROTO(struct xhci_virt_device *vdev), 176 207 TP_ARGS(vdev), ··· 235 204 ); 236 205 237 206 DEFINE_EVENT(xhci_log_virt_dev, xhci_alloc_virt_device, 238 - TP_PROTO(struct xhci_virt_device *vdev), 239 - TP_ARGS(vdev) 240 - ); 241 - 242 - DEFINE_EVENT(xhci_log_virt_dev, xhci_free_virt_device, 243 207 TP_PROTO(struct xhci_virt_device *vdev), 244 208 TP_ARGS(vdev) 245 209 );