stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Greg KH <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: torvalds@linux-foundation.org, akpm@linux-foundation.org,
	alan@lxorguk.ukuu.org.uk, Huajun Li <huajun.li.lee@gmail.com>,
	Ming Lei <tom.leiming@gmail.com>, Oliver Neukum <oneukum@suse.de>,
	"David S. Miller" <davem@davemloft.net>
Subject: [ 05/47] usbnet: fix skb traversing races during unlink(v2)
Date: Fri, 18 May 2012 14:26:54 -0700	[thread overview]
Message-ID: <20120518212649.707728445@linuxfoundation.org> (raw)
In-Reply-To: <20120518212701.GA5023@kroah.com>

3.3-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Ming Lei <tom.leiming@gmail.com>

commit 5b6e9bcdeb65634b4ad604eb4536404bbfc62cfa upstream.

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>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

---
 drivers/net/usb/usbnet.c   |   54 +++++++++++++++++++++++++++++++--------------
 include/linux/usb/usbnet.h |    3 +-
 2 files changed, 40 insertions(+), 17 deletions(-)

--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -281,17 +281,32 @@ int usbnet_change_mtu (struct net_device
 }
 EXPORT_SYMBOL_GPL(usbnet_change_mtu);
 
+/* The caller must hold list->lock */
+static void __usbnet_queue_skb(struct sk_buff_head *list,
+			struct sk_buff *newsk, enum skb_state state)
+{
+	struct skb_data *entry = (struct skb_data *) newsk->cb;
+
+	__skb_queue_tail(list, newsk);
+	entry->state = state;
+}
+
 /*-------------------------------------------------------------------------*/
 
 /* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from
  * completion callbacks.  2.5 should have fixed those bugs...
  */
 
