aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Kuznetsov <kuznet@ms2.inr.ac.ru>2007-04-25 16:07:28 -0400
committerDavid S. Miller <davem@davemloft.net>2007-04-25 16:07:28 -0400
commit1194ed0a3eb8076c8fbfe310f1ccbf229e8647de (patch)
tree3ec35f14c5e1a12a681629e0422cf9f0e254332f
parent5044eed48886b105a123333fe7ca97c6bd496120 (diff)
[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>
-rw-r--r--net/ipv4/fib_frontend.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index fc920f63452b..cac06c43f004 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -776,6 +776,8 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb )
776 .nl_u = { .ip4_u = { .daddr = frn->fl_addr, 776 .nl_u = { .ip4_u = { .daddr = frn->fl_addr,
777 .tos = frn->fl_tos, 777 .tos = frn->fl_tos,
778 .scope = frn->fl_scope } } }; 778 .scope = frn->fl_scope } } };
779
780 frn->err = -ENOENT;
779 if (tb) { 781 if (tb) {
780 local_bh_disable(); 782 local_bh_disable();
781 783
@@ -787,6 +789,7 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb )
787 frn->nh_sel = res.nh_sel; 789 frn->nh_sel = res.nh_sel;
788 frn->type = res.type; 790 frn->type = res.type;
789 frn->scope = res.scope; 791 frn->scope = res.scope;
792 fib_res_put(&res);
790 } 793 }
791 local_bh_enable(); 794 local_bh_enable();
792 } 795 }
@@ -801,6 +804,9 @@ static void nl_fib_input(struct sock *sk, int len)
801 struct fib_table *tb; 804 struct fib_table *tb;
802 805
803 skb = skb_dequeue(&sk->sk_receive_queue); 806 skb = skb_dequeue(&sk->sk_receive_queue);
807 if (skb == NULL)
808 return;
809
804 nlh = (struct nlmsghdr *)skb->data; 810 nlh = (struct nlmsghdr *)skb->data;
805 if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len || 811 if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len ||
806 nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn))) { 812 nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn))) {
@@ -813,7 +819,7 @@ static void nl_fib_input(struct sock *sk, int len)
813 819
814 nl_fib_lookup(frn, tb); 820 nl_fib_lookup(frn, tb);
815 821
816 pid = nlh->nlmsg_pid; /*pid of sending process */ 822 pid = NETLINK_CB(skb).pid; /* pid of sending process */
817 NETLINK_CB(skb).pid = 0; /* from kernel */ 823 NETLINK_CB(skb).pid = 0; /* from kernel */
818 NETLINK_CB(skb).dst_group = 0; /* unicast */ 824 NETLINK_CB(skb).dst_group = 0; /* unicast */
819 netlink_unicast(sk, skb, pid, MSG_DONTWAIT); 825 netlink_unicast(sk, skb, pid, MSG_DONTWAIT);