Commit 3a3ec1b2 authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf

Pablo Neira Ayuso says:

====================
netfilter fixes for net

The following patchset contains netfilter updates for your net tree,
they are:

1) Fix refcount leak when dumping the dying/unconfirmed conntrack lists,
   from Florian Westphal.

2) Fix crash in NAT when removing a netnamespace, also from Florian.

3) Fix a crash in IPVS when trying to remove an estimator out of the
   sysctl scope, from Julian Anastasov.

4) Add zone attribute to the routing to calculate the message size in
   ctnetlink events, from Ken-ichirou MATSUZAWA.

5) Another fix for the dying/unconfirmed list which was preventing to
   dump more than one memory page of entries (~17 entries in x86_64).

6) Fix missing RCU-safe list insertion in the rule replacement code
   in nf_tables.

7) Since the new transaction infrastructure is in place, we have to
   upgrade the chain use counter from u16 to u32 to avoid overflow
   after more than 2^16 rules are added.

8) Fix refcount leak when replacing rule in nf_tables. This problem
   was also introduced in new transaction.

9) Call the ->destroy() callback when releasing nft-xt rules to fix
   module refcount leaks.

10) Set the family in the netlink messages that contain set elements
    in nf_tables to make it consistent with other object types.

11) Don't dump NAT port information if it is unset in nft_nat.

12) Update the MAINTAINERS file, I have merged the ebtables entry
    into netfilter. While at it, also removed the netfilter users
    mailing list, the development list should be enough.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 62a02c98 db9cf3a3
