Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2654

kernel-2.6.18-238.el5.src.rpm

From: David S. Miller <davem@redhat.com>
Subject: [RHEL5 bz#237905]: Fix user OOPS'able bug in FIB netlink
Date: Fri, 27 Apr 2007 16:47:36 -0400 (EDT)
Bugzilla: 237913
Message-Id: <20070427.164736.95080812.davem@redhat.com>
Changelog: [net] Fix user OOPS'able bug in FIB netlink



Here is a new version of the fix, it incorporates an
important follow-on that prevents another possible OOPS
introduced by the original version of the fix.  That is
why there are two changelog entries here.

Please ACK, thanks!

[NETLINK]: Infinite recursion in netlink.

Reply to NETLINK_FIB_LOOKUP messages were misrouted back to kernel,
which resulted in infinite recursion and stack overflow.

The bug is present in all kernel versions since the feature appeared.

The patch also makes some minimal cleanup:

1. Return something consistent (-ENOENT) when fib table is missing
2. Do not crash when queue is empty (does not happen, but yet)
3. Put result of lookup

Signed-off-by: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Signed-off-by: David S. Miller <davem@davemloft.net>

[IPV4] nl_fib_lookup: Initialise res.r before fib_res_put(&res)

When CONFIG_IP_MULTIPLE_TABLES is enabled, the code in nl_fib_lookup()
needs to initialize the res.r field before fib_res_put(&res) - unlike
fib_lookup(), a direct call to ->tb_lookup does not set this field.

Signed-off-by: Sergey Vlasov <vsu@altlinux.ru>
Signed-off-by: David S. Miller <davem@davemloft.net>

diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index fc920f6..cac06c4 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -553,6 +553,12 @@ static void nl_fib_lookup(struct fib_res
 							    .fwmark = frn->fl_fwmark,
 							    .tos = frn->fl_tos,
 							    .scope = frn->fl_scope } } };
+
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+	res.r = NULL;
+#endif
+
+	frn->err = -ENOENT;
 	if (tb) {
 		local_bh_disable();
 
@@ -564,6 +570,7 @@ static void nl_fib_lookup(struct fib_res
 			frn->nh_sel = res.nh_sel;
 			frn->type = res.type;
 			frn->scope = res.scope;
+			fib_res_put(&res);
 		}
 		local_bh_enable();
 	}
@@ -578,6 +585,9 @@ static void nl_fib_input(struct sock *sk
 	struct fib_table *tb;
 	
 	skb = skb_dequeue(&sk->sk_receive_queue);
+	if (skb == NULL)
+		return;
+
 	nlh = (struct nlmsghdr *)skb->data;
 	if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len ||
 	    nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn))) {
@@ -590,7 +600,7 @@ static void nl_fib_input(struct sock *sk
 
 	nl_fib_lookup(frn, tb);
 	
-	pid = nlh->nlmsg_pid;           /*pid of sending process */
+	pid = NETLINK_CB(skb).pid;       /* pid of sending process */
 	NETLINK_CB(skb).pid = 0;         /* from kernel */
 	NETLINK_CB(skb).dst_pid = pid;
 	NETLINK_CB(skb).dst_group = 0;  /* unicast */