-static void defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_head *list)
+static enum skb_state defer_bh(struct usbnet *dev, struct sk_buff *skb,
+		struct sk_buff_head *list, enum skb_state state)
 {
 	unsigned long		flags;
+	enum skb_state 		old_state;
+	struct skb_data *entry = (struct skb_data *) skb->cb;
 
 	spin_lock_irqsave(&list->lock, flags);
+	old_state = entry->state;
+	entry->state = state;
 	__skb_unlink(skb, list);
 	spin_unlock(&list->lock);
 	spin_lock(&dev->done.lock);
@@ -299,6 +314,7 @@ static void defer_bh(struct usbnet *dev,
 	if (dev->done.qlen == 1)
 		tasklet_schedule(&dev->bh);
 	spin_unlock_irqrestore(&dev->done.lock, flags);
+	return old_state;
 }
 
 /* some work can't be done in tasklets, so we use keventd
@@ -339,7 +355,6 @@ static int rx_submit (struct usbnet *dev
 	entry = (struct skb_data *) skb->cb;
 	entry->urb = urb;
 	entry->dev = dev;
-	entry->state = rx_start;
 	entry->length = 0;
 
 	usb_fill_bulk_urb (urb, dev->udev, dev->in,
@@ -371,7 +386,7 @@ static int rx_submit (struct usbnet *dev
 			tasklet_schedule (&dev->bh);
 			break;
 		case 0:
-			__skb_queue_tail (&dev->rxq, skb);
+			__usbnet_queue_skb(&dev->rxq, skb, rx_start);
 		}
 	} else {
 		netif_dbg(dev, ifdown, dev->net, "rx: stopped\n");
@@ -422,16 +437,17 @@ static void rx_complete (struct urb *urb
 	struct skb_data		*entry = (struct skb_data *) skb->cb;
 	struct usbnet		*dev = entry->dev;
 	int			urb_status = urb->status;
+	enum skb_state		state;
 
 	skb_put (skb, urb->actual_length);
-	entry->state = rx_done;
+	state = rx_done;
 	entry->urb = NULL;
 
 	switch (urb_status) {
 	/* success */
 	case 0:
 		if (skb->len < dev->net->hard_header_len) {
-			entry->state = rx_cleanup;
+			state = rx_cleanup;
 			dev->net->stats.rx_errors++;
 			dev->net->stats.rx_length_errors++;
 			netif_dbg(dev, rx_err, dev->net,
@@ -470,7 +486,7 @@ static void rx_complete (struct urb *urb
 				  "rx throttle %d\n", urb_status);
 		}
 block:
-		entry->state = rx_cleanup;
+		state = rx_cleanup;
 		entry->urb = urb;
 		urb = NULL;
 		break;
@@ -481,17 +497,18 @@ block:
 		// FALLTHROUGH
 
 	default:
-		entry->state = rx_cleanup;
+		state = rx_cleanup;
 		dev->net->stats.rx_errors++;
 		netif_dbg(dev, rx_err, dev->net, "rx status %d\n", urb_status);
 		break;
 	}
 
-	defer_bh(dev, skb, &dev->rxq);
+	state = defer_bh(dev, skb, &dev->rxq, state);
 
 	if (urb) {
 		if (netif_running (dev->net) &&
-		    !test_bit (EVENT_RX_HALT, &dev->flags)) {
+		    !test_bit (EVENT_RX_HALT, &dev->flags) &&
+		    state != unlink_start) {
 			rx_submit (dev, urb, GFP_ATOMIC);
 			return;
 		}
@@ -577,16 +594,23 @@ EXPORT_SYMBOL_GPL(usbnet_purge_paused_rx
 static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
 {
 	unsigned long		flags;
-	struct sk_buff		*skb, *skbnext;
+	struct sk_buff		*skb;
 	int			count = 0;
 
 	spin_lock_irqsave (&q->lock, flags);
-	skb_queue_walk_safe(q, skb, skbnext) {
+	while (!skb_queue_empty(q)) {
 		struct skb_data		*entry;
 		struct urb		*urb;
 		int			retval;
 
-		entry = (struct skb_data *) skb->cb;
+		skb_queue_walk(q, skb) {
+			entry = (struct skb_data *) skb->cb;
+			if (entry->state != unlink_start)
+				goto found;
+		}
+		break;
+found:
+		entry->state = unlink_start;
 		urb = entry->urb;
 
 		/*
@@ -1037,8 +1061,7 @@ static void tx_complete (struct urb *urb
 	}
 
 	usb_autopm_put_interface_async(dev->intf);
-	entry->state = tx_done;
-	defer_bh(dev, skb, &dev->txq);
+	(void) defer_bh(dev, skb, &dev->txq, tx_done);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1094,7 +1117,6 @@ netdev_tx_t usbnet_start_xmit (struct sk
 	entry = (struct skb_data *) skb->cb;
 	entry->urb = urb;
 	entry->dev = dev;
-	entry->state = tx_start;
 	entry->length = length;
 
 	usb_fill_bulk_urb (urb, dev->udev, dev->out,
@@ -1153,7 +1175,7 @@ netdev_tx_t usbnet_start_xmit (struct sk
 		break;
 	case 0:
 		net->trans_start = jiffies;
-		__skb_queue_tail (&dev->txq, skb);
+		__usbnet_queue_skb(&dev->txq, skb, tx_start);
 		if (dev->txq.qlen >= TX_QLEN (dev))
 			netif_stop_queue (net);
 	}
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -191,7 +191,8 @@ extern void usbnet_cdc_status(struct usb
 enum skb_state {
 	illegal = 0,
 	tx_start, tx_done,
-	rx_start, rx_done, rx_cleanup
+	rx_start, rx_done, rx_cleanup,
+	unlink_start
 };
 
 struct skb_data {	/* skb->cb is one of these */



  parent reply	other threads:[~2012-05-18 21:26 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-05-18 21:27 [ 00/47] 3.3.7-stable review Greg KH
2012-05-18 21:26 ` [ 01/47] ALSA: echoaudio: Remove incorrect part of assertion Greg KH
2012-05-18 21:26 ` [ 02/47] ALSA: HDA: Lessen CPU usage when waiting for chip to respond Greg KH
2012-05-18 21:26 ` [ 03/47] ALSA: hda/realtek - Add missing CD-input pin for MSI-7350 mobo Greg KH
2012-05-18 21:26 ` [ 04/47] ALSA: hda/idt - Fix power-map for speaker-pins with some HP laptops Greg KH
2012-05-18 21:26 ` Greg KH [this message]
2012-05-18 21:26 ` [ 06/47] namespaces, pid_ns: fix leakage on fork() failure Greg KH
2012-05-18 21:26 ` [ 07/47] sparc64: Do not clobber %g2 in xcall_fetch_glob_regs() Greg KH
2012-05-18 21:26 ` [ 08/47] media: marvell-cam: fix an ARM build error Greg KH
2012-05-18 21:26 ` [ 09/47] ARM: 7417/1: vfp: ensure preemption is disabled when enabling VFP access Greg KH
2012-05-18 21:26 ` [ 10/47] ARM: prevent VM_GROWSDOWN mmaps extending below FIRST_USER_ADDRESS Greg KH
2012-05-18 21:27 ` [ 11/47] media: s5p-fimc: Fix locking in subdev set_crop op Greg KH
2012-05-18 21:27 ` [ 12/47] media: rc: Postpone ISR registration Greg KH
2012-05-18 21:27 ` [ 13/47] media: dvb_frontend: fix a regression with DVB-S zig-zag Greg KH
2012-05-18 21:27 ` [ 14/47] ASoC: cs42l73: Sync digital mixer kcontrols to allow for 0dB Greg KH
2012-05-18 21:27 ` [ 15/47] ASoC: wm8994: Fix AIF2ADC power down Greg KH
2012-05-18 21:27 ` [ 16/47] cdc_ether: Ignore bogus union descriptor for RNDIS devices Greg KH
2012-05-18 21:27 ` [ 17/47] cdc_ether: add Novatel USB551L device IDs for FLAG_WWAN Greg KH
2012-05-18 21:27 ` [ 18/47] percpu: pcpu_embed_first_chunk() should free unused parts after all allocs are complete Greg KH
2012-05-18 21:27 ` [ 19/47] kmemleak: Fix the kmemleak tracking of the percpu areas with !SMP Greg KH
2012-05-18 21:27 ` [ 20/47] mtd: fix oops in dataflash driver Greg KH
2012-05-18 21:27 ` [ 21/47] hugetlb: prevent BUG_ON in hugetlb_fault() -> hugetlb_cow() Greg KH
2012-05-18 21:27 ` [ 22/47] mm: nobootmem: fix sign extend problem in __free_pages_memory() Greg KH
2012-05-18 21:27 ` [ 23/47] jffs2: Fix lock acquisition order bug in gc path Greg KH
2012-05-18 21:27 ` [ 24/47] arch/tile: apply commit 74fca9da0 to the compat signal handling as well Greg KH
2012-05-18 21:27 ` [ 25/47] crypto: mv_cesa requires on CRYPTO_HASH to build Greg KH
2012-05-18 21:27 ` [ 26/47] target: Drop incorrect se_lun_acl release for dynamic -> explict ACL conversion Greg KH
2012-05-18 21:27 ` [ 27/47] target: Fix SPC-2 RELEASE bug for multi-session iSCSI client setups Greg KH
2012-05-18 21:27 ` [ 28/47] target: Fix bug in handling of FILEIO + block_device resize ops Greg KH
2012-05-18 21:27 ` [ 29/47] virtio: console: tell host of open ports after resume from s3/s4 Greg KH
2012-05-18 21:27 ` [ 30/47] dm mpath: check if scsi_dh module already loaded before trying to load Greg KH
2012-05-18 21:27 ` [ 31/47] e1000: Prevent reset task killing itself Greg KH
2012-05-18 21:27 ` [ 32/47] MD: Add del_timer_sync to mddev_suspend (fix nasty panic) Greg KH
2012-05-18 21:27 ` [ 33/47] tcp: do_tcp_sendpages() must try to push data out on oom conditions Greg KH
2012-05-18 21:27 ` [ 34/47] init: dont try mounting device as nfs root unless type fully matches Greg KH
2012-05-18 21:27 ` [ 35/47] ext4: avoid deadlock on sync-mounted FS w/o journal Greg KH
2012-05-18 21:27 ` [ 36/47] memcg: free spare array to avoid memory leak Greg KH
2012-05-18 21:27 ` [ 37/47] cifs: fix revalidation test in cifs_llseek() Greg KH
2012-05-18 21:27 ` [ 38/47] compat: Fix RT signal mask corruption via sigprocmask Greg KH
2012-05-18 21:27 ` [ 39/47] dl2k: Clean up rio_ioctl Greg KH
2012-05-18 21:27 ` [ 40/47] OMAPDSS: VENC: fix NULL pointer dereference in DSS2 VENC sysfs debug attr on OMAP4 Greg KH
2012-05-18 21:27 ` [ 41/47] i2c-eg20t: change timeout value 50msec to 1000msec Greg KH
2012-05-18 21:27 ` [ 42/47] spi-topcliff-pch: Modify pci-bus number dynamically to get DMA device info Greg KH
2012-05-18 21:27 ` [ 43/47] spi-topcliff-pch: Fix issue for transmitting over 4KByte Greg KH
2012-05-18 21:27 ` [ 44/47] spi-topcliff-pch: supports a spi mode setup and bit order setup by IO control Greg KH
2012-05-18 21:27 ` [ 45/47] spi-topcliff-pch: add recovery processing in case wait-event timeout Greg KH
2012-05-18 21:27 ` [ 46/47] Avoid beyond bounds copy while caching ACL Greg KH
2012-05-18 21:27 ` [ 47/47] Avoid reading past buffer when calling GETACL Greg KH

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120518212649.707728445@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=akpm@linux-foundation.org \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=davem@davemloft.net \
    --cc=huajun.li.lee@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=oneukum@suse.de \
    --cc=stable@vger.kernel.org \
    --cc=tom.leiming@gmail.com \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).