From: Greg Kroah-Hartman Date: Wed, 3 Sep 2008 15:35:07 +0000 (-0700) Subject: networking patches for .26 X-Git-Tag: v2.6.25.17~10 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=72905e46af81f29ae23ffb6bbd744022c0a4fe2f;p=thirdparty%2Fkernel%2Fstable-queue.git networking patches for .26 --- diff --git a/queue-2.6.26/0001-AX.25-Fix-sysctl-registration-if-CONFIG_AX25_DAMA_.patch b/queue-2.6.26/0001-AX.25-Fix-sysctl-registration-if-CONFIG_AX25_DAMA_.patch new file mode 100644 index 00000000000..7e90371857e --- /dev/null +++ b/queue-2.6.26/0001-AX.25-Fix-sysctl-registration-if-CONFIG_AX25_DAMA_.patch @@ -0,0 +1,68 @@ +From 6960627457edff5313fb369cba645d5d5ab73e01 Mon Sep 17 00:00:00 2001 +From: Ralf Baechle +Date: Wed, 27 Aug 2008 22:28:53 -0700 +Subject: AX.25: Fix sysctl registration if !CONFIG_AX25_DAMA_SLAVE + +From: Ralf Baechle + +[ Upstream commit ffb208479bd62ab26c29a242faeb1de1c6d5fcdc ] + +Since 49ffcf8f99e8d33ec8afb450956804af518fd788 ("sysctl: update +sysctl_check_table") setting struct ctl_table.procname = NULL does no +longer work as it used to the way the AX.25 code is expecting it to +resulting in the AX.25 sysctl registration code to break if +CONFIG_AX25_DAMA_SLAVE was not set as in some distribution kernels. +Kernel releases from 2.6.24 are affected. + +Signed-off-by: Ralf Baechle +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/ax25/sysctl_net_ax25.c | 14 ++++---------- + 1 file changed, 4 insertions(+), 10 deletions(-) + +--- a/net/ax25/sysctl_net_ax25.c ++++ b/net/ax25/sysctl_net_ax25.c +@@ -36,6 +36,7 @@ static struct ctl_path ax25_path[] = { + { .procname = "ax25", .ctl_name = NET_AX25, }, + { } + }; ++ + static const ctl_table ax25_param_table[] = { + { + .ctl_name = NET_AX25_IP_DEFAULT_MODE, +@@ -167,6 +168,7 @@ static const ctl_table ax25_param_table[ + .extra1 = &min_proto, + .extra2 = &max_proto + }, ++#ifdef CONFIG_AX25_DAMA_SLAVE + { + .ctl_name = NET_AX25_DAMA_SLAVE_TIMEOUT, + .procname = "dama_slave_timeout", +@@ -177,6 +179,8 @@ static const ctl_table ax25_param_table[ + .extra1 = &min_ds_timeout, + .extra2 = &max_ds_timeout + }, ++#endif ++ + { .ctl_name = 0 } /* that's all, folks! */ + }; + +@@ -210,16 +214,6 @@ void ax25_register_sysctl(void) + ax25_table[n].procname = ax25_dev->dev->name; + ax25_table[n].mode = 0555; + +-#ifndef CONFIG_AX25_DAMA_SLAVE +- /* +- * We do not wish to have a representation of this parameter +- * in /proc/sys/ when configured *not* to include the +- * AX.25 DAMA slave code, do we? +- */ +- +- child[AX25_VALUES_DS_TIMEOUT].procname = NULL; +-#endif +- + child[AX25_MAX_VALUES].ctl_name = 0; /* just in case... */ + + for (k = 0; k < AX25_MAX_VALUES; k++) diff --git a/queue-2.6.26/0002-ipv6-Fix-OOPS-ip-f-inet6-route-get-fec0-1-linux.patch b/queue-2.6.26/0002-ipv6-Fix-OOPS-ip-f-inet6-route-get-fec0-1-linux.patch new file mode 100644 index 00000000000..f03693e8faf --- /dev/null +++ b/queue-2.6.26/0002-ipv6-Fix-OOPS-ip-f-inet6-route-get-fec0-1-linux.patch @@ -0,0 +1,60 @@ +From faac03cead6146bddd3180678fff849a06705ab7 Mon Sep 17 00:00:00 2001 +From: Brian Haley +Date: Wed, 27 Aug 2008 22:30:08 -0700 +Subject: ipv6: Fix OOPS, ip -f inet6 route get fec0::1, linux-2.6.26, ip6_route_output, rt6_fill_node+0x175 + +From: Brian Haley + +[ Upstream commit 5e0115e500fe9dd2ca11e6f92db9123204f1327a ] + +Alexey Dobriyan wrote: +> On Thu, Aug 07, 2008 at 07:00:56PM +0200, John Gumb wrote: +>> Scenario: no ipv6 default route set. +> +>> # ip -f inet6 route get fec0::1 +>> +>> BUG: unable to handle kernel NULL pointer dereference at 00000000 +>> IP: [] rt6_fill_node+0x175/0x3b0 +>> EIP is at rt6_fill_node+0x175/0x3b0 +> +> 0xffffffff80424dd3 is in rt6_fill_node (net/ipv6/route.c:2191). +> 2186 } else +> 2187 #endif +> 2188 NLA_PUT_U32(skb, RTA_IIF, iif); +> 2189 } else if (dst) { +> 2190 struct in6_addr saddr_buf; +> 2191 ====> if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev, +> ^^^^^^^^^^^^^^^^^^^^^^^^ +> NULL +> +> 2192 dst, 0, &saddr_buf) == 0) +> 2193 NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); +> 2194 } + +The commit that changed this can't be reverted easily, but the patch +below works for me. + +Fix NULL de-reference in rt6_fill_node() when there's no IPv6 input +device present in the dst entry. + +Signed-off-by: Brian Haley +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/ipv6/route.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -2179,8 +2179,9 @@ static int rt6_fill_node(struct sk_buff + #endif + NLA_PUT_U32(skb, RTA_IIF, iif); + } else if (dst) { ++ struct inet6_dev *idev = ip6_dst_idev(&rt->u.dst); + struct in6_addr saddr_buf; +- if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev, ++ if (ipv6_dev_get_saddr(idev ? idev->dev : NULL, + dst, 0, &saddr_buf) == 0) + NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); + } diff --git a/queue-2.6.26/0003-netns-Add-network-namespace-argument-to-rt6_fill_no.patch b/queue-2.6.26/0003-netns-Add-network-namespace-argument-to-rt6_fill_no.patch new file mode 100644 index 00000000000..81f19dee999 --- /dev/null +++ b/queue-2.6.26/0003-netns-Add-network-namespace-argument-to-rt6_fill_no.patch @@ -0,0 +1,192 @@ +From 9a6484bf4021520db69e2988cfacd162a8379dad Mon Sep 17 00:00:00 2001 +From: Brian Haley +Date: Wed, 27 Aug 2008 22:30:52 -0700 +Subject: netns: Add network namespace argument to rt6_fill_node() and ipv6_dev_get_saddr() + +From: Brian Haley + +[ Upstream commit 191cd582500f49b32a63040fedeebb0168c720af ] + +ipv6_dev_get_saddr() blindly de-references dst_dev to get the network +namespace, but some callers might pass NULL. Change callers to pass a +namespace pointer instead. + +Signed-off-by: Brian Haley +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + include/net/addrconf.h | 3 ++- + include/net/ip6_route.h | 1 + + net/ipv6/addrconf.c | 3 +-- + net/ipv6/fib6_rules.c | 3 ++- + net/ipv6/ip6_fib.c | 1 + + net/ipv6/ip6_output.c | 2 +- + net/ipv6/ndisc.c | 2 +- + net/ipv6/route.c | 12 +++++++----- + net/ipv6/xfrm6_policy.c | 4 +++- + net/sctp/ipv6.c | 3 ++- + 10 files changed, 21 insertions(+), 13 deletions(-) + +--- a/include/net/addrconf.h ++++ b/include/net/addrconf.h +@@ -80,7 +80,8 @@ extern struct inet6_ifaddr *ipv6_ge + struct net_device *dev, + int strict); + +-extern int ipv6_dev_get_saddr(struct net_device *dev, ++extern int ipv6_dev_get_saddr(struct net *net, ++ struct net_device *dev, + const struct in6_addr *daddr, + unsigned int srcprefs, + struct in6_addr *saddr); +--- a/include/net/ip6_route.h ++++ b/include/net/ip6_route.h +@@ -112,6 +112,7 @@ struct rt6_rtnl_dump_arg + { + struct sk_buff *skb; + struct netlink_callback *cb; ++ struct net *net; + }; + + extern int rt6_dump_route(struct rt6_info *rt, void *p_arg); +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -1076,13 +1076,12 @@ out: + return ret; + } + +-int ipv6_dev_get_saddr(struct net_device *dst_dev, ++int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev, + const struct in6_addr *daddr, unsigned int prefs, + struct in6_addr *saddr) + { + struct ipv6_saddr_score scores[2], + *score = &scores[0], *hiscore = &scores[1]; +- struct net *net = dev_net(dst_dev); + struct ipv6_saddr_dst dst; + struct net_device *dev; + int dst_type; +--- a/net/ipv6/fib6_rules.c ++++ b/net/ipv6/fib6_rules.c +@@ -93,7 +93,8 @@ static int fib6_rule_action(struct fib_r + if (flags & RT6_LOOKUP_F_SRCPREF_COA) + srcprefs |= IPV6_PREFER_SRC_COA; + +- if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev, ++ if (ipv6_dev_get_saddr(net, ++ ip6_dst_idev(&rt->u.dst)->dev, + &flp->fl6_dst, srcprefs, + &saddr)) + goto again; +--- a/net/ipv6/ip6_fib.c ++++ b/net/ipv6/ip6_fib.c +@@ -380,6 +380,7 @@ static int inet6_dump_fib(struct sk_buff + + arg.skb = skb; + arg.cb = cb; ++ arg.net = net; + w->args = &arg; + + for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -925,7 +925,7 @@ static int ip6_dst_lookup_tail(struct so + goto out_err_release; + + if (ipv6_addr_any(&fl->fl6_src)) { +- err = ipv6_dev_get_saddr(ip6_dst_idev(*dst)->dev, ++ err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev, + &fl->fl6_dst, + sk ? inet6_sk(sk)->srcprefs : 0, + &fl->fl6_src); +--- a/net/ipv6/ndisc.c ++++ b/net/ipv6/ndisc.c +@@ -549,7 +549,7 @@ static void ndisc_send_na(struct net_dev + override = 0; + in6_ifa_put(ifp); + } else { +- if (ipv6_dev_get_saddr(dev, daddr, ++ if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr, + inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs, + &tmpaddr)) + return; +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -2098,7 +2098,8 @@ static inline size_t rt6_nlmsg_size(void + + nla_total_size(sizeof(struct rta_cacheinfo)); + } + +-static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, ++static int rt6_fill_node(struct net *net, ++ struct sk_buff *skb, struct rt6_info *rt, + struct in6_addr *dst, struct in6_addr *src, + int iif, int type, u32 pid, u32 seq, + int prefix, int nowait, unsigned int flags) +@@ -2181,7 +2182,7 @@ static int rt6_fill_node(struct sk_buff + } else if (dst) { + struct inet6_dev *idev = ip6_dst_idev(&rt->u.dst); + struct in6_addr saddr_buf; +- if (ipv6_dev_get_saddr(idev ? idev->dev : NULL, ++ if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, + dst, 0, &saddr_buf) == 0) + NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); + } +@@ -2226,7 +2227,8 @@ int rt6_dump_route(struct rt6_info *rt, + } else + prefix = 0; + +- return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, ++ return rt6_fill_node(arg->net, ++ arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, + NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq, + prefix, 0, NLM_F_MULTI); + } +@@ -2292,7 +2294,7 @@ static int inet6_rtm_getroute(struct sk_ + rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl); + skb->dst = &rt->u.dst; + +- err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, ++ err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, + RTM_NEWROUTE, NETLINK_CB(in_skb).pid, + nlh->nlmsg_seq, 0, 0, 0); + if (err < 0) { +@@ -2319,7 +2321,7 @@ void inet6_rt_notify(int event, struct r + if (skb == NULL) + goto errout; + +- err = rt6_fill_node(skb, rt, NULL, NULL, 0, ++ err = rt6_fill_node(net, skb, rt, NULL, NULL, 0, + event, info->pid, seq, 0, 0, 0); + if (err < 0) { + /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */ +--- a/net/ipv6/xfrm6_policy.c ++++ b/net/ipv6/xfrm6_policy.c +@@ -52,12 +52,14 @@ static struct dst_entry *xfrm6_dst_looku + static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) + { + struct dst_entry *dst; ++ struct net_device *dev; + + dst = xfrm6_dst_lookup(0, NULL, daddr); + if (IS_ERR(dst)) + return -EHOSTUNREACH; + +- ipv6_dev_get_saddr(ip6_dst_idev(dst)->dev, ++ dev = ip6_dst_idev(dst)->dev; ++ ipv6_dev_get_saddr(dev_net(dev), dev, + (struct in6_addr *)&daddr->a6, 0, + (struct in6_addr *)&saddr->a6); + dst_release(dst); +--- a/net/sctp/ipv6.c ++++ b/net/sctp/ipv6.c +@@ -317,7 +317,8 @@ static void sctp_v6_get_saddr(struct sct + __func__, asoc, dst, NIP6(daddr->v6.sin6_addr)); + + if (!asoc) { +- ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, ++ ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)), ++ dst ? ip6_dst_idev(dst)->dev : NULL, + &daddr->v6.sin6_addr, + inet6_sk(&sk->inet.sk)->srcprefs, + &saddr->v6.sin6_addr); diff --git a/queue-2.6.26/0004-pkt_sched-Fix-return-value-corruption-in-HTB-and-TB.patch b/queue-2.6.26/0004-pkt_sched-Fix-return-value-corruption-in-HTB-and-TB.patch new file mode 100644 index 00000000000..58872584873 --- /dev/null +++ b/queue-2.6.26/0004-pkt_sched-Fix-return-value-corruption-in-HTB-and-TB.patch @@ -0,0 +1,83 @@ +From d63121b53730c03d4c2c32fbecc31aac031fca45 Mon Sep 17 00:00:00 2001 +From: David S. Miller +Date: Wed, 27 Aug 2008 22:35:56 -0700 +Subject: pkt_sched: Fix return value corruption in HTB and TBF. + +From: David S. Miller + +[ Upstream commit 69747650c814a8a79fef412c7416adf823293a3e ] + +Based upon a bug report by Josip Rodin. + +Packet schedulers should only return NET_XMIT_DROP iff +the packet really was dropped. If the packet does reach +the device after we return NET_XMIT_DROP then TCP can +crash because it depends upon the enqueue path return +values being accurate. + +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/sched/sch_htb.c | 20 ++++++++++++-------- + net/sched/sch_tbf.c | 11 ++--------- + 2 files changed, 14 insertions(+), 17 deletions(-) + +--- a/net/sched/sch_htb.c ++++ b/net/sched/sch_htb.c +@@ -595,11 +595,13 @@ static int htb_enqueue(struct sk_buff *s + kfree_skb(skb); + return ret; + #endif +- } else if (cl->un.leaf.q->enqueue(skb, cl->un.leaf.q) != ++ } else if ((ret = cl->un.leaf.q->enqueue(skb, cl->un.leaf.q)) != + NET_XMIT_SUCCESS) { +- sch->qstats.drops++; +- cl->qstats.drops++; +- return NET_XMIT_DROP; ++ if (ret == NET_XMIT_DROP) { ++ sch->qstats.drops++; ++ cl->qstats.drops++; ++ } ++ return ret; + } else { + cl->bstats.packets += + skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1; +@@ -639,11 +641,13 @@ static int htb_requeue(struct sk_buff *s + kfree_skb(skb); + return ret; + #endif +- } else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) != ++ } else if ((ret = cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q)) != + NET_XMIT_SUCCESS) { +- sch->qstats.drops++; +- cl->qstats.drops++; +- return NET_XMIT_DROP; ++ if (ret == NET_XMIT_DROP) { ++ sch->qstats.drops++; ++ cl->qstats.drops++; ++ } ++ return ret; + } else + htb_activate(q, cl); + +--- a/net/sched/sch_tbf.c ++++ b/net/sched/sch_tbf.c +@@ -123,15 +123,8 @@ static int tbf_enqueue(struct sk_buff *s + struct tbf_sched_data *q = qdisc_priv(sch); + int ret; + +- if (skb->len > q->max_size) { +- sch->qstats.drops++; +-#ifdef CONFIG_NET_CLS_ACT +- if (sch->reshape_fail == NULL || sch->reshape_fail(skb, sch)) +-#endif +- kfree_skb(skb); +- +- return NET_XMIT_DROP; +- } ++ if (skb->len > q->max_size) ++ return qdisc_reshape_fail(skb, sch); + + if ((ret = q->qdisc->enqueue(skb, q->qdisc)) != 0) { + sch->qstats.drops++; diff --git a/queue-2.6.26/0005-pkt_sched-Fix-actions-referencing.patch b/queue-2.6.26/0005-pkt_sched-Fix-actions-referencing.patch new file mode 100644 index 00000000000..fd5f2ed6d85 --- /dev/null +++ b/queue-2.6.26/0005-pkt_sched-Fix-actions-referencing.patch @@ -0,0 +1,36 @@ +From e3e7b1a03cbd69e446791afa9c0196d73cf6f94b Mon Sep 17 00:00:00 2001 +From: Jamal Hadi Salim +Date: Wed, 27 Aug 2008 22:38:11 -0700 +Subject: [PATCH] pkt_sched: Fix actions referencing + +From: Jamal Hadi Salim + +[ Upstream commit 76aab2c1eae491a5d73ac83deec97dd28ebac584 ] + +When an action is added several times with the same exact index +it gets deleted on every even-numbered attempt. +This fixes that issue. + +Signed-off-by: Jamal Hadi Salim +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/sched/act_api.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/net/sched/act_api.c ++++ b/net/sched/act_api.c +@@ -205,10 +205,9 @@ struct tcf_common *tcf_hash_check(u32 in + { + struct tcf_common *p = NULL; + if (index && (p = tcf_hash_lookup(index, hinfo)) != NULL) { +- if (bind) { ++ if (bind) + p->tcfc_bindcnt++; +- p->tcfc_refcnt++; +- } ++ p->tcfc_refcnt++; + a->priv = p; + } + return p; diff --git a/queue-2.6.26/0006-udp-Drop-socket-lock-for-encapsulated-packets.patch b/queue-2.6.26/0006-udp-Drop-socket-lock-for-encapsulated-packets.patch new file mode 100644 index 00000000000..94868029b73 --- /dev/null +++ b/queue-2.6.26/0006-udp-Drop-socket-lock-for-encapsulated-packets.patch @@ -0,0 +1,86 @@ +From ea1b147e2aac639e6e8385399a21fca20b904acf Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Wed, 27 Aug 2008 22:40:04 -0700 +Subject: udp: Drop socket lock for encapsulated packets + +From: Herbert Xu + +[ Upstream commit d97106ea52aa57e63ff40d04479016836bbb5a4e ] + +The socket lock is there to protect the normal UDP receive path. +Encapsulation UDP sockets don't need that protection. In fact +the locking is deadly for them as they may contain another UDP +packet within, possibly with the same addresses. + +Also the nested bit was copied from TCP. TCP needs it because +of accept(2) spawning sockets. This simply doesn't apply to UDP +so I've removed it. + +Signed-off-by: Herbert Xu +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/ipv4/udp.c | 6 ++++-- + net/ipv6/udp.c | 6 +++--- + 2 files changed, 7 insertions(+), 5 deletions(-) + +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -988,7 +988,9 @@ int udp_queue_rcv_skb(struct sock * sk, + up->encap_rcv != NULL) { + int ret; + ++ bh_unlock_sock(sk); + ret = (*up->encap_rcv)(sk, skb); ++ bh_lock_sock(sk); + if (ret <= 0) { + UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, + is_udplite); +@@ -1087,7 +1089,7 @@ static int __udp4_lib_mcast_deliver(stru + if (skb1) { + int ret = 0; + +- bh_lock_sock_nested(sk); ++ bh_lock_sock(sk); + if (!sock_owned_by_user(sk)) + ret = udp_queue_rcv_skb(sk, skb1); + else +@@ -1187,7 +1189,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, + + if (sk != NULL) { + int ret = 0; +- bh_lock_sock_nested(sk); ++ bh_lock_sock(sk); + if (!sock_owned_by_user(sk)) + ret = udp_queue_rcv_skb(sk, skb); + else +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -376,7 +376,7 @@ static int __udp6_lib_mcast_deliver(stru + uh->source, saddr, dif))) { + struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); + if (buff) { +- bh_lock_sock_nested(sk2); ++ bh_lock_sock(sk2); + if (!sock_owned_by_user(sk2)) + udpv6_queue_rcv_skb(sk2, buff); + else +@@ -384,7 +384,7 @@ static int __udp6_lib_mcast_deliver(stru + bh_unlock_sock(sk2); + } + } +- bh_lock_sock_nested(sk); ++ bh_lock_sock(sk); + if (!sock_owned_by_user(sk)) + udpv6_queue_rcv_skb(sk, skb); + else +@@ -502,7 +502,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, + + /* deliver */ + +- bh_lock_sock_nested(sk); ++ bh_lock_sock(sk); + if (!sock_owned_by_user(sk)) + udpv6_queue_rcv_skb(sk, skb); + else diff --git a/queue-2.6.26/0007-sctp-fix-potential-panics-in-the-SCTP-AUTH-API.patch b/queue-2.6.26/0007-sctp-fix-potential-panics-in-the-SCTP-AUTH-API.patch new file mode 100644 index 00000000000..8d9344da62b --- /dev/null +++ b/queue-2.6.26/0007-sctp-fix-potential-panics-in-the-SCTP-AUTH-API.patch @@ -0,0 +1,251 @@ +From a12006354213203bf7fc2114286df9cbe848e234 Mon Sep 17 00:00:00 2001 +From: Vlad Yasevich +Date: Wed, 27 Aug 2008 22:41:00 -0700 +Subject: sctp: fix potential panics in the SCTP-AUTH API. + +From: Vlad Yasevich + +[ Upstream commit 5e739d1752aca4e8f3e794d431503bfca3162df4 ] + +All of the SCTP-AUTH socket options could cause a panic +if the extension is disabled and the API is envoked. + +Additionally, there were some additional assumptions that +certain pointers would always be valid which may not +always be the case. + +This patch hardens the API and address all of the crash +scenarios. + +Signed-off-by: Vlad Yasevich +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/sctp/endpointola.c | 4 +- + net/sctp/socket.c | 85 +++++++++++++++++++++++++++++++++++++------------ + 2 files changed, 67 insertions(+), 22 deletions(-) + +--- a/net/sctp/endpointola.c ++++ b/net/sctp/endpointola.c +@@ -103,6 +103,7 @@ static struct sctp_endpoint *sctp_endpoi + + /* Initialize the CHUNKS parameter */ + auth_chunks->param_hdr.type = SCTP_PARAM_CHUNKS; ++ auth_chunks->param_hdr.length = htons(sizeof(sctp_paramhdr_t)); + + /* If the Add-IP functionality is enabled, we must + * authenticate, ASCONF and ASCONF-ACK chunks +@@ -110,8 +111,7 @@ static struct sctp_endpoint *sctp_endpoi + if (sctp_addip_enable) { + auth_chunks->chunks[0] = SCTP_CID_ASCONF; + auth_chunks->chunks[1] = SCTP_CID_ASCONF_ACK; +- auth_chunks->param_hdr.length = +- htons(sizeof(sctp_paramhdr_t) + 2); ++ auth_chunks->param_hdr.length += htons(2); + } + } + +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -2965,6 +2965,9 @@ static int sctp_setsockopt_auth_chunk(st + { + struct sctp_authchunk val; + ++ if (!sctp_auth_enable) ++ return -EACCES; ++ + if (optlen != sizeof(struct sctp_authchunk)) + return -EINVAL; + if (copy_from_user(&val, optval, optlen)) +@@ -2995,6 +2998,9 @@ static int sctp_setsockopt_hmac_ident(st + struct sctp_hmacalgo *hmacs; + int err; + ++ if (!sctp_auth_enable) ++ return -EACCES; ++ + if (optlen < sizeof(struct sctp_hmacalgo)) + return -EINVAL; + +@@ -3033,6 +3039,9 @@ static int sctp_setsockopt_auth_key(stru + struct sctp_association *asoc; + int ret; + ++ if (!sctp_auth_enable) ++ return -EACCES; ++ + if (optlen <= sizeof(struct sctp_authkey)) + return -EINVAL; + +@@ -3070,6 +3079,9 @@ static int sctp_setsockopt_active_key(st + struct sctp_authkeyid val; + struct sctp_association *asoc; + ++ if (!sctp_auth_enable) ++ return -EACCES; ++ + if (optlen != sizeof(struct sctp_authkeyid)) + return -EINVAL; + if (copy_from_user(&val, optval, optlen)) +@@ -3095,6 +3107,9 @@ static int sctp_setsockopt_del_key(struc + struct sctp_authkeyid val; + struct sctp_association *asoc; + ++ if (!sctp_auth_enable) ++ return -EACCES; ++ + if (optlen != sizeof(struct sctp_authkeyid)) + return -EINVAL; + if (copy_from_user(&val, optval, optlen)) +@@ -5053,19 +5068,29 @@ static int sctp_getsockopt_maxburst(stru + static int sctp_getsockopt_hmac_ident(struct sock *sk, int len, + char __user *optval, int __user *optlen) + { ++ struct sctp_hmacalgo __user *p = (void __user *)optval; + struct sctp_hmac_algo_param *hmacs; +- __u16 param_len; ++ __u16 data_len = 0; ++ u32 num_idents; ++ ++ if (!sctp_auth_enable) ++ return -EACCES; + + hmacs = sctp_sk(sk)->ep->auth_hmacs_list; +- param_len = ntohs(hmacs->param_hdr.length); ++ data_len = ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t); + +- if (len < param_len) ++ if (len < sizeof(struct sctp_hmacalgo) + data_len) + return -EINVAL; ++ ++ len = sizeof(struct sctp_hmacalgo) + data_len; ++ num_idents = data_len / sizeof(u16); ++ + if (put_user(len, optlen)) + return -EFAULT; +- if (copy_to_user(optval, hmacs->hmac_ids, len)) ++ if (put_user(num_idents, &p->shmac_num_idents)) ++ return -EFAULT; ++ if (copy_to_user(p->shmac_idents, hmacs->hmac_ids, data_len)) + return -EFAULT; +- + return 0; + } + +@@ -5075,6 +5100,9 @@ static int sctp_getsockopt_active_key(st + struct sctp_authkeyid val; + struct sctp_association *asoc; + ++ if (!sctp_auth_enable) ++ return -EACCES; ++ + if (len < sizeof(struct sctp_authkeyid)) + return -EINVAL; + if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid))) +@@ -5089,6 +5117,12 @@ static int sctp_getsockopt_active_key(st + else + val.scact_keynumber = sctp_sk(sk)->ep->active_key_id; + ++ len = sizeof(struct sctp_authkeyid); ++ if (put_user(len, optlen)) ++ return -EFAULT; ++ if (copy_to_user(optval, &val, len)) ++ return -EFAULT; ++ + return 0; + } + +@@ -5099,13 +5133,16 @@ static int sctp_getsockopt_peer_auth_chu + struct sctp_authchunks val; + struct sctp_association *asoc; + struct sctp_chunks_param *ch; +- u32 num_chunks; ++ u32 num_chunks = 0; + char __user *to; + +- if (len <= sizeof(struct sctp_authchunks)) ++ if (!sctp_auth_enable) ++ return -EACCES; ++ ++ if (len < sizeof(struct sctp_authchunks)) + return -EINVAL; + +- if (copy_from_user(&val, p, sizeof(struct sctp_authchunks))) ++ if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) + return -EFAULT; + + to = p->gauth_chunks; +@@ -5114,20 +5151,21 @@ static int sctp_getsockopt_peer_auth_chu + return -EINVAL; + + ch = asoc->peer.peer_chunks; ++ if (!ch) ++ goto num; + + /* See if the user provided enough room for all the data */ + num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t); + if (len < num_chunks) + return -EINVAL; + +- len = num_chunks; +- if (put_user(len, optlen)) ++ if (copy_to_user(to, ch->chunks, num_chunks)) + return -EFAULT; ++num: ++ len = sizeof(struct sctp_authchunks) + num_chunks; ++ if (put_user(len, optlen)) return -EFAULT; + if (put_user(num_chunks, &p->gauth_number_of_chunks)) + return -EFAULT; +- if (copy_to_user(to, ch->chunks, len)) +- return -EFAULT; +- + return 0; + } + +@@ -5138,13 +5176,16 @@ static int sctp_getsockopt_local_auth_ch + struct sctp_authchunks val; + struct sctp_association *asoc; + struct sctp_chunks_param *ch; +- u32 num_chunks; ++ u32 num_chunks = 0; + char __user *to; + +- if (len <= sizeof(struct sctp_authchunks)) ++ if (!sctp_auth_enable) ++ return -EACCES; ++ ++ if (len < sizeof(struct sctp_authchunks)) + return -EINVAL; + +- if (copy_from_user(&val, p, sizeof(struct sctp_authchunks))) ++ if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) + return -EFAULT; + + to = p->gauth_chunks; +@@ -5157,17 +5198,21 @@ static int sctp_getsockopt_local_auth_ch + else + ch = sctp_sk(sk)->ep->auth_chunk_list; + ++ if (!ch) ++ goto num; ++ + num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t); +- if (len < num_chunks) ++ if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + +- len = num_chunks; ++ if (copy_to_user(to, ch->chunks, num_chunks)) ++ return -EFAULT; ++num: ++ len = sizeof(struct sctp_authchunks) + num_chunks; + if (put_user(len, optlen)) + return -EFAULT; + if (put_user(num_chunks, &p->gauth_number_of_chunks)) + return -EFAULT; +- if (copy_to_user(to, ch->chunks, len)) +- return -EFAULT; + + return 0; + } diff --git a/queue-2.6.26/0008-sctp-add-verification-checks-to-SCTP_AUTH_KEY-optio.patch b/queue-2.6.26/0008-sctp-add-verification-checks-to-SCTP_AUTH_KEY-optio.patch new file mode 100644 index 00000000000..09f1b1277be --- /dev/null +++ b/queue-2.6.26/0008-sctp-add-verification-checks-to-SCTP_AUTH_KEY-optio.patch @@ -0,0 +1,49 @@ +From c7064b2bd573a5bd2364e076878c753c5da50ee5 Mon Sep 17 00:00:00 2001 +From: Vlad Yasevich +Date: Wed, 27 Aug 2008 22:41:52 -0700 +Subject: sctp: add verification checks to SCTP_AUTH_KEY option + +From: Vlad Yasevich + +[ Upstream commit 30c2235cbc477d4629983d440cdc4f496fec9246 ] + +The structure used for SCTP_AUTH_KEY option contains a +length that needs to be verfied to prevent buffer overflow +conditions. Spoted by Eugene Teo . + +Signed-off-by: Vlad Yasevich +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/sctp/auth.c | 4 ++++ + net/sctp/socket.c | 5 +++++ + 2 files changed, 9 insertions(+) + +--- a/net/sctp/auth.c ++++ b/net/sctp/auth.c +@@ -80,6 +80,10 @@ static struct sctp_auth_bytes *sctp_auth + { + struct sctp_auth_bytes *key; + ++ /* Verify that we are not going to overflow INT_MAX */ ++ if ((INT_MAX - key_len) < sizeof(struct sctp_auth_bytes)) ++ return NULL; ++ + /* Allocate the shared key */ + key = kmalloc(sizeof(struct sctp_auth_bytes) + key_len, gfp); + if (!key) +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -3054,6 +3054,11 @@ static int sctp_setsockopt_auth_key(stru + goto out; + } + ++ if (authkey->sca_keylength > optlen) { ++ ret = -EINVAL; ++ goto out; ++ } ++ + asoc = sctp_id2assoc(sk, authkey->sca_assoc_id); + if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) { + ret = -EINVAL; diff --git a/queue-2.6.26/0009-sch_prio-Fix-nla_parse_nested_compat-regression.patch b/queue-2.6.26/0009-sch_prio-Fix-nla_parse_nested_compat-regression.patch new file mode 100644 index 00000000000..d1578ae90ed --- /dev/null +++ b/queue-2.6.26/0009-sch_prio-Fix-nla_parse_nested_compat-regression.patch @@ -0,0 +1,54 @@ +From cb3b7106b526380da4133364ffb2cf187759d8ea Mon Sep 17 00:00:00 2001 +From: Thomas Graf +Date: Wed, 3 Sep 2008 01:00:02 -0700 +Subject: sch_prio: Fix nla_parse_nested_compat() regression + +From: Thomas Graf + +[ No upstream commit, this is fixing code no longer in 2.6.27 ] + +nla_parse_nested_compat() was used to parse two different message +formats in the netem and prio qdisc, when it was "fixed" to work +with netem, it broke the multi queue support in the prio qdisc. +Since the prio qdisc code in question is already removed in the +development tree, this patch only fixes the regression in the +stable tree. + +Based on original patch from Alexander H Duyck + +Signed-off-by: Thomas Graf +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/sched/sch_prio.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +--- a/net/sched/sch_prio.c ++++ b/net/sched/sch_prio.c +@@ -228,14 +228,20 @@ static int prio_tune(struct Qdisc *sch, + { + struct prio_sched_data *q = qdisc_priv(sch); + struct tc_prio_qopt *qopt; +- struct nlattr *tb[TCA_PRIO_MAX + 1]; ++ struct nlattr *tb[TCA_PRIO_MAX + 1] = {0}; + int err; + int i; + +- err = nla_parse_nested_compat(tb, TCA_PRIO_MAX, opt, NULL, qopt, +- sizeof(*qopt)); +- if (err < 0) +- return err; ++ qopt = nla_data(opt); ++ if (nla_len(opt) < sizeof(*qopt)) ++ return -1; ++ ++ if (nla_len(opt) >= sizeof(*qopt) + sizeof(struct nlattr)) { ++ err = nla_parse_nested(tb, TCA_PRIO_MAX, ++ (struct nlattr *) (qopt + 1), NULL); ++ if (err < 0) ++ return err; ++ } + + q->bands = qopt->bands; + /* If we're multiqueue, make sure the number of incoming bands diff --git a/queue-2.6.26/0010-net-Unbreak-userspace-which-includes-linux-mroute.h.patch b/queue-2.6.26/0010-net-Unbreak-userspace-which-includes-linux-mroute.h.patch new file mode 100644 index 00000000000..a90b18e06e1 --- /dev/null +++ b/queue-2.6.26/0010-net-Unbreak-userspace-which-includes-linux-mroute.h.patch @@ -0,0 +1,143 @@ +From c3725971d48033a43beb9e12ea4ae68cea5438c1 Mon Sep 17 00:00:00 2001 +From: David S. Miller +Date: Wed, 3 Sep 2008 01:01:01 -0700 +Subject: net: Unbreak userspace which includes linux/mroute.h + +From: David S. Miller + +[ Upstream commit 7c19a3d280297d43ef5ff7c6b205dc208a16d3d1 ] + +This essentially reverts two commits: + +1) 2e8046271f68198dd37451017c1a4a2432e4ec68 ("[IPV4] MROUTE: Move PIM + definitions to .") + +and + +2) 80a9492a33dd7d852465625022d56ff76d62174d ("[IPV4] MROUTE: Adjust + include files for user-space.") + +which broke userpsace, in particular the XORP build as reported by +Jose Calhariz, the debain package maintainer for XORP. + +Nothing originally in linux/mroute.h was exported to userspace +ever, but some of this stuff started to be when it was moved into +this new linux/pim.h, and that was wrong. If we didn't provide these +definitions for 10 years we can reasonable expect that applications +defined this stuff locally or used GLIBC headers providing the +protocol definitions. And as such the only result of this can +be conflict and userland build breakage. + +The commit #1 had such a short and terse commit message, that we +cannot even know why such a move and set of new userland exports were +even made. + +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/Kbuild | 1 - + include/linux/mroute.h | 25 +++++++++++++++++++++---- + include/linux/pim.h | 45 --------------------------------------------- + 3 files changed, 21 insertions(+), 50 deletions(-) + +--- a/include/linux/Kbuild ++++ b/include/linux/Kbuild +@@ -293,7 +293,6 @@ unifdef-y += parport.h + unifdef-y += patchkey.h + unifdef-y += pci.h + unifdef-y += personality.h +-unifdef-y += pim.h + unifdef-y += pktcdvd.h + unifdef-y += pmu.h + unifdef-y += poll.h +--- a/include/linux/mroute.h ++++ b/include/linux/mroute.h +@@ -2,11 +2,7 @@ + #define __LINUX_MROUTE_H + + #include +-#include +-#ifdef __KERNEL__ + #include +-#endif +-#include + + /* + * Based on the MROUTING 3.5 defines primarily to keep +@@ -214,6 +210,27 @@ struct mfc_cache + #define IGMPMSG_WHOLEPKT 3 /* For PIM Register processing */ + + #ifdef __KERNEL__ ++ ++#define PIM_V1_VERSION __constant_htonl(0x10000000) ++#define PIM_V1_REGISTER 1 ++ ++#define PIM_VERSION 2 ++#define PIM_REGISTER 1 ++ ++#define PIM_NULL_REGISTER __constant_htonl(0x40000000) ++ ++/* PIMv2 register message header layout (ietf-draft-idmr-pimvsm-v2-00.ps */ ++ ++struct pimreghdr ++{ ++ __u8 type; ++ __u8 reserved; ++ __be16 csum; ++ __be32 flags; ++}; ++ ++extern int pim_rcv_v1(struct sk_buff *); ++ + struct rtmsg; + extern int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait); + #endif +--- a/include/linux/pim.h ++++ /dev/null +@@ -1,45 +0,0 @@ +-#ifndef __LINUX_PIM_H +-#define __LINUX_PIM_H +- +-#include +- +-#ifndef __KERNEL__ +-struct pim { +-#if defined(__LITTLE_ENDIAN_BITFIELD) +- __u8 pim_type:4, /* PIM message type */ +- pim_ver:4; /* PIM version */ +-#elif defined(__BIG_ENDIAN_BITFIELD) +- __u8 pim_ver:4; /* PIM version */ +- pim_type:4; /* PIM message type */ +-#endif +- __u8 pim_rsv; /* Reserved */ +- __be16 pim_cksum; /* Checksum */ +-}; +- +-#define PIM_MINLEN 8 +-#endif +- +-/* Message types - V1 */ +-#define PIM_V1_VERSION __constant_htonl(0x10000000) +-#define PIM_V1_REGISTER 1 +- +-/* Message types - V2 */ +-#define PIM_VERSION 2 +-#define PIM_REGISTER 1 +- +-#if defined(__KERNEL__) +-#define PIM_NULL_REGISTER __constant_htonl(0x40000000) +- +-/* PIMv2 register message header layout (ietf-draft-idmr-pimvsm-v2-00.ps */ +-struct pimreghdr +-{ +- __u8 type; +- __u8 reserved; +- __be16 csum; +- __be32 flags; +-}; +- +-struct sk_buff; +-extern int pim_rcv_v1(struct sk_buff *); +-#endif +-#endif diff --git a/queue-2.6.26/0011-sctp-correct-bounds-check-in-sctp_setsockopt_auth_k.patch b/queue-2.6.26/0011-sctp-correct-bounds-check-in-sctp_setsockopt_auth_k.patch new file mode 100644 index 00000000000..884aae65b7a --- /dev/null +++ b/queue-2.6.26/0011-sctp-correct-bounds-check-in-sctp_setsockopt_auth_k.patch @@ -0,0 +1,35 @@ +From 7bcd9afb203f780afb7fddaf7604166912129c4e Mon Sep 17 00:00:00 2001 +From: Vlad Yasevich +Date: Wed, 3 Sep 2008 01:02:19 -0700 +Subject: sctp: correct bounds check in sctp_setsockopt_auth_key + +From: Vlad Yasevich + +[ Upstream commit 328fc47ea0bcc27d9afa69c3ad6e52431cadd76c ] + +The bonds check to prevent buffer overlflow was not exactly +right. It still allowed overflow of up to 8 bytes which is +sizeof(struct sctp_authkey). + +Since optlen is already checked against the size of that struct, +we are guaranteed not to cause interger overflow either. + +Signed-off-by: Vlad Yasevich +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/sctp/socket.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -3054,7 +3054,7 @@ static int sctp_setsockopt_auth_key(stru + goto out; + } + +- if (authkey->sca_keylength > optlen) { ++ if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) { + ret = -EINVAL; + goto out; + } diff --git a/queue-2.6.26/0012-sctp-fix-random-memory-dereference-with-SCTP_HMAC_I.patch b/queue-2.6.26/0012-sctp-fix-random-memory-dereference-with-SCTP_HMAC_I.patch new file mode 100644 index 00000000000..187147f902d --- /dev/null +++ b/queue-2.6.26/0012-sctp-fix-random-memory-dereference-with-SCTP_HMAC_I.patch @@ -0,0 +1,56 @@ +From ddfe8ddeda4fc1fa7cd39462af39d2d7b3423c3c Mon Sep 17 00:00:00 2001 +From: Vlad Yasevich +Date: Wed, 3 Sep 2008 01:02:37 -0700 +Subject: sctp: fix random memory dereference with SCTP_HMAC_IDENT option. + +From: Vlad Yasevich + +[ Upstream commit d97240552cd98c4b07322f30f66fd9c3ba4171de ] + +The number of identifiers needs to be checked against the option +length. Also, the identifier index provided needs to be verified +to make sure that it doesn't exceed the bounds of the array. + +Signed-off-by: Vlad Yasevich +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/sctp/auth.c | 3 +++ + net/sctp/socket.c | 6 ++++-- + 2 files changed, 7 insertions(+), 2 deletions(-) + +--- a/net/sctp/auth.c ++++ b/net/sctp/auth.c +@@ -786,6 +786,9 @@ int sctp_auth_ep_set_hmacs(struct sctp_e + for (i = 0; i < hmacs->shmac_num_idents; i++) { + id = hmacs->shmac_idents[i]; + ++ if (id > SCTP_AUTH_HMAC_ID_MAX) ++ return -EOPNOTSUPP; ++ + if (SCTP_AUTH_HMAC_ID_SHA1 == id) + has_sha1 = 1; + +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -2996,6 +2996,7 @@ static int sctp_setsockopt_hmac_ident(st + int optlen) + { + struct sctp_hmacalgo *hmacs; ++ u32 idents; + int err; + + if (!sctp_auth_enable) +@@ -3013,8 +3014,9 @@ static int sctp_setsockopt_hmac_ident(st + goto out; + } + +- if (hmacs->shmac_num_idents == 0 || +- hmacs->shmac_num_idents > SCTP_AUTH_NUM_HMACS) { ++ idents = hmacs->shmac_num_idents; ++ if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || ++ (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) { + err = -EINVAL; + goto out; + } diff --git a/queue-2.6.26/0013-ipsec-Fix-deadlock-in-xfrm_state-management.patch b/queue-2.6.26/0013-ipsec-Fix-deadlock-in-xfrm_state-management.patch new file mode 100644 index 00000000000..3f63d842410 --- /dev/null +++ b/queue-2.6.26/0013-ipsec-Fix-deadlock-in-xfrm_state-management.patch @@ -0,0 +1,154 @@ +From e0227ac0d1b681a0e9a809969861de078503056a Mon Sep 17 00:00:00 2001 +From: David S. Miller +Date: Wed, 3 Sep 2008 01:03:39 -0700 +Subject: ipsec: Fix deadlock in xfrm_state management. + +From: David S. Miller + +[ Upstream commit 37b08e34a98c664bea86e3fae718ac45a46b7276 ] + +Ever since commit 4c563f7669c10a12354b72b518c2287ffc6ebfb3 +("[XFRM]: Speed up xfrm_policy and xfrm_state walking") it is +illegal to call __xfrm_state_destroy (and thus xfrm_state_put()) +with xfrm_state_lock held. If we do, we'll deadlock since we +have the lock already and __xfrm_state_destroy() tries to take +it again. + +Fix this by pushing the xfrm_state_put() calls after the lock +is dropped. + +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/xfrm/xfrm_state.c | 32 +++++++++++++++++++++++--------- + 1 file changed, 23 insertions(+), 9 deletions(-) + +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -780,11 +780,13 @@ xfrm_state_find(xfrm_address_t *daddr, x + { + unsigned int h; + struct hlist_node *entry; +- struct xfrm_state *x, *x0; ++ struct xfrm_state *x, *x0, *to_put; + int acquire_in_progress = 0; + int error = 0; + struct xfrm_state *best = NULL; + ++ to_put = NULL; ++ + spin_lock_bh(&xfrm_state_lock); + h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family); + hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { +@@ -833,7 +835,7 @@ xfrm_state_find(xfrm_address_t *daddr, x + if (tmpl->id.spi && + (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi, + tmpl->id.proto, family)) != NULL) { +- xfrm_state_put(x0); ++ to_put = x0; + error = -EEXIST; + goto out; + } +@@ -849,7 +851,7 @@ xfrm_state_find(xfrm_address_t *daddr, x + error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); + if (error) { + x->km.state = XFRM_STATE_DEAD; +- xfrm_state_put(x); ++ to_put = x; + x = NULL; + goto out; + } +@@ -870,7 +872,7 @@ xfrm_state_find(xfrm_address_t *daddr, x + xfrm_hash_grow_check(x->bydst.next != NULL); + } else { + x->km.state = XFRM_STATE_DEAD; +- xfrm_state_put(x); ++ to_put = x; + x = NULL; + error = -ESRCH; + } +@@ -881,6 +883,8 @@ out: + else + *err = acquire_in_progress ? -EAGAIN : error; + spin_unlock_bh(&xfrm_state_lock); ++ if (to_put) ++ xfrm_state_put(to_put); + return x; + } + +@@ -1067,18 +1071,20 @@ static struct xfrm_state *__xfrm_find_ac + + int xfrm_state_add(struct xfrm_state *x) + { +- struct xfrm_state *x1; ++ struct xfrm_state *x1, *to_put; + int family; + int err; + int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); + + family = x->props.family; + ++ to_put = NULL; ++ + spin_lock_bh(&xfrm_state_lock); + + x1 = __xfrm_state_locate(x, use_spi, family); + if (x1) { +- xfrm_state_put(x1); ++ to_put = x1; + x1 = NULL; + err = -EEXIST; + goto out; +@@ -1088,7 +1094,7 @@ int xfrm_state_add(struct xfrm_state *x) + x1 = __xfrm_find_acq_byseq(x->km.seq); + if (x1 && ((x1->id.proto != x->id.proto) || + xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { +- xfrm_state_put(x1); ++ to_put = x1; + x1 = NULL; + } + } +@@ -1110,6 +1116,9 @@ out: + xfrm_state_put(x1); + } + ++ if (to_put) ++ xfrm_state_put(to_put); ++ + return err; + } + EXPORT_SYMBOL(xfrm_state_add); +@@ -1269,10 +1278,12 @@ EXPORT_SYMBOL(xfrm_state_migrate); + + int xfrm_state_update(struct xfrm_state *x) + { +- struct xfrm_state *x1; ++ struct xfrm_state *x1, *to_put; + int err; + int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); + ++ to_put = NULL; ++ + spin_lock_bh(&xfrm_state_lock); + x1 = __xfrm_state_locate(x, use_spi, x->props.family); + +@@ -1281,7 +1292,7 @@ int xfrm_state_update(struct xfrm_state + goto out; + + if (xfrm_state_kern(x1)) { +- xfrm_state_put(x1); ++ to_put = x1; + err = -EEXIST; + goto out; + } +@@ -1295,6 +1306,9 @@ int xfrm_state_update(struct xfrm_state + out: + spin_unlock_bh(&xfrm_state_lock); + ++ if (to_put) ++ xfrm_state_put(to_put); ++ + if (err) + return err; + diff --git a/queue-2.6.26/series b/queue-2.6.26/series index ea787a885b3..ba5199d25f2 100644 --- a/queue-2.6.26/series +++ b/queue-2.6.26/series @@ -17,3 +17,16 @@ drivers-char-random.c-fix-a-race-which-can-lead-to-a-bogus-bug.patch rtc_time_to_tm-fix-signed-unsigned-arithmetic.patch 8250-improve-workaround-for-uarts-that-don-t-re-assert-thre-correctly.patch mm-make-setup_zone_migrate_reserve-aware-of-overlapping-nodes.patch +0001-AX.25-Fix-sysctl-registration-if-CONFIG_AX25_DAMA_.patch +0002-ipv6-Fix-OOPS-ip-f-inet6-route-get-fec0-1-linux.patch +0003-netns-Add-network-namespace-argument-to-rt6_fill_no.patch +0004-pkt_sched-Fix-return-value-corruption-in-HTB-and-TB.patch +0005-pkt_sched-Fix-actions-referencing.patch +0006-udp-Drop-socket-lock-for-encapsulated-packets.patch +0007-sctp-fix-potential-panics-in-the-SCTP-AUTH-API.patch +0008-sctp-add-verification-checks-to-SCTP_AUTH_KEY-optio.patch +0009-sch_prio-Fix-nla_parse_nested_compat-regression.patch +0010-net-Unbreak-userspace-which-includes-linux-mroute.h.patch +0011-sctp-correct-bounds-check-in-sctp_setsockopt_auth_k.patch +0012-sctp-fix-random-memory-dereference-with-SCTP_HMAC_I.patch +0013-ipsec-Fix-deadlock-in-xfrm_state-management.patch