From 632041f306707df94110441f55b1458ebeb096db Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Sun, 13 Jan 2008 16:20:56 -0500 Subject: rfkill: call rfkill_led_trigger_unregister() on error Code inspection turned up that error cases in rfkill_register() do not call rfkill_led_trigger_unregister() even though we have already registered. Signed-off-by: Eric Paris Signed-off-by: John W. Linville --- net/rfkill/rfkill.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 4469a7be006c27..d06d338812e975 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -392,11 +392,14 @@ int rfkill_register(struct rfkill *rfkill) rfkill_led_trigger_register(rfkill); error = rfkill_add_switch(rfkill); - if (error) + if (error) { + rfkill_led_trigger_unregister(rfkill); return error; + } error = device_add(dev); if (error) { + rfkill_led_trigger_unregister(rfkill); rfkill_remove_switch(rfkill); return error; } -- cgit 1.2.3-korg From b3652b2dc5ec6ccd946ae9136b30c6babb81305a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 18 Jan 2008 03:27:12 -0800 Subject: [IPV6]: Mischecked tw match in __inet6_check_established. When looking for a conflicting connection the !sk->sk_bound_dev_if check is performed only for live sockets, but not for timewait-ed. This is not the case for ipv4, for __inet6_lookup_established in both ipv4 and ipv6 and for other places that check for tw-s. Was this missed accidentally? If so, then this patch fixes it and besides makes use if the dif variable declared in the function. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/inet6_hashtables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index adc73adadfae47..0765d8bd380f62 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -193,7 +193,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, sk2->sk_family == PF_INET6 && ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) && ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) && - sk2->sk_bound_dev_if == sk->sk_bound_dev_if) { + (!sk2->sk_bound_dev_if || sk2->sk_bound_dev_if == dif)) { if (twsk_unique(sk, sk2, twp)) goto unique; else -- cgit 1.2.3-korg From bd566e7525b5986864e8d6eb5b67640abcd284a9 Mon Sep 17 00:00:00 2001 From: Joonwoo Park Date: Fri, 18 Jan 2008 03:44:48 -0800 Subject: [IPV4] fib_hash: fix duplicated route issue http://bugzilla.kernel.org/show_bug.cgi?id=9493 The fib allows making identical routes with 'ip route replace'. This patch makes the fib return -EEXIST if replacement would cause duplication. Signed-off-by: Joonwoo Park Signed-off-by: David S. Miller --- net/ipv4/fib_hash.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 527a6e0af5b60e..99071d79c5e75f 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -444,6 +444,9 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) struct fib_info *fi_drop; u8 state; + if (fi->fib_treeref > 1) + goto out; + write_lock_bh(&fib_hash_lock); fi_drop = fa->fa_info; fa->fa_info = fi; -- cgit 1.2.3-korg From 6725033fa27c8f49e1221d2badbaaaf1ef459519 Mon Sep 17 00:00:00 2001 From: Joonwoo Park Date: Fri, 18 Jan 2008 03:45:18 -0800 Subject: [IPV4] fib_trie: fix duplicated route issue http://bugzilla.kernel.org/show_bug.cgi?id=9493 The fib allows making identical routes with 'ip route replace'. This patch makes the fib return -EEXIST if replacement would cause duplication. Signed-off-by: Joonwoo Park Signed-off-by: David S. Miller --- net/ipv4/fib_trie.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 8d8c2915e064f9..1010b469d7d344 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1214,6 +1214,9 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg) struct fib_info *fi_drop; u8 state; + if (fi->fib_treeref > 1) + goto out; + err = -ENOBUFS; new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); if (new_fa == NULL) -- cgit 1.2.3-korg From 49d85c502ec5e6d5998c1a04394c5b24e8f7d32d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 18 Jan 2008 04:21:39 -0800 Subject: [NET]: Fix interrupt semaphore corruption in Intel drivers. Several of the Intel ethernet drivers keep an atomic counter used to manage when to actually hit the hardware with a disable or an enable. The way the net_rx_work() breakout logic works during a pending napi_disable() is that it simply unschedules the poll even if it still has work. This can potentially leave interrupts disabled, but that is OK because all of the drivers are about to disable interrupts anyways in all such code paths that do a napi_disable(). Unfortunately, this trips up the semaphore used here in the Intel drivers. If you hit this case, when you try to bring the interface back up it won't enable interrupts. A reload of the driver module fixes it of course. So what we do is make sure all the sequences now go: napi_disable(); atomic_set(&adapter->irq_sem, 0); *_irq_disable(); which makes sure the counter is always in the correct state. Reported by Robert Olsson. Signed-off-by: David S. Miller --- drivers/net/e1000/e1000_main.c | 1 + drivers/net/e1000e/netdev.c | 1 + drivers/net/ixgb/ixgb_main.c | 9 ++++++--- drivers/net/ixgbe/ixgbe_main.c | 4 +++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 0c9a6f7104d280..76c0fa690cc6ad 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -632,6 +632,7 @@ e1000_down(struct e1000_adapter *adapter) #ifdef CONFIG_E1000_NAPI napi_disable(&adapter->napi); + atomic_set(&adapter->irq_sem, 0); #endif e1000_irq_disable(adapter); diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 2ab3bfbb8a6338..9cc5a6b01bc1dc 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -2183,6 +2183,7 @@ void e1000e_down(struct e1000_adapter *adapter) msleep(10); napi_disable(&adapter->napi); + atomic_set(&adapter->irq_sem, 0); e1000_irq_disable(adapter); del_timer_sync(&adapter->watchdog_timer); diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index d2fb88d5cda277..4f63839051b05c 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -296,6 +296,11 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog) { struct net_device *netdev = adapter->netdev; +#ifdef CONFIG_IXGB_NAPI + napi_disable(&adapter->napi); + atomic_set(&adapter->irq_sem, 0); +#endif + ixgb_irq_disable(adapter); free_irq(adapter->pdev->irq, netdev); @@ -304,9 +309,7 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog) if(kill_watchdog) del_timer_sync(&adapter->watchdog_timer); -#ifdef CONFIG_IXGB_NAPI - napi_disable(&adapter->napi); -#endif + adapter->link_speed = 0; adapter->link_duplex = 0; netif_carrier_off(netdev); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index de3f45e4c5ae38..a4265bc1cebb71 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1409,9 +1409,11 @@ void ixgbe_down(struct ixgbe_adapter *adapter) IXGBE_WRITE_FLUSH(&adapter->hw); msleep(10); + napi_disable(&adapter->napi); + atomic_set(&adapter->irq_sem, 0); + ixgbe_irq_disable(adapter); - napi_disable(&adapter->napi); del_timer_sync(&adapter->watchdog_timer); netif_carrier_off(netdev); -- cgit 1.2.3-korg From 8d3f099abe25c21670cb5728178a1f286952782d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 18 Jan 2008 04:30:21 -0800 Subject: [IPV4] FIB_HASH : Avoid unecessary loop in fn_hash_dump_zone() I noticed "ip route list" was slower than "cat /proc/net/route" on a machine with a full Internet routing table (214392 entries : Special thanks to Robert ;) ) This is similar to problem reported in commit d8c9283089287341c85a0a69de32c2287a990e71 ("[IPV4] ROUTE: ip_rt_dump() is unecessary slow") Fix is to avoid scanning the begining of fz_hash table, but directly seek to the right offset. Before patch : time ip route >/tmp/ROUTE real 0m1.285s user 0m0.712s sys 0m0.436s After patch # time ip route >/tmp/ROUTE real 0m0.835s user 0m0.692s sys 0m0.124s Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/fib_hash.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 99071d79c5e75f..0dfee27cfbcd8c 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -721,19 +721,18 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb, { int h, s_h; + if (fz->fz_hash == NULL) + return skb->len; s_h = cb->args[3]; - for (h=0; h < fz->fz_divisor; h++) { - if (h < s_h) continue; - if (h > s_h) - memset(&cb->args[4], 0, - sizeof(cb->args) - 4*sizeof(cb->args[0])); - if (fz->fz_hash == NULL || - hlist_empty(&fz->fz_hash[h])) + for (h = s_h; h < fz->fz_divisor; h++) { + if (hlist_empty(&fz->fz_hash[h])) continue; - if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h])<0) { + if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h]) < 0) { cb->args[3] = h; return -1; } + memset(&cb->args[4], 0, + sizeof(cb->args) - 4*sizeof(cb->args[0])); } cb->args[3] = h; return skb->len; @@ -749,14 +748,13 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin read_lock(&fib_hash_lock); for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) { if (m < s_m) continue; - if (m > s_m) - memset(&cb->args[3], 0, - sizeof(cb->args) - 3*sizeof(cb->args[0])); if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) { cb->args[2] = m; read_unlock(&fib_hash_lock); return -1; } + memset(&cb->args[3], 0, + sizeof(cb->args) - 3*sizeof(cb->args[0])); } read_unlock(&fib_hash_lock); cb->args[2] = m; -- cgit 1.2.3-korg From 398bcbebb6f721ac308df1e3d658c0029bb74503 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sat, 19 Jan 2008 00:35:16 -0800 Subject: [IPV6] ROUTE: Make sending algorithm more friendly with RFC 4861. We omit (or delay) sending NSes for known-to-unreachable routers (in NUD_FAILED state) according to RFC 4191 (Default Router Preferences and More-Specific Routes). But this is not fully compatible with RFC 4861 (Neighbor Discovery Protocol for IPv6), which does not remember unreachability of neighbors. So, let's avoid mixing sending algorithm of RFC 4191 and that of RFC 4861, and make the algorithm more friendly with RFC 4861 if RFC 4191 is disabled. Issue was found by IPv6 Ready Logo Core Self_Test 1.5.0b2 (by TAHI Project), and has been tracked down by Mitsuru Chinen . Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/route.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 6ecb5e6fae2eb9..20083e0d3995cf 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -329,7 +329,7 @@ static inline int rt6_check_dev(struct rt6_info *rt, int oif) static inline int rt6_check_neigh(struct rt6_info *rt) { struct neighbour *neigh = rt->rt6i_nexthop; - int m = 0; + int m; if (rt->rt6i_flags & RTF_NONEXTHOP || !(rt->rt6i_flags & RTF_GATEWAY)) m = 1; @@ -337,10 +337,15 @@ static inline int rt6_check_neigh(struct rt6_info *rt) read_lock_bh(&neigh->lock); if (neigh->nud_state & NUD_VALID) m = 2; - else if (!(neigh->nud_state & NUD_FAILED)) +#ifdef CONFIG_IPV6_ROUTER_PREF + else if (neigh->nud_state & NUD_FAILED) + m = 0; +#endif + else m = 1; read_unlock_bh(&neigh->lock); - } + } else + m = 0; return m; } -- cgit 1.2.3-korg From 2dc2f207fb251666d2396fe1a69272b307ecc333 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sun, 20 Jan 2008 06:25:48 -0800 Subject: [NETFILTER]: bridge-netfilter: fix net_device refcnt leaks When packets are flood-forwarded to multiple output devices, the bridge-netfilter code reuses skb->nf_bridge for each clone to store the bridge port. When queueing packets using NFQUEUE netfilter takes a reference to skb->nf_bridge->physoutdev, which is overwritten when the packet is forwarded to the second port. This causes refcount unterflows for the first device and refcount leaks for all others. Additionally this provides incorrect data to the iptables physdev match. Unshare skb->nf_bridge by copying it if it is shared before assigning the physoutdev device. Reported, tested and based on initial patch by Jan Christoph Nordholz . Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/bridge/br_netfilter.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 5d8b939eded193..9f78a69d6b8b57 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -142,6 +142,23 @@ static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) return skb->nf_bridge; } +static inline struct nf_bridge_info *nf_bridge_unshare(struct sk_buff *skb) +{ + struct nf_bridge_info *nf_bridge = skb->nf_bridge; + + if (atomic_read(&nf_bridge->use) > 1) { + struct nf_bridge_info *tmp = nf_bridge_alloc(skb); + + if (tmp) { + memcpy(tmp, nf_bridge, sizeof(struct nf_bridge_info)); + atomic_set(&tmp->use, 1); + nf_bridge_put(nf_bridge); + } + nf_bridge = tmp; + } + return nf_bridge; +} + static inline void nf_bridge_push_encap_header(struct sk_buff *skb) { unsigned int len = nf_bridge_encap_header_len(skb); @@ -637,6 +654,11 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb, if (!skb->nf_bridge) return NF_ACCEPT; + /* Need exclusive nf_bridge_info since we might have multiple + * different physoutdevs. */ + if (!nf_bridge_unshare(skb)) + return NF_DROP; + parent = bridge_parent(out); if (!parent) return NF_DROP; @@ -718,6 +740,11 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff *skb, if (!skb->nf_bridge) return NF_ACCEPT; + /* Need exclusive nf_bridge_info since we might have multiple + * different physoutdevs. */ + if (!nf_bridge_unshare(skb)) + return NF_DROP; + nf_bridge = skb->nf_bridge; if (!(nf_bridge->mask & BRNF_BRIDGED_DNAT)) return NF_ACCEPT; -- cgit 1.2.3-korg From cecbb63967b4f36701b9412a12377e8fe006a93b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 20 Jan 2008 16:39:03 -0800 Subject: [NEIGH]: Revert 'Fix race between neigh_parms_release and neightbl_fill_parms' Commit 9cd40029423701c376391da59d2c6469672b4bed (Fix race between neigh_parms_release and neightbl_fill_parms) introduced device reference counting regressions for several people, see: http://bugzilla.kernel.org/show_bug.cgi?id=9778 for example. Signed-off-by: David S. Miller --- net/core/neighbour.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index cc8a2f190acfa7..29b8ee4e35d6dc 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1316,6 +1316,8 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) *p = parms->next; parms->dead = 1; write_unlock_bh(&tbl->lock); + if (parms->dev) + dev_put(parms->dev); call_rcu(&parms->rcu_head, neigh_rcu_free_parms); return; } @@ -1326,8 +1328,6 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) void neigh_parms_destroy(struct neigh_parms *parms) { - if (parms->dev) - dev_put(parms->dev); kfree(parms); } -- cgit 1.2.3-korg From 61e44b4815063a5cc31242d3669d5f87beeaa45f Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 20 Jan 2008 16:58:04 -0800 Subject: [IrDA]: af_irda memory leak fixes Here goes an IrDA patch against your latest net-2.6 tree. This patch fixes some af_irda memory leaks. It also checks for irias_new_obect() return value. Signed-off-by: Jesper Juhl Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- net/irda/af_irda.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index d5e4dd75200b78..07dfa7fdd2a021 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -802,12 +802,18 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) } #endif /* CONFIG_IRDA_ULTRA */ + self->ias_obj = irias_new_object(addr->sir_name, jiffies); + if (self->ias_obj == NULL) + return -ENOMEM; + err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name); - if (err < 0) + if (err < 0) { + kfree(self->ias_obj->name); + kfree(self->ias_obj); return err; + } /* Register with LM-IAS */ - self->ias_obj = irias_new_object(addr->sir_name, jiffies); irias_add_integer_attrib(self->ias_obj, "IrDA:TinyTP:LsapSel", self->stsap_sel, IAS_KERNEL_ATTR); irias_insert_object(self->ias_obj); @@ -1825,7 +1831,7 @@ static int irda_setsockopt(struct socket *sock, int level, int optname, struct irda_ias_set *ias_opt; struct ias_object *ias_obj; struct ias_attrib * ias_attr; /* Attribute in IAS object */ - int opt; + int opt, free_ias = 0; IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); @@ -1881,11 +1887,20 @@ static int irda_setsockopt(struct socket *sock, int level, int optname, /* Create a new object */ ias_obj = irias_new_object(ias_opt->irda_class_name, jiffies); + if (ias_obj == NULL) { + kfree(ias_opt); + return -ENOMEM; + } + free_ias = 1; } /* Do we have the attribute already ? */ if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) { kfree(ias_opt); + if (free_ias) { + kfree(ias_obj->name); + kfree(ias_obj); + } return -EINVAL; } @@ -1904,6 +1919,11 @@ static int irda_setsockopt(struct socket *sock, int level, int optname, if(ias_opt->attribute.irda_attrib_octet_seq.len > IAS_MAX_OCTET_STRING) { kfree(ias_opt); + if (free_ias) { + kfree(ias_obj->name); + kfree(ias_obj); + } + return -EINVAL; } /* Add an octet sequence attribute */ @@ -1932,6 +1952,10 @@ static int irda_setsockopt(struct socket *sock, int level, int optname, break; default : kfree(ias_opt); + if (free_ias) { + kfree(ias_obj->name); + kfree(ias_obj); + } return -EINVAL; } irias_insert_object(ias_obj); -- cgit 1.2.3-korg From 799fa6779bc870a32377000b42a3e6297446ed10 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 20 Jan 2008 17:22:28 -0800 Subject: [ATM] atm/idt77105.c: Fix section mismatch. EXPORT_SYMBOL'ed code mustn't be __*init. Signed-off-by: Adrian Bunk Acked-by: Sam Ravnborg Signed-off-by: David S. Miller --- drivers/atm/idt77105.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c index 0bd657f5dd2a45..84672dc57f7afd 100644 --- a/drivers/atm/idt77105.c +++ b/drivers/atm/idt77105.c @@ -357,7 +357,7 @@ static const struct atmphy_ops idt77105_ops = { }; -int __devinit idt77105_init(struct atm_dev *dev) +int idt77105_init(struct atm_dev *dev) { dev->phy = &idt77105_ops; return 0; -- cgit 1.2.3-korg From 421c991483a6e52091cd2120c007cbc220d669ae Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 20 Jan 2008 17:23:12 -0800 Subject: [ATM] atm/suni.c: Fix section mismatch. EXPORT_SYMBOL'ed code mustn't be __*init. Signed-off-by: Adrian Bunk Acked-by: Sam Ravnborg Signed-off-by: David S. Miller --- drivers/atm/suni.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c index f04f39c00833cc..b1d063cc4fbe0f 100644 --- a/drivers/atm/suni.c +++ b/drivers/atm/suni.c @@ -289,7 +289,7 @@ static const struct atmphy_ops suni_ops = { }; -int __devinit suni_init(struct atm_dev *dev) +int suni_init(struct atm_dev *dev) { unsigned char mri; -- cgit 1.2.3-korg From d4782c323d10d3698b71b6a6b3c7bdad33824658 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sun, 20 Jan 2008 17:24:29 -0800 Subject: [AF_KEY]: Fix skb leak on pfkey_send_migrate() error Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/key/af_key.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/net/key/af_key.c b/net/key/af_key.c index 26d5e63c4cc5d9..76dcd882f87b97 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3593,27 +3593,29 @@ static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, /* old ipsecrequest */ int mode = pfkey_mode_from_xfrm(mp->mode); if (mode < 0) - return -EINVAL; + goto err; if (set_ipsecrequest(skb, mp->proto, mode, (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE), mp->reqid, mp->old_family, - &mp->old_saddr, &mp->old_daddr) < 0) { - return -EINVAL; - } + &mp->old_saddr, &mp->old_daddr) < 0) + goto err; /* new ipsecrequest */ if (set_ipsecrequest(skb, mp->proto, mode, (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE), mp->reqid, mp->new_family, - &mp->new_saddr, &mp->new_daddr) < 0) { - return -EINVAL; - } + &mp->new_saddr, &mp->new_daddr) < 0) + goto err; } /* broadcast migrate message to sockets */ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); return 0; + +err: + kfree_skb(skb); + return -EINVAL; } #else static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, -- cgit 1.2.3-korg From 68365458a4252fa993b91a00f7a0b18fed399f0d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sun, 20 Jan 2008 17:25:14 -0800 Subject: [NET]: rtnl_link: fix use-after-free When unregistering the rtnl_link_ops, all existing devices using the ops are destroyed. With nested devices this may lead to a use-after-free despite the use of for_each_netdev_safe() in case the upper device is next in the device list and is destroyed by the NETDEV_UNREGISTER notifier. The easy fix is to restart scanning the device list after removing a device. Alternatively we could add new devices to the front of the list to avoid having dependant devices follow the device they depend on. A third option would be to only restart scanning if dev->iflink of the next device matches dev->ifindex of the current one. For now this seems like the safest solution. With this patch, the veth rtnl_link_ops unregistration can use rtnl_link_unregister() directly since it now also handles destruction of multiple devices at once. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- drivers/net/veth.c | 14 +------------- net/core/rtnetlink.c | 5 ++++- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 43af9e9b26525a..3f67a29593bc41 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -459,19 +459,7 @@ static __init int veth_init(void) static __exit void veth_exit(void) { - struct veth_priv *priv, *next; - - rtnl_lock(); - /* - * cannot trust __rtnl_link_unregister() to unregister all - * devices, as each ->dellink call will remove two devices - * from the list at once. - */ - list_for_each_entry_safe(priv, next, &veth_list, list) - veth_dellink(priv->dev); - - __rtnl_link_unregister(&veth_link_ops); - rtnl_unlock(); + rtnl_link_unregister(&veth_link_ops); } module_init(veth_init); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index e1ba26fb4bf280..fed95a323b2810 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -308,9 +308,12 @@ void __rtnl_link_unregister(struct rtnl_link_ops *ops) struct net *net; for_each_net(net) { +restart: for_each_netdev_safe(net, dev, n) { - if (dev->rtnl_link_ops == ops) + if (dev->rtnl_link_ops == ops) { ops->dellink(dev); + goto restart; + } } } list_del(&ops->list); -- cgit 1.2.3-korg From c964ff4ffbef4586ec63dbeb008563078114e6dc Mon Sep 17 00:00:00 2001 From: Wang Chen Date: Mon, 21 Jan 2008 03:04:47 -0800 Subject: [IPV6]: ICMP6_MIB_OUTMSGS increment duplicated icmpv6_send() calls ip6_push_pending_frames() indirectly. Both ip6_push_pending_frames() and icmpv6_send() increment counter ICMP6_MIB_OUTMSGS. This patch remove the increment from icmpv6_send. Signed-off-by: Wang Chen Acked-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/icmp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 9bb031fa1c2f53..f1240688dc5849 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -458,8 +458,6 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, } err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, len + sizeof(struct icmp6hdr)); - ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS); - out_put: if (likely(idev != NULL)) in6_dev_put(idev); -- cgit 1.2.3-korg From fa95c28322a312a798a688c655458ab2079b72eb Mon Sep 17 00:00:00 2001 From: Wang Chen Date: Mon, 21 Jan 2008 03:05:43 -0800 Subject: [IPV6]: RFC 2011 compatibility broken The snmp6 entry name was changed, and it broke compatibility to RFC 2011. Signed-off-by: Wang Chen Acked-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/proc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 8631ed7fe8a9a8..44937616057e77 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -88,7 +88,7 @@ static char *icmp6type2name[256] = { [ICMPV6_PKT_TOOBIG] = "PktTooBigs", [ICMPV6_TIME_EXCEED] = "TimeExcds", [ICMPV6_PARAMPROB] = "ParmProblems", - [ICMPV6_ECHO_REQUEST] = "EchoRequest", + [ICMPV6_ECHO_REQUEST] = "Echos", [ICMPV6_ECHO_REPLY] = "EchoReplies", [ICMPV6_MGM_QUERY] = "GroupMembQueries", [ICMPV6_MGM_REPORT] = "GroupMembResponses", @@ -98,7 +98,7 @@ static char *icmp6type2name[256] = { [NDISC_ROUTER_SOLICITATION] = "RouterSolicits", [NDISC_NEIGHBOUR_ADVERTISEMENT] = "NeighborAdvertisements", [NDISC_NEIGHBOUR_SOLICITATION] = "NeighborSolicits", - [NDISC_REDIRECT] = "NeighborRedirects", + [NDISC_REDIRECT] = "Redirects", }; -- cgit 1.2.3-korg From 5b4d383a1a562de6955cacd72e20809064ee137f Mon Sep 17 00:00:00 2001 From: Wang Chen Date: Mon, 21 Jan 2008 03:39:45 -0800 Subject: [ICMP]: ICMP_MIB_OUTMSGS increment duplicated Commit "96793b482540f3a26e2188eaf75cb56b7829d3e3" (Add ICMPMsgStats MIB (RFC 4293)) made a mistake. In that patch, David L added a icmp_out_count() in ip_push_pending_frames(), remove icmp_out_count() from icmp_reply(). But he forgot to remove icmp_out_count() from icmp_send() too. Since icmp_send and icmp_reply will call icmp_push_reply, which will call ip_push_pending_frames, a duplicated increment happened in icmp_send. This patch remove the icmp_out_count from icmp_send too. Signed-off-by: Wang Chen Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 233de06342989e..82baea026484d6 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -540,7 +540,6 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) icmp_param.data.icmph.checksum = 0; icmp_param.skb = skb_in; icmp_param.offset = skb_network_offset(skb_in); - icmp_out_count(icmp_param.data.icmph.type); inet_sk(icmp_socket->sk)->tos = tos; ipc.addr = iph->saddr; ipc.opt = &icmp_param.replyopts; -- cgit 1.2.3-korg