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

usbnet: fix skb traversing races during unlink(v2)

Commit 4231d47e6fe69f061f96c98c30eaf9fb4c14b96d(net/usbnet: avoid
recursive locking in usbnet_stop()) fixes the recursive locking
problem by releasing the skb queue lock before unlink, but may
cause skb traversing races:
- after URB is unlinked and the queue lock is released,
the refered skb and skb->next may be moved to done queue,
even be released
- in skb_queue_walk_safe, the next skb is still obtained
by next pointer of the last skb
- so maybe trigger oops or other problems

This patch extends the usage of entry->state to describe 'start_unlink'
state, so always holding the queue(rx/tx) lock to change the state if
the referd skb is in rx or tx queue because we need to know if the
refered urb has been started unlinking in unlink_urbs.

The other part of this patch is based on Huajun's patch:
always traverse from head of the tx/rx queue to get skb which is
to be unlinked but not been started unlinking.

Signed-off-by: Huajun Li <huajun.li.lee@gmail.com>
Signed-off-by: Ming Lei <tom.leiming@gmail.com>
Cc: Oliver Neukum <oneukum@suse.de>
Cc: stable@kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Ming Lei and committed by
David S. Miller
5b6e9bcd 8aa51d64

+40 -17
+38 -16
drivers/net/usb/usbnet.c
··· 282 282 } 283 283 EXPORT_SYMBOL_GPL(usbnet_change_mtu); 284 284 285 + /* The caller must hold list->lock */ 286 + static void __usbnet_queue_skb(struct sk_buff_head *list, 287 + struct sk_buff *newsk, enum skb_state state) 288 + { 289 + struct skb_data *entry = (struct skb_data *) newsk->cb; 290 + 291 + __skb_queue_tail(list, newsk); 292 + entry->state = state; 293 + } 294 + 285 295 /*-------------------------------------------------------------------------*/ 286 296 287 297 /* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from 288 298 * completion callbacks. 2.5 should have fixed those bugs... 289 299 */ 290 300 291 - static void defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_head *list) 301 + static enum skb_state defer_bh(struct usbnet *dev, struct sk_buff *skb, 302 + struct sk_buff_head *list, enum skb_state state) 292 303 { 293 304 unsigned long flags; 305 + enum skb_state old_state; 306 + struct skb_data *entry = (struct skb_data *) skb->cb; 294 307 295 308 spin_lock_irqsave(&list->lock, flags); 309 + old_state = entry->state; 310 + entry->state = state; 296 311 __skb_unlink(skb, list); 297 312 spin_unlock(&list->lock); 298 313 spin_lock(&dev->done.lock); ··· 315 300 if (dev->done.qlen == 1) 316 301 tasklet_schedule(&dev->bh); 317 302 spin_unlock_irqrestore(&dev->done.lock, flags); 303 + return old_state; 318 304 } 319 305 320 306 /* some work can't be done in tasklets, so we use keventd ··· 356 340 entry = (struct skb_data *) skb->cb; 357 341 entry->urb = urb; 358 342 entry->dev = dev; 359 - entry->state = rx_start; 360 343 entry->length = 0; 361 344 362 345 usb_fill_bulk_urb (urb, dev->udev, dev->in, ··· 387 372 tasklet_schedule (&dev->bh); 388 373 break; 389 374 case 0: 390 - __skb_queue_tail (&dev->rxq, skb); 375 + __usbnet_queue_skb(&dev->rxq, skb, rx_start); 391 376 } 392 377 } else { 393 378 netif_dbg(dev, ifdown, dev->net, "rx: stopped\n"); ··· 438 423 struct skb_data *entry = (struct skb_data *) skb->cb; 439 424 struct usbnet *dev = entry->dev; 440 425 int urb_status = urb->status; 426 + enum skb_state state; 441 427 442 428 skb_put (skb, urb->actual_length); 443 - entry->state = rx_done; 429 + state = rx_done; 444 430 entry->urb = NULL; 445 431 446 432 switch (urb_status) { 447 433 /* success */ 448 434 case 0: 449 435 if (skb->len < dev->net->hard_header_len) { 450 - entry->state = rx_cleanup; 436 + state = rx_cleanup; 451 437 dev->net->stats.rx_errors++; 452 438 dev->net->stats.rx_length_errors++; 453 439 netif_dbg(dev, rx_err, dev->net, ··· 487 471 "rx throttle %d\n", urb_status); 488 472 } 489 473 block: 490 - entry->state = rx_cleanup; 474 + state = rx_cleanup; 491 475 entry->urb = urb; 492 476 urb = NULL; 493 477 break; ··· 498 482 // FALLTHROUGH 499 483 500 484 default: 501 - entry->state = rx_cleanup; 485 + state = rx_cleanup; 502 486 dev->net->stats.rx_errors++; 503 487 netif_dbg(dev, rx_err, dev->net, "rx status %d\n", urb_status); 504 488 break; 505 489 } 506 490 507 - defer_bh(dev, skb, &dev->rxq); 491 + state = defer_bh(dev, skb, &dev->rxq, state); 508 492 509 493 if (urb) { 510 494 if (netif_running (dev->net) && 511 - !test_bit (EVENT_RX_HALT, &dev->flags)) { 495 + !test_bit (EVENT_RX_HALT, &dev->flags) && 496 + state != unlink_start) { 512 497 rx_submit (dev, urb, GFP_ATOMIC); 513 498 usb_mark_last_busy(dev->udev); 514 499 return; ··· 596 579 static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) 597 580 { 598 581 unsigned long flags; 599 - struct sk_buff *skb, *skbnext; 582 + struct sk_buff *skb; 600 583 int count = 0; 601 584 602 585 spin_lock_irqsave (&q->lock, flags); 603 - skb_queue_walk_safe(q, skb, skbnext) { 586 + while (!skb_queue_empty(q)) { 604 587 struct skb_data *entry; 605 588 struct urb *urb; 606 589 int retval; 607 590 608 - entry = (struct skb_data *) skb->cb; 591 + skb_queue_walk(q, skb) { 592 + entry = (struct skb_data *) skb->cb; 593 + if (entry->state != unlink_start) 594 + goto found; 595 + } 596 + break; 597 + found: 598 + entry->state = unlink_start; 609 599 urb = entry->urb; 610 600 611 601 /* ··· 1063 1039 } 1064 1040 1065 1041 usb_autopm_put_interface_async(dev->intf); 1066 - entry->state = tx_done; 1067 - defer_bh(dev, skb, &dev->txq); 1042 + (void) defer_bh(dev, skb, &dev->txq, tx_done); 1068 1043 } 1069 1044 1070 1045 /*-------------------------------------------------------------------------*/ ··· 1119 1096 entry = (struct skb_data *) skb->cb; 1120 1097 entry->urb = urb; 1121 1098 entry->dev = dev; 1122 - entry->state = tx_start; 1123 1099 entry->length = length; 1124 1100 1125 1101 usb_fill_bulk_urb (urb, dev->udev, dev->out, ··· 1177 1155 break; 1178 1156 case 0: 1179 1157 net->trans_start = jiffies; 1180 - __skb_queue_tail (&dev->txq, skb); 1158 + __usbnet_queue_skb(&dev->txq, skb, tx_start); 1181 1159 if (dev->txq.qlen >= TX_QLEN (dev)) 1182 1160 netif_stop_queue (net); 1183 1161 }
+2 -1
include/linux/usb/usbnet.h
··· 191 191 enum skb_state { 192 192 illegal = 0, 193 193 tx_start, tx_done, 194 - rx_start, rx_done, rx_cleanup 194 + rx_start, rx_done, rx_cleanup, 195 + unlink_start 195 196 }; 196 197 197 198 struct skb_data { /* skb->cb is one of these */