Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 1411

kernel-2.6.18-128.1.10.el5.src.rpm

From: Neil Horman <nhorman@redhat.com>
Date: Thu, 26 Feb 2009 14:13:02 -0500
Subject: [net] fix oops when using openswan
Message-id: 20090226191302.GK24652@shamino.rdu.redhat.com
O-Subject: [RHEL 5.4 PATCH]: net: Fix oops when using openswan (bz 484590)
Bugzilla: 484590
RH-Acked-by: David Miller <davem@redhat.com>
RH-Acked-by: Thomas Graf <tgraf@redhat.com>

Hey all-
	Backport of commit 93821778def10ec1e69aa3ac10adee975dad4ff3 to correctly
fix udp locking and avoid a deadlock.  Tested and confirmed to fix bz 484590

Neil

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 3e9d21a..f83064a 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1004,6 +1004,25 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb)
 #endif
 }
 
+static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+	int rc;
+
+	if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) {
+		/* Note that an ENOMEM error is charged twice */
+		if (rc == -ENOMEM)
+			UDP_INC_STATS_BH(UDP_MIB_INERRORS);
+		goto drop;
+	}
+
+	return 0;
+
+drop:
+	UDP_INC_STATS_BH(UDP_MIB_INERRORS);
+	kfree_skb(skb);
+	return -1;
+}
+
 /* returns:
  *  -1: error
  *   0: success
@@ -1014,6 +1033,7 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb)
  */
 static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 {
+	int rc;
 	struct udp_sock *up = udp_sk(sk);
 
 	/*
@@ -1037,9 +1057,7 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 		 */
 		int ret;
 
-		bh_unlock_sock(sk);
 		ret = udp_encap_rcv(sk, skb);
-		bh_lock_sock(sk);
 		if (ret == 0) {
 			/* Eat the packet .. */
 			kfree_skb(skb);
@@ -1064,12 +1082,16 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	}
 
-	if (sock_queue_rcv_skb(sk,skb)<0) {
-		UDP_INC_STATS_BH(UDP_MIB_INERRORS);
-		kfree_skb(skb);
-		return -1;
-	}
-	return 0;
+	rc = 0;
+
+	bh_lock_sock(sk);
+	if (!sock_owned_by_user(sk))
+		rc = __udp_queue_rcv_skb(sk, skb);
+	else
+		sk_add_backlog(sk, skb);
+	bh_unlock_sock(sk);
+
+	return rc;
 }
 
 /*
@@ -1100,14 +1122,7 @@ static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh,
 				skb1 = skb_clone(skb, GFP_ATOMIC);
 
 			if(skb1) {
-				int ret = 0;
-
-				bh_lock_sock(sk);
-				if (!sock_owned_by_user(sk))
-					ret = udp_queue_rcv_skb(sk, skb1);
-				else
-					sk_add_backlog(sk, skb1);
-				bh_unlock_sock(sk);
+				int ret = udp_queue_rcv_skb(sk, skb1);
 
 				if (ret > 0)
 					/* we should probably re-process instead
@@ -1181,13 +1196,7 @@ int udp_rcv(struct sk_buff *skb)
 	sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex);
 
 	if (sk != NULL) {
-		int ret = 0;
-		bh_lock_sock(sk);
-		if (!sock_owned_by_user(sk))
-			ret = udp_queue_rcv_skb(sk, skb);
-		else
-			sk_add_backlog(sk, skb);
-		bh_unlock_sock(sk);
+		int ret = udp_queue_rcv_skb(sk, skb);
 		sock_put(sk);
 
 		/* a return value > 0 means to resubmit the input, but
@@ -1432,7 +1441,7 @@ struct proto udp_prot = {
 	.sendmsg	   = udp_sendmsg,
 	.recvmsg	   = udp_recvmsg,
 	.sendpage	   = udp_sendpage,
-	.backlog_rcv	   = udp_queue_rcv_skb,
+	.backlog_rcv	   = __udp_queue_rcv_skb,
 	.hash		   = udp_v4_hash,
 	.unhash		   = udp_v4_unhash,
 	.get_port	   = udp_v4_get_port,