...@@ -3189,14 +3189,6 @@ L: linux-scsi@vger.kernel.org ...@@ -3189,14 +3189,6 @@ L: linux-scsi@vger.kernel.org
S: Maintained S: Maintained
F: drivers/scsi/eata_pio.* F: drivers/scsi/eata_pio.*
EBTABLES
L: netfilter-devel@vger.kernel.org
W: http://ebtables.sourceforge.net/
S: Orphan
F: include/linux/netfilter_bridge/ebt_*.h
F: include/uapi/linux/netfilter_bridge/ebt_*.h
F: net/bridge/netfilter/ebt*.c
EC100 MEDIA DRIVER EC100 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi> M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org L: linux-media@vger.kernel.org
...@@ -6105,12 +6097,11 @@ F: Documentation/networking/s2io.txt ...@@ -6105,12 +6097,11 @@ F: Documentation/networking/s2io.txt
F: Documentation/networking/vxge.txt F: Documentation/networking/vxge.txt
F: drivers/net/ethernet/neterion/ F: drivers/net/ethernet/neterion/
NETFILTER/IPTABLES NETFILTER ({IP,IP6,ARP,EB,NF}TABLES)
M: Pablo Neira Ayuso <pablo@netfilter.org> M: Pablo Neira Ayuso <pablo@netfilter.org>
M: Patrick McHardy <kaber@trash.net> M: Patrick McHardy <kaber@trash.net>
M: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> M: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
L: netfilter-devel@vger.kernel.org L: netfilter-devel@vger.kernel.org
L: netfilter@vger.kernel.org
L: coreteam@netfilter.org L: coreteam@netfilter.org
W: http://www.netfilter.org/ W: http://www.netfilter.org/
W: http://www.iptables.org/ W: http://www.iptables.org/
......
...@@ -503,9 +503,9 @@ enum nft_chain_flags { ...@@ -503,9 +503,9 @@ enum nft_chain_flags {
* @net: net namespace that this chain belongs to * @net: net namespace that this chain belongs to
* @table: table that this chain belongs to * @table: table that this chain belongs to
* @handle: chain handle * @handle: chain handle
* @flags: bitmask of enum nft_chain_flags
* @use: number of jump references to this chain * @use: number of jump references to this chain
* @level: length of longest path to this chain * @level: length of longest path to this chain
* @flags: bitmask of enum nft_chain_flags
* @name: name of the chain * @name: name of the chain
*/ */
struct nft_chain { struct nft_chain {
...@@ -514,9 +514,9 @@ struct nft_chain { ...@@ -514,9 +514,9 @@ struct nft_chain {
struct net *net; struct net *net;
struct nft_table *table; struct nft_table *table;
u64 handle; u64 handle;
u8 flags; u32 use;
u16 use;
u16 level; u16 level;
u8 flags;
char name[NFT_CHAIN_MAXNAMELEN]; char name[NFT_CHAIN_MAXNAMELEN];
}; };
......
...@@ -3778,6 +3778,7 @@ static void __net_exit ip_vs_control_net_cleanup_sysctl(struct net *net) ...@@ -3778,6 +3778,7 @@ static void __net_exit ip_vs_control_net_cleanup_sysctl(struct net *net)
cancel_delayed_work_sync(&ipvs->defense_work); cancel_delayed_work_sync(&ipvs->defense_work);
cancel_work_sync(&ipvs->defense_work.work); cancel_work_sync(&ipvs->defense_work.work);
unregister_net_sysctl_table(ipvs->sysctl_hdr); unregister_net_sysctl_table(ipvs->sysctl_hdr);
ip_vs_stop_estimator(net, &ipvs->tot_stats);
} }
#else #else
...@@ -3840,7 +3841,6 @@ void __net_exit ip_vs_control_net_cleanup(struct net *net) ...@@ -3840,7 +3841,6 @@ void __net_exit ip_vs_control_net_cleanup(struct net *net)
struct netns_ipvs *ipvs = net_ipvs(net); struct netns_ipvs *ipvs = net_ipvs(net);
ip_vs_trash_cleanup(net); ip_vs_trash_cleanup(net);
ip_vs_stop_estimator(net, &ipvs->tot_stats);
ip_vs_control_net_cleanup_sysctl(net); ip_vs_control_net_cleanup_sysctl(net);
remove_proc_entry("ip_vs_stats_percpu", net->proc_net); remove_proc_entry("ip_vs_stats_percpu", net->proc_net);
remove_proc_entry("ip_vs_stats", net->proc_net); remove_proc_entry("ip_vs_stats", net->proc_net);
......
...@@ -596,6 +596,9 @@ ctnetlink_nlmsg_size(const struct nf_conn *ct) ...@@ -596,6 +596,9 @@ ctnetlink_nlmsg_size(const struct nf_conn *ct)
#endif #endif
#ifdef CONFIG_NF_CONNTRACK_MARK #ifdef CONFIG_NF_CONNTRACK_MARK
+ nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */ + nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */
#endif
#ifdef CONFIG_NF_CONNTRACK_ZONES
+ nla_total_size(sizeof(u_int16_t)) /* CTA_ZONE */
#endif #endif
+ ctnetlink_proto_size(ct) + ctnetlink_proto_size(ct)
+ ctnetlink_label_size(ct) + ctnetlink_label_size(ct)
...@@ -1150,7 +1153,7 @@ static int ctnetlink_done_list(struct netlink_callback *cb) ...@@ -1150,7 +1153,7 @@ static int ctnetlink_done_list(struct netlink_callback *cb)
static int static int
ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying) ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying)
{ {
struct nf_conn *ct, *last = NULL; struct nf_conn *ct, *last;
struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple_hash *h;
struct hlist_nulls_node *n; struct hlist_nulls_node *n;
struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
...@@ -1163,8 +1166,7 @@ ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying ...@@ -1163,8 +1166,7 @@ ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying
if (cb->args[2]) if (cb->args[2])
return 0; return 0;
if (cb->args[0] == nr_cpu_ids) last = (struct nf_conn *)cb->args[1];
return 0;
for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) { for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) {
struct ct_pcpu *pcpu; struct ct_pcpu *pcpu;
...@@ -1174,7 +1176,6 @@ ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying ...@@ -1174,7 +1176,6 @@ ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying
pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
spin_lock_bh(&pcpu->lock); spin_lock_bh(&pcpu->lock);
last = (struct nf_conn *)cb->args[1];
list = dying ? &pcpu->dying : &pcpu->unconfirmed; list = dying ? &pcpu->dying : &pcpu->unconfirmed;
restart: restart:
hlist_nulls_for_each_entry(h, n, list, hnnode) { hlist_nulls_for_each_entry(h, n, list, hnnode) {
...@@ -1193,7 +1194,9 @@ ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying ...@@ -1193,7 +1194,9 @@ ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying
ct); ct);
rcu_read_unlock(); rcu_read_unlock();
if (res < 0) { if (res < 0) {
nf_conntrack_get(&ct->ct_general); if (!atomic_inc_not_zero(&ct->ct_general.use))
continue;
cb->args[0] = cpu;
cb->args[1] = (unsigned long)ct; cb->args[1] = (unsigned long)ct;
spin_unlock_bh(&pcpu->lock); spin_unlock_bh(&pcpu->lock);
goto out; goto out;
...@@ -1202,10 +1205,10 @@ ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying ...@@ -1202,10 +1205,10 @@ ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying
if (cb->args[1]) { if (cb->args[1]) {
cb->args[1] = 0; cb->args[1] = 0;
goto restart; goto restart;
} else }
cb->args[2] = 1;
spin_unlock_bh(&pcpu->lock); spin_unlock_bh(&pcpu->lock);
} }
cb->args[2] = 1;
out: out:
if (last) if (last)
nf_ct_put(last); nf_ct_put(last);
...@@ -2039,6 +2042,9 @@ ctnetlink_nfqueue_build_size(const struct nf_conn *ct) ...@@ -2039,6 +2042,9 @@ ctnetlink_nfqueue_build_size(const struct nf_conn *ct)
#endif #endif
#ifdef CONFIG_NF_CONNTRACK_MARK #ifdef CONFIG_NF_CONNTRACK_MARK
+ nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */ + nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */
#endif
#ifdef CONFIG_NF_CONNTRACK_ZONES
+ nla_total_size(sizeof(u_int16_t)) /* CTA_ZONE */
#endif #endif
+ ctnetlink_proto_size(ct) + ctnetlink_proto_size(ct)
; ;
......
...@@ -525,6 +525,39 @@ static int nf_nat_proto_remove(struct nf_conn *i, void *data) ...@@ -525,6 +525,39 @@ static int nf_nat_proto_remove(struct nf_conn *i, void *data)
return i->status & IPS_NAT_MASK ? 1 : 0; return i->status & IPS_NAT_MASK ? 1 : 0;
} }
static int nf_nat_proto_clean(struct nf_conn *ct, void *data)
{
struct nf_conn_nat *nat = nfct_nat(ct);
if (nf_nat_proto_remove(ct, data))
return 1;
if (!nat || !nat->ct)
return 0;
/* This netns is being destroyed, and conntrack has nat null binding.
* Remove it from bysource hash, as the table will be freed soon.
*
* Else, when the conntrack is destoyed, nf_nat_cleanup_conntrack()
* will delete entry from already-freed table.
*/
if (!del_timer(&ct->timeout))
return 1;
spin_lock_bh(&nf_nat_lock);
hlist_del_rcu(&nat->bysource);
ct->status &= ~IPS_NAT_DONE_MASK;
nat->ct = NULL;
spin_unlock_bh(&nf_nat_lock);
add_timer(&ct->timeout);
/* don't delete conntrack. Although that would make things a lot
* simpler, we'd end up flushing all conntracks on nat rmmod.
*/
return 0;
}
static void nf_nat_l4proto_clean(u8 l3proto, u8 l4proto) static void nf_nat_l4proto_clean(u8 l3proto, u8 l4proto)
{ {
struct nf_nat_proto_clean clean = { struct nf_nat_proto_clean clean = {
...@@ -795,7 +828,7 @@ static void __net_exit nf_nat_net_exit(struct net *net) ...@@ -795,7 +828,7 @@ static void __net_exit nf_nat_net_exit(struct net *net)
{ {
struct nf_nat_proto_clean clean = {}; struct nf_nat_proto_clean clean = {};
nf_ct_iterate_cleanup(net, &nf_nat_proto_remove, &clean, 0, 0); nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean, 0, 0);
synchronize_rcu(); synchronize_rcu();
nf_ct_free_hashtable(net->ct.nat_bysource, net->ct.nat_htable_size); nf_ct_free_hashtable(net->ct.nat_bysource, net->ct.nat_htable_size);
} }
......
...@@ -1730,6 +1730,9 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, ...@@ -1730,6 +1730,9 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
if (!create || nlh->nlmsg_flags & NLM_F_REPLACE) if (!create || nlh->nlmsg_flags & NLM_F_REPLACE)
return -EINVAL; return -EINVAL;
handle = nf_tables_alloc_handle(table); handle = nf_tables_alloc_handle(table);
if (chain->use == UINT_MAX)
return -EOVERFLOW;
} }
if (nla[NFTA_RULE_POSITION]) { if (nla[NFTA_RULE_POSITION]) {
...@@ -1789,14 +1792,15 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, ...@@ -1789,14 +1792,15 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
if (nlh->nlmsg_flags & NLM_F_REPLACE) { if (nlh->nlmsg_flags & NLM_F_REPLACE) {
if (nft_rule_is_active_next(net, old_rule)) { if (nft_rule_is_active_next(net, old_rule)) {
trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, trans = nft_trans_rule_add(&ctx, NFT_MSG_DELRULE,
old_rule); old_rule);
if (trans == NULL) { if (trans == NULL) {
err = -ENOMEM; err = -ENOMEM;
goto err2; goto err2;
} }
nft_rule_disactivate_next(net, old_rule); nft_rule_disactivate_next(net, old_rule);
list_add_tail(&rule->list, &old_rule->list); chain->use--;
list_add_tail_rcu(&rule->list, &old_rule->list);
} else { } else {
err = -ENOENT; err = -ENOENT;
goto err2; goto err2;
...@@ -1826,6 +1830,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, ...@@ -1826,6 +1830,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
list_del_rcu(&nft_trans_rule(trans)->list); list_del_rcu(&nft_trans_rule(trans)->list);
nft_rule_clear(net, nft_trans_rule(trans)); nft_rule_clear(net, nft_trans_rule(trans));
nft_trans_destroy(trans); nft_trans_destroy(trans);
chain->use++;
} }
err2: err2:
nf_tables_rule_destroy(&ctx, rule); nf_tables_rule_destroy(&ctx, rule);
...@@ -2845,7 +2850,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -2845,7 +2850,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
goto nla_put_failure; goto nla_put_failure;
nfmsg = nlmsg_data(nlh); nfmsg = nlmsg_data(nlh);
nfmsg->nfgen_family = NFPROTO_UNSPEC; nfmsg->nfgen_family = ctx.afi->family;
nfmsg->version = NFNETLINK_V0; nfmsg->version = NFNETLINK_V0;
nfmsg->res_id = 0; nfmsg->res_id = 0;
......
...@@ -195,6 +195,15 @@ static void ...@@ -195,6 +195,15 @@ static void
nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
{ {
struct xt_target *target = expr->ops->data; struct xt_target *target = expr->ops->data;
void *info = nft_expr_priv(expr);
struct xt_tgdtor_param par;
par.net = ctx->net;
par.target = target;
par.targinfo = info;
par.family = ctx->afi->family;
if (par.target->destroy != NULL)
par.target->destroy(&par);
module_put(target->me); module_put(target->me);
} }
...@@ -382,6 +391,15 @@ static void ...@@ -382,6 +391,15 @@ static void
nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
{ {
struct xt_match *match = expr->ops->data; struct xt_match *match = expr->ops->data;
void *info = nft_expr_priv(expr);
struct xt_mtdtor_param par;
par.net = ctx->net;
par.match = match;
par.matchinfo = info;
par.family = ctx->afi->family;
if (par.match->destroy != NULL)
par.match->destroy(&par);
module_put(match->me); module_put(match->me);
} }
......
...@@ -175,12 +175,14 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr) ...@@ -175,12 +175,14 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
if (nla_put_be32(skb, if (nla_put_be32(skb,
NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max))) NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max)))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_be32(skb, if (priv->sreg_proto_min) {
NFTA_NAT_REG_PROTO_MIN, htonl(priv->sreg_proto_min))) if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MIN,
htonl(priv->sreg_proto_min)))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_be32(skb, if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MAX,
NFTA_NAT_REG_PROTO_MAX, htonl(priv->sreg_proto_max))) htonl(priv->sreg_proto_max)))
goto nla_put_failure; goto nla_put_failure;
}
return 0; return 0;
nla_put_failure: nla_put_failure:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment