aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-12-28 17:24:14 -0500
committerDavid S. Miller <davem@davemloft.net>2012-12-28 17:28:17 -0500
commitac196f8c92948deb0fc9ae617f3a453c6d71fa69 (patch)
treef79d08264a3d6e8c49ab4f20c98e7885f71d4183 /net
parent101e5c7470eb7f77ae87f966b9155f0dbb5b4698 (diff)
parent1310b955c804975651dca6c674ebfd1cb2b4c7ff (diff)
Merge branch 'master' of git://1984.lsi.us.es/nf
Pablo Neira Ayuso says: ==================== The following batch contains Netfilter fixes for 3.8-rc1. They are a mixture of old bugs that have passed unnoticed (I'll pass these to stable) and more fresh ones from the previous merge window, they are: * Fix for MAC address in 6in4 tunnels via NFLOG that results in ulogd showing up wrong address, from Bob Hockney. * Fix a comment in nf_conntrack_ipv6, from Florent Fourcot. * Fix a leak an error path in ctnetlink while creating an expectation, from Jesper Juhl. * Fix missing ICMP time exceeded in the IPv6 defragmentation code, from Haibo Xi. * Fix inconsistent handling of routing changes in MASQUERADE for the new connections case, from Andrew Collins. * Fix a missing skb_reset_transport in ip[6]t_REJECT that leads to crashes in the ixgbe driver (since it seems to access the transport header with TSO enabled), from Mukund Jampala. * Recover obsoleted NOTRACK target by including it into the CT and spot a warning via printk about being obsoleted. Many people don't check the scheduled to be removal file under Documentation, so we follow some less agressive approach to kill this in a year or so. Spotted by Florian Westphal, patch from myself. * Fix race condition in xt_hashlimit that allows to create two or more entries, from myself. * Fix crash if the CT is used due to the recently added facilities to consult the dying and unconfirmed conntrack lists, from myself. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c1
-rw-r--r--net/ipv4/netfilter/iptable_nat.c15
-rw-r--r--net/ipv6/netfilter/ip6t_REJECT.c1
-rw-r--r--net/ipv6/netfilter/ip6table_nat.c15
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c4
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c5
-rw-r--r--net/netfilter/Kconfig4
-rw-r--r--net/netfilter/nf_conntrack_core.c2
-rw-r--r--net/netfilter/nf_conntrack_netlink.c2
-rw-r--r--net/netfilter/nfnetlink_log.c16
-rw-r--r--net/netfilter/xt_CT.c58
-rw-r--r--net/netfilter/xt_hashlimit.c54
-rw-r--r--net/netfilter/xt_recent.c20
13 files changed, 167 insertions, 30 deletions
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index 51f13f8ec724..04b18c1ac345 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -81,6 +81,7 @@ static void send_reset(struct sk_buff *oldskb, int hook)
81 niph->saddr = oiph->daddr; 81 niph->saddr = oiph->daddr;
82 niph->daddr = oiph->saddr; 82 niph->daddr = oiph->saddr;
83 83
84 skb_reset_transport_header(nskb);
84 tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); 85 tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
85 memset(tcph, 0, sizeof(*tcph)); 86 memset(tcph, 0, sizeof(*tcph));
86 tcph->source = oth->dest; 87 tcph->source = oth->dest;
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c
index da2c8a368f68..eeaff7e4acb5 100644
--- a/net/ipv4/netfilter/iptable_nat.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -124,23 +124,28 @@ nf_nat_ipv4_fn(unsigned int hooknum,
124 ret = nf_nat_rule_find(skb, hooknum, in, out, ct); 124 ret = nf_nat_rule_find(skb, hooknum, in, out, ct);
125 if (ret != NF_ACCEPT) 125 if (ret != NF_ACCEPT)
126 return ret; 126 return ret;
127 } else 127 } else {
128 pr_debug("Already setup manip %s for ct %p\n", 128 pr_debug("Already setup manip %s for ct %p\n",
129 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", 129 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST",
130 ct); 130 ct);
131 if (nf_nat_oif_changed(hooknum, ctinfo, nat, out))
132 goto oif_changed;
133 }
131 break; 134 break;
132 135
133 default: 136 default:
134 /* ESTABLISHED */ 137 /* ESTABLISHED */
135 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || 138 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
136 ctinfo == IP_CT_ESTABLISHED_REPLY); 139 ctinfo == IP_CT_ESTABLISHED_REPLY);
137 if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) { 140 if (nf_nat_oif_changed(hooknum, ctinfo, nat, out))
138 nf_ct_kill_acct(ct, ctinfo, skb); 141 goto oif_changed;
139 return NF_DROP;
140 }
141 } 142 }
142 143
143 return nf_nat_packet(ct, ctinfo, hooknum, skb); 144 return nf_nat_packet(ct, ctinfo, hooknum, skb);
145
146oif_changed:
147 nf_ct_kill_acct(ct, ctinfo, skb);
148 return NF_DROP;
144} 149}
145 150
146static unsigned int 151static unsigned int
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index fd4fb34c51c7..029623dbd411 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -132,6 +132,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
132 ip6h->saddr = oip6h->daddr; 132 ip6h->saddr = oip6h->daddr;
133 ip6h->daddr = oip6h->saddr; 133 ip6h->daddr = oip6h->saddr;
134 134
135 skb_reset_transport_header(nskb);
135 tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); 136 tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
136 /* Truncate to length (no data) */ 137 /* Truncate to length (no data) */
137 tcph->doff = sizeof(struct tcphdr)/4; 138 tcph->doff = sizeof(struct tcphdr)/4;
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c
index 6c8ae24b85eb..e0e788d25b14 100644
--- a/net/ipv6/netfilter/ip6table_nat.c
+++ b/net/ipv6/netfilter/ip6table_nat.c
@@ -127,23 +127,28 @@ nf_nat_ipv6_fn(unsigned int hooknum,
127 ret = nf_nat_rule_find(skb, hooknum, in, out, ct); 127 ret = nf_nat_rule_find(skb, hooknum, in, out, ct);
128 if (ret != NF_ACCEPT) 128 if (ret != NF_ACCEPT)
129 return ret; 129 return ret;
130 } else 130 } else {
131 pr_debug("Already setup manip %s for ct %p\n", 131 pr_debug("Already setup manip %s for ct %p\n",
132 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", 132 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST",
133 ct); 133 ct);
134 if (nf_nat_oif_changed(hooknum, ctinfo, nat, out))
135 goto oif_changed;
136 }
134 break; 137 break;
135 138
136 default: 139 default:
137 /* ESTABLISHED */ 140 /* ESTABLISHED */
138 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || 141 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
139 ctinfo == IP_CT_ESTABLISHED_REPLY); 142 ctinfo == IP_CT_ESTABLISHED_REPLY);
140 if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) { 143 if (nf_nat_oif_changed(hooknum, ctinfo, nat, out))
141 nf_ct_kill_acct(ct, ctinfo, skb); 144 goto oif_changed;
142 return NF_DROP;
143 }
144 } 145 }
145 146
146 return nf_nat_packet(ct, ctinfo, hooknum, skb); 147 return nf_nat_packet(ct, ctinfo, hooknum, skb);
148
149oif_changed:
150 nf_ct_kill_acct(ct, ctinfo, skb);
151 return NF_DROP;
147} 152}
148 153
149static unsigned int 154static unsigned int
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 00ee17c3e893..137e245860ab 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -81,8 +81,8 @@ static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
81 } 81 }
82 protoff = ipv6_skip_exthdr(skb, extoff, &nexthdr, &frag_off); 82 protoff = ipv6_skip_exthdr(skb, extoff, &nexthdr, &frag_off);
83 /* 83 /*
84 * (protoff == skb->len) mean that the packet doesn't have no data 84 * (protoff == skb->len) means the packet has not data, just
85 * except of IPv6 & ext headers. but it's tracked anyway. - YK 85 * IPv6 and possibly extensions headers, but it is tracked anyway
86 */ 86 */
87 if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { 87 if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
88 pr_debug("ip6_conntrack_core: can't find proto in pkt\n"); 88 pr_debug("ip6_conntrack_core: can't find proto in pkt\n");
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 22c8ea951185..3dacecc99065 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -311,7 +311,10 @@ found:
311 else 311 else
312 fq->q.fragments = skb; 312 fq->q.fragments = skb;
313 313
314 skb->dev = NULL; 314 if (skb->dev) {
315 fq->iif = skb->dev->ifindex;
316 skb->dev = NULL;
317 }
315 fq->q.stamp = skb->tstamp; 318 fq->q.stamp = skb->tstamp;
316 fq->q.meat += skb->len; 319 fq->q.meat += skb->len;
317 if (payload_len > fq->q.max_size) 320 if (payload_len > fq->q.max_size)
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index fefa514b9917..390f96cc8ed4 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -680,6 +680,10 @@ config NETFILTER_XT_TARGET_NFQUEUE
680 680
681 To compile it as a module, choose M here. If unsure, say N. 681 To compile it as a module, choose M here. If unsure, say N.
682 682
683config NETFILTER_XT_TARGET_NOTRACK
684 tristate '"NOTRACK" target support (DEPRECATED)'
685 select NETFILTER_XT_TARGET_CT
686
683config NETFILTER_XT_TARGET_RATEEST 687config NETFILTER_XT_TARGET_RATEEST
684 tristate '"RATEEST" target support' 688 tristate '"RATEEST" target support'
685 depends on NETFILTER_ADVANCED 689 depends on NETFILTER_ADVANCED
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 08cdc71d8e87..016d95ead930 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1526,6 +1526,7 @@ err_extend:
1526 */ 1526 */
1527#define UNCONFIRMED_NULLS_VAL ((1<<30)+0) 1527#define UNCONFIRMED_NULLS_VAL ((1<<30)+0)
1528#define DYING_NULLS_VAL ((1<<30)+1) 1528#define DYING_NULLS_VAL ((1<<30)+1)
1529#define TEMPLATE_NULLS_VAL ((1<<30)+2)
1529 1530
1530static int nf_conntrack_init_net(struct net *net) 1531static int nf_conntrack_init_net(struct net *net)
1531{ 1532{
@@ -1534,6 +1535,7 @@ static int nf_conntrack_init_net(struct net *net)
1534 atomic_set(&net->ct.count, 0); 1535 atomic_set(&net->ct.count, 0);
1535 INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, UNCONFIRMED_NULLS_VAL); 1536 INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, UNCONFIRMED_NULLS_VAL);
1536 INIT_HLIST_NULLS_HEAD(&net->ct.dying, DYING_NULLS_VAL); 1537 INIT_HLIST_NULLS_HEAD(&net->ct.dying, DYING_NULLS_VAL);
1538 INIT_HLIST_NULLS_HEAD(&net->ct.tmpl, TEMPLATE_NULLS_VAL);
1537 net->ct.stat = alloc_percpu(struct ip_conntrack_stat); 1539 net->ct.stat = alloc_percpu(struct ip_conntrack_stat);
1538 if (!net->ct.stat) { 1540 if (!net->ct.stat) {
1539 ret = -ENOMEM; 1541 ret = -ENOMEM;
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 4e078cd84d83..627b0e50b238 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -2624,7 +2624,7 @@ ctnetlink_create_expect(struct net *net, u16 zone,
2624 if (!help) { 2624 if (!help) {
2625 if (!cda[CTA_EXPECT_TIMEOUT]) { 2625 if (!cda[CTA_EXPECT_TIMEOUT]) {
2626 err = -EINVAL; 2626 err = -EINVAL;
2627 goto out; 2627 goto err_out;
2628 } 2628 }
2629 exp->timeout.expires = 2629 exp->timeout.expires =
2630 jiffies + ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ; 2630 jiffies + ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ;
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 9f199f2e31fa..92fd8eca0d31 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -13,6 +13,7 @@
13 */ 13 */
14#include <linux/module.h> 14#include <linux/module.h>
15#include <linux/skbuff.h> 15#include <linux/skbuff.h>
16#include <linux/if_arp.h>
16#include <linux/init.h> 17#include <linux/init.h>
17#include <linux/ip.h> 18#include <linux/ip.h>
18#include <linux/ipv6.h> 19#include <linux/ipv6.h>
@@ -384,6 +385,7 @@ __build_packet_message(struct nfulnl_instance *inst,
384 struct nfgenmsg *nfmsg; 385 struct nfgenmsg *nfmsg;
385 sk_buff_data_t old_tail = inst->skb->tail; 386 sk_buff_data_t old_tail = inst->skb->tail;
386 struct sock *sk; 387 struct sock *sk;
388 const unsigned char *hwhdrp;
387 389
388 nlh = nlmsg_put(inst->skb, 0, 0, 390 nlh = nlmsg_put(inst->skb, 0, 0,
389 NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET, 391 NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET,
@@ -485,9 +487,17 @@ __build_packet_message(struct nfulnl_instance *inst,
485 if (indev && skb_mac_header_was_set(skb)) { 487 if (indev && skb_mac_header_was_set(skb)) {
486 if (nla_put_be16(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)) || 488 if (nla_put_be16(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)) ||
487 nla_put_be16(inst->skb, NFULA_HWLEN, 489 nla_put_be16(inst->skb, NFULA_HWLEN,
488 htons(skb->dev->hard_header_len)) || 490 htons(skb->dev->hard_header_len)))
489 nla_put(inst->skb, NFULA_HWHEADER, skb->dev->hard_header_len, 491 goto nla_put_failure;
490 skb_mac_header(skb))) 492
493 hwhdrp = skb_mac_header(skb);
494
495 if (skb->dev->type == ARPHRD_SIT)
496 hwhdrp -= ETH_HLEN;
497
498 if (hwhdrp >= skb->head &&
499 nla_put(inst->skb, NFULA_HWHEADER,
500 skb->dev->hard_header_len, hwhdrp))
491 goto nla_put_failure; 501 goto nla_put_failure;
492 } 502 }
493 503
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index ae7f5daeee43..2a0843081840 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -149,6 +149,10 @@ static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
149 149
150 __set_bit(IPS_TEMPLATE_BIT, &ct->status); 150 __set_bit(IPS_TEMPLATE_BIT, &ct->status);
151 __set_bit(IPS_CONFIRMED_BIT, &ct->status); 151 __set_bit(IPS_CONFIRMED_BIT, &ct->status);
152
153 /* Overload tuple linked list to put us in template list. */
154 hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
155 &par->net->ct.tmpl);
152out: 156out:
153 info->ct = ct; 157 info->ct = ct;
154 return 0; 158 return 0;
@@ -289,6 +293,10 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
289 293
290 __set_bit(IPS_TEMPLATE_BIT, &ct->status); 294 __set_bit(IPS_TEMPLATE_BIT, &ct->status);
291 __set_bit(IPS_CONFIRMED_BIT, &ct->status); 295 __set_bit(IPS_CONFIRMED_BIT, &ct->status);
296
297 /* Overload tuple linked list to put us in template list. */
298 hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
299 &par->net->ct.tmpl);
292out: 300out:
293 info->ct = ct; 301 info->ct = ct;
294 return 0; 302 return 0;
@@ -377,14 +385,60 @@ static struct xt_target xt_ct_tg_reg[] __read_mostly = {
377 }, 385 },
378}; 386};
379 387
388static unsigned int
389notrack_tg(struct sk_buff *skb, const struct xt_action_param *par)
390{
391 /* Previously seen (loopback)? Ignore. */
392 if (skb->nfct != NULL)
393 return XT_CONTINUE;
394
395 skb->nfct = &nf_ct_untracked_get()->ct_general;
396 skb->nfctinfo = IP_CT_NEW;
397 nf_conntrack_get(skb->nfct);
398
399 return XT_CONTINUE;
400}
401
402static int notrack_chk(const struct xt_tgchk_param *par)
403{
404 if (!par->net->xt.notrack_deprecated_warning) {
405 pr_info("netfilter: NOTRACK target is deprecated, "
406 "use CT instead or upgrade iptables\n");
407 par->net->xt.notrack_deprecated_warning = true;
408 }
409 return 0;
410}
411
412static struct xt_target notrack_tg_reg __read_mostly = {
413 .name = "NOTRACK",
414 .revision = 0,
415 .family = NFPROTO_UNSPEC,
416 .checkentry = notrack_chk,
417 .target = notrack_tg,
418 .table = "raw",
419 .me = THIS_MODULE,
420};
421
380static int __init xt_ct_tg_init(void) 422static int __init xt_ct_tg_init(void)
381{ 423{
382 return xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); 424 int ret;
425
426 ret = xt_register_target(&notrack_tg_reg);
427 if (ret < 0)
428 return ret;
429
430 ret = xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
431 if (ret < 0) {
432 xt_unregister_target(&notrack_tg_reg);
433 return ret;
434 }
435 return 0;
383} 436}
384 437
385static void __exit xt_ct_tg_exit(void) 438static void __exit xt_ct_tg_exit(void)
386{ 439{
387 xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); 440 xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
441 xt_unregister_target(&notrack_tg_reg);
388} 442}
389 443
390module_init(xt_ct_tg_init); 444module_init(xt_ct_tg_init);
@@ -394,3 +448,5 @@ MODULE_LICENSE("GPL");
394MODULE_DESCRIPTION("Xtables: connection tracking target"); 448MODULE_DESCRIPTION("Xtables: connection tracking target");
395MODULE_ALIAS("ipt_CT"); 449MODULE_ALIAS("ipt_CT");
396MODULE_ALIAS("ip6t_CT"); 450MODULE_ALIAS("ip6t_CT");
451MODULE_ALIAS("ipt_NOTRACK");
452MODULE_ALIAS("ip6t_NOTRACK");
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index 26a668a84aa2..a9d7af953ceb 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -157,11 +157,22 @@ dsthash_find(const struct xt_hashlimit_htable *ht,
157/* allocate dsthash_ent, initialize dst, put in htable and lock it */ 157/* allocate dsthash_ent, initialize dst, put in htable and lock it */
158static struct dsthash_ent * 158static struct dsthash_ent *
159dsthash_alloc_init(struct xt_hashlimit_htable *ht, 159dsthash_alloc_init(struct xt_hashlimit_htable *ht,
160 const struct dsthash_dst *dst) 160 const struct dsthash_dst *dst, bool *race)
161{ 161{
162 struct dsthash_ent *ent; 162 struct dsthash_ent *ent;
163 163
164 spin_lock(&ht->lock); 164 spin_lock(&ht->lock);
165
166 /* Two or more packets may race to create the same entry in the
167 * hashtable, double check if this packet lost race.
168 */
169 ent = dsthash_find(ht, dst);
170 if (ent != NULL) {
171 spin_unlock(&ht->lock);
172 *race = true;
173 return ent;
174 }
175
165 /* initialize hash with random val at the time we allocate 176 /* initialize hash with random val at the time we allocate
166 * the first hashtable entry */ 177 * the first hashtable entry */
167 if (unlikely(!ht->rnd_initialized)) { 178 if (unlikely(!ht->rnd_initialized)) {
@@ -318,7 +329,10 @@ static void htable_destroy(struct xt_hashlimit_htable *hinfo)
318 parent = hashlimit_net->ipt_hashlimit; 329 parent = hashlimit_net->ipt_hashlimit;
319 else 330 else
320 parent = hashlimit_net->ip6t_hashlimit; 331 parent = hashlimit_net->ip6t_hashlimit;
321 remove_proc_entry(hinfo->pde->name, parent); 332
333 if(parent != NULL)
334 remove_proc_entry(hinfo->pde->name, parent);
335
322 htable_selective_cleanup(hinfo, select_all); 336 htable_selective_cleanup(hinfo, select_all);
323 vfree(hinfo); 337 vfree(hinfo);
324} 338}
@@ -585,6 +599,7 @@ hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
585 unsigned long now = jiffies; 599 unsigned long now = jiffies;
586 struct dsthash_ent *dh; 600 struct dsthash_ent *dh;
587 struct dsthash_dst dst; 601 struct dsthash_dst dst;
602 bool race = false;
588 u32 cost; 603 u32 cost;
589 604
590 if (hashlimit_init_dst(hinfo, &dst, skb, par->thoff) < 0) 605 if (hashlimit_init_dst(hinfo, &dst, skb, par->thoff) < 0)
@@ -593,13 +608,18 @@ hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
593 rcu_read_lock_bh(); 608 rcu_read_lock_bh();
594 dh = dsthash_find(hinfo, &dst); 609 dh = dsthash_find(hinfo, &dst);
595 if (dh == NULL) { 610 if (dh == NULL) {
596 dh = dsthash_alloc_init(hinfo, &dst); 611 dh = dsthash_alloc_init(hinfo, &dst, &race);
597 if (dh == NULL) { 612 if (dh == NULL) {
598 rcu_read_unlock_bh(); 613 rcu_read_unlock_bh();
599 goto hotdrop; 614 goto hotdrop;
615 } else if (race) {
616 /* Already got an entry, update expiration timeout */
617 dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);
618 rateinfo_recalc(dh, now, hinfo->cfg.mode);
619 } else {
620 dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
621 rateinfo_init(dh, hinfo);
600 } 622 }
601 dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
602 rateinfo_init(dh, hinfo);
603 } else { 623 } else {
604 /* update expiration timeout */ 624 /* update expiration timeout */
605 dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); 625 dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);
@@ -856,6 +876,27 @@ static int __net_init hashlimit_proc_net_init(struct net *net)
856 876
857static void __net_exit hashlimit_proc_net_exit(struct net *net) 877static void __net_exit hashlimit_proc_net_exit(struct net *net)
858{ 878{
879 struct xt_hashlimit_htable *hinfo;
880 struct hlist_node *pos;
881 struct proc_dir_entry *pde;
882 struct hashlimit_net *hashlimit_net = hashlimit_pernet(net);
883
884 /* recent_net_exit() is called before recent_mt_destroy(). Make sure
885 * that the parent xt_recent proc entry is is empty before trying to
886 * remove it.
887 */
888 mutex_lock(&hashlimit_mutex);
889 pde = hashlimit_net->ipt_hashlimit;
890 if (pde == NULL)
891 pde = hashlimit_net->ip6t_hashlimit;
892
893 hlist_for_each_entry(hinfo, pos, &hashlimit_net->htables, node)
894 remove_proc_entry(hinfo->pde->name, pde);
895
896 hashlimit_net->ipt_hashlimit = NULL;
897 hashlimit_net->ip6t_hashlimit = NULL;
898 mutex_unlock(&hashlimit_mutex);
899
859 proc_net_remove(net, "ipt_hashlimit"); 900 proc_net_remove(net, "ipt_hashlimit");
860#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 901#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
861 proc_net_remove(net, "ip6t_hashlimit"); 902 proc_net_remove(net, "ip6t_hashlimit");
@@ -872,9 +913,6 @@ static int __net_init hashlimit_net_init(struct net *net)
872 913
873static void __net_exit hashlimit_net_exit(struct net *net) 914static void __net_exit hashlimit_net_exit(struct net *net)
874{ 915{
875 struct hashlimit_net *hashlimit_net = hashlimit_pernet(net);
876
877 BUG_ON(!hlist_empty(&hashlimit_net->htables));
878 hashlimit_proc_net_exit(net); 916 hashlimit_proc_net_exit(net);
879} 917}
880 918
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index 4635c9b00459..dab053e2a1a2 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -431,7 +431,8 @@ static void recent_mt_destroy(const struct xt_mtdtor_param *par)
431 list_del(&t->list); 431 list_del(&t->list);
432 spin_unlock_bh(&recent_lock); 432 spin_unlock_bh(&recent_lock);
433#ifdef CONFIG_PROC_FS 433#ifdef CONFIG_PROC_FS
434 remove_proc_entry(t->name, recent_net->xt_recent); 434 if (recent_net->xt_recent != NULL)
435 remove_proc_entry(t->name, recent_net->xt_recent);
435#endif 436#endif
436 recent_table_flush(t); 437 recent_table_flush(t);
437 kfree(t); 438 kfree(t);
@@ -615,6 +616,20 @@ static int __net_init recent_proc_net_init(struct net *net)
615 616
616static void __net_exit recent_proc_net_exit(struct net *net) 617static void __net_exit recent_proc_net_exit(struct net *net)
617{ 618{
619 struct recent_net *recent_net = recent_pernet(net);
620 struct recent_table *t;
621
622 /* recent_net_exit() is called before recent_mt_destroy(). Make sure
623 * that the parent xt_recent proc entry is is empty before trying to
624 * remove it.
625 */
626 spin_lock_bh(&recent_lock);
627 list_for_each_entry(t, &recent_net->tables, list)
628 remove_proc_entry(t->name, recent_net->xt_recent);
629
630 recent_net->xt_recent = NULL;
631 spin_unlock_bh(&recent_lock);
632
618 proc_net_remove(net, "xt_recent"); 633 proc_net_remove(net, "xt_recent");
619} 634}
620#else 635#else
@@ -638,9 +653,6 @@ static int __net_init recent_net_init(struct net *net)
638 653
639static void __net_exit recent_net_exit(struct net *net) 654static void __net_exit recent_net_exit(struct net *net)
640{ 655{
641 struct recent_net *recent_net = recent_pernet(net);
642
643 BUG_ON(!list_empty(&recent_net->tables));
644 recent_proc_net_exit(net); 656 recent_proc_net_exit(net);
645} 657}
646 658