netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Per Liden <per.liden@ericsson.com>
To: David Miller <davem@davemloft.net>
Cc: netdev@vger.kernel.org, P Litov <xpl@amln.net>
Subject: [PATCH 8/14] [TIPC] Fix socket receive queue NULL pointer dereference on SMP systems
Date: Fri, 13 Oct 2006 13:37:49 +0200	[thread overview]
Message-ID: <1160739475921-git-send-email-per.liden@ericsson.com> (raw)
In-Reply-To: <Pine.LNX.4.64.0610131330350.30166@ulinpc219.uab.ericsson.se>

From: P Litov <xpl@amln.net>

This patch corrects an SMP system-specific race condition which allowed
TIPC to prematurely dereference the first sk_buff in a socket receive
queue that was changing from empty to non-empty state.

Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
Signed-off-by: Per Liden <per.liden@ericsson.com>
---
 net/tipc/socket.c |   40 ++++++++++++++++++++++++++--------------
 1 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 2a6a5a6..827f204 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -82,6 +82,18 @@ static int sockets_enabled = 0;
 static atomic_t tipc_queue_size = ATOMIC_INIT(0);
 
 
+/*
+ * Notes on receive queue locking:
+ *
+ * 1) Routines called from an application thread that examine the socket 
+ * receive queue must typically use skb_queue_empty() rather than
+ * skb_queue_len() to determine if the queue has a message in it; otherwise,
+ * a race condition can arise on SMP systems wherein skb_queue_len() indicates
+ * the presence of a message that is not yet on the queue.  (This race could
+ * be avoided by taking the queue lock before examining the queue, but this
+ * would complicate the code and impact performance.)
+ */
+
 /* 
  * sock_lock(): Lock a port/socket pair. lock_sock() can 
  * not be used here, since the same lock must protect ports 
@@ -123,7 +135,7 @@ static u32 pollmask(struct socket *sock)
 {
 	u32 mask;
 
-	if ((skb_queue_len(&sock->sk->sk_receive_queue) != 0) ||
+	if (!skb_queue_empty(&sock->sk->sk_receive_queue) ||
 	    (sock->state == SS_UNCONNECTED) ||
 	    (sock->state == SS_DISCONNECTING))
 		mask = (POLLRDNORM | POLLIN);
@@ -809,7 +821,7 @@ static int recv_msg(struct kiocb *iocb, 
 	struct tipc_sock *tsock = tipc_sk(sock->sk);
 	struct sk_buff *buf;
 	struct tipc_msg *msg;
-	unsigned int q_len;
+	int q_empty;
 	unsigned int sz;
 	u32 err;
 	int res;
@@ -828,7 +840,7 @@ static int recv_msg(struct kiocb *iocb, 
 		if (unlikely(sock->state == SS_UNCONNECTED))
 			return -ENOTCONN;
 		if (unlikely((sock->state == SS_DISCONNECTING) && 
-			     (skb_queue_len(&sock->sk->sk_receive_queue) == 0)))
+			     (skb_queue_empty(&sock->sk->sk_receive_queue))))
 		       	return -ENOTCONN;
 	}
 
@@ -838,7 +850,7 @@ static int recv_msg(struct kiocb *iocb, 
 		return -ERESTARTSYS;
 
 restart:
-	if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) &&
+	if (unlikely(skb_queue_empty(&sock->sk->sk_receive_queue) &&
 		     (flags & MSG_DONTWAIT))) {
 		res = -EWOULDBLOCK;
 		goto exit;
@@ -846,7 +858,7 @@ restart:
 
 	if ((res = wait_event_interruptible(
 		*sock->sk->sk_sleep, 
-		((q_len = skb_queue_len(&sock->sk->sk_receive_queue)) ||
+		(!(q_empty = skb_queue_empty(&sock->sk->sk_receive_queue)) ||
 		 (sock->state == SS_DISCONNECTING))) )) {
 		goto exit;
 	}
@@ -854,7 +866,7 @@ restart:
 	/* Catch attempt to receive on an already terminated connection */
 	/* [THIS CHECK MAY OVERLAP WITH AN EARLIER CHECK] */
 
-	if (!q_len) {
+	if (q_empty) {
 		res = -ENOTCONN;
 		goto exit;
 	}
@@ -941,7 +953,7 @@ static int recv_stream(struct kiocb *ioc
 	struct tipc_sock *tsock = tipc_sk(sock->sk);
 	struct sk_buff *buf;
 	struct tipc_msg *msg;
-	unsigned int q_len;
+	int q_empty;
 	unsigned int sz;
 	int sz_to_copy;
 	int sz_copied = 0;
@@ -962,7 +974,7 @@ static int recv_stream(struct kiocb *ioc
 		return -EINVAL;
 
 	if (unlikely(sock->state == SS_DISCONNECTING)) {
-		if (skb_queue_len(&sock->sk->sk_receive_queue) == 0)
+		if (skb_queue_empty(&sock->sk->sk_receive_queue))
 			return -ENOTCONN;
 	} else if (unlikely(sock->state != SS_CONNECTED))
 		return -ENOTCONN;
@@ -973,7 +985,7 @@ static int recv_stream(struct kiocb *ioc
 		return -ERESTARTSYS;
 
 restart:
-	if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) &&
+	if (unlikely(skb_queue_empty(&sock->sk->sk_receive_queue) &&
 		     (flags & MSG_DONTWAIT))) {
 		res = -EWOULDBLOCK;
 		goto exit;
@@ -981,7 +993,7 @@ restart:
 
 	if ((res = wait_event_interruptible(
 		*sock->sk->sk_sleep, 
-		((q_len = skb_queue_len(&sock->sk->sk_receive_queue)) ||
+		(!(q_empty = skb_queue_empty(&sock->sk->sk_receive_queue)) ||
 		 (sock->state == SS_DISCONNECTING))) )) {
 		goto exit;
 	}
@@ -989,7 +1001,7 @@ restart:
 	/* Catch attempt to receive on an already terminated connection */
 	/* [THIS CHECK MAY OVERLAP WITH AN EARLIER CHECK] */
 
-	if (!q_len) {
+	if (q_empty) {
 		res = -ENOTCONN;
 		goto exit;
 	}
@@ -1287,7 +1299,7 @@ static int connect(struct socket *sock, 
    /* Wait for destination's 'ACK' response */
 
    res = wait_event_interruptible_timeout(*sock->sk->sk_sleep,
-                                          skb_queue_len(&sock->sk->sk_receive_queue),
+                                          (!skb_queue_empty(&sock->sk->sk_receive_queue)),
 					  sock->sk->sk_rcvtimeo);
    buf = skb_peek(&sock->sk->sk_receive_queue);
    if (res > 0) {
@@ -1349,7 +1361,7 @@ static int accept(struct socket *sock, s
 	if (sock->state != SS_LISTENING)
 		return -EINVAL;
 	
-	if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) && 
+	if (unlikely(skb_queue_empty(&sock->sk->sk_receive_queue) && 
 		     (flags & O_NONBLOCK)))
 		return -EWOULDBLOCK;
 
@@ -1357,7 +1369,7 @@ static int accept(struct socket *sock, s
 		return -ERESTARTSYS;
 
 	if (wait_event_interruptible(*sock->sk->sk_sleep, 
-				     skb_queue_len(&sock->sk->sk_receive_queue))) {
+				     (!skb_queue_empty(&sock->sk->sk_receive_queue)))) {
 		res = -ERESTARTSYS;
 		goto exit;
 	}
-- 
1.4.1


  parent reply	other threads:[~2006-10-13 11:38 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-10-13 11:37 [PATCH 0/14] TIPC updates Per Liden
2006-10-13 11:37 ` [PATCH 1/14] [TIPC] Add missing unlock in port timeout code Per Liden
2006-10-17  4:39   ` David Miller
2006-10-13 11:37 ` [PATCH 2/14] [TIPC] Debug print buffer enhancements and fixes Per Liden
2006-10-17  4:43   ` David Miller
2006-10-13 11:37 ` [PATCH 3/14] [TIPC] Stream socket can now send > 66000 bytes at a time Per Liden
2006-10-17  4:44   ` David Miller
2006-10-13 11:37 ` [PATCH 4/14] [TIPC] Added duplicate node address detection capability Per Liden
2006-10-17  4:45   ` David Miller
2006-10-13 11:37 ` [PATCH 5/14] [TIPC] Optimize wakeup logic when socket has no waiting processes Per Liden
2006-10-17  4:48   ` David Miller
2006-10-13 11:37 ` [PATCH 6/14] [TIPC] Remove code bloat introduced by print buffer rework Per Liden
2006-10-17  4:49   ` David Miller
2006-10-13 11:37 ` [PATCH 7/14] [TIPC] Add support for Ethernet VLANs Per Liden
2006-10-17  4:50   ` David Miller
2006-10-13 11:37 ` Per Liden [this message]
2006-10-17  4:55   ` [PATCH 8/14] [TIPC] Fix socket receive queue NULL pointer dereference on SMP systems David Miller
2006-10-13 11:37 ` [PATCH 9/14] [TIPC] Name publication events now delivered in chronological order Per Liden
2006-10-13 23:13   ` Bill Fink
2006-10-16  8:50     ` Per Liden
2006-10-16 20:59       ` David Miller
2006-10-17  4:56   ` David Miller
2006-10-13 11:37 ` [PATCH 10/14] [TIPC] Fixed slow link reactivation when link tolerance is large Per Liden
2006-10-17  4:57   ` David Miller
2006-10-13 11:37 ` [PATCH 11/14] [TIPC] Can now list multicast link on an isolated network node Per Liden
2006-10-17  4:58   ` David Miller
2006-10-13 11:37 ` [PATCH 12/14] [TIPC] Added subscription cancellation capability Per Liden
2006-10-17  5:00   ` David Miller
2006-10-13 11:37 ` [PATCH 13/14] [TIPC] Unrecognized configuration command now returns error message Per Liden
2006-10-17  5:01   ` David Miller
2006-10-13 11:37 ` [PATCH 14/14] [TIPC] Updated TIPC version number to 1.6.2 Per Liden
2006-10-17  5:01   ` David Miller
2006-10-17  5:04 ` [PATCH 0/14] TIPC updates David Miller
2006-10-18  8:24   ` Per Liden

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=1160739475921-git-send-email-per.liden@ericsson.com \
    --to=per.liden@ericsson.com \
    --cc=davem@davemloft.net \
    --cc=netdev@vger.kernel.org \
    --cc=xpl@amln.net \
    /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).