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

Pablo Neira Ayuso says:

====================
netfilter/ipvs fixes for net

The following patchset contains netfilter/ipvs fixes, they are:

1) Small fix for the FTP helper in IPVS, a diff variable may be left
   unset when CONFIG_IP_VS_IPV6 is set. Patch from Dan Carpenter.

2) Fix nf_tables port NAT in little endian archs, patch from leroy
   christophe.

3) Fix race condition between conntrack confirmation and flush from
   userspace. This is the second reincarnation to resolve this problem.

4) Make sure inner messages in the batch come with the nfnetlink header.

5) Relax strict check from nfnetlink_bind() that may break old userspace
   applications using all 1s group mask.

6) Schedule removal of chains once no sets and rules refer to them in
   the new nf_tables ruleset flush command. Reported by Asbjoern Sloth
   Toennesen.

Note that this batch comes later than usual because of the short
winter holidays.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2015-01-12 00:14:49 -05:00
commit 2bd8221804
7 changed files with 38 additions and 35 deletions

View File

@ -27,10 +27,10 @@ static void nft_redir_ipv4_eval(const struct nft_expr *expr,
memset(&mr, 0, sizeof(mr)); memset(&mr, 0, sizeof(mr));
if (priv->sreg_proto_min) { if (priv->sreg_proto_min) {
mr.range[0].min.all = (__force __be16) mr.range[0].min.all =
data[priv->sreg_proto_min].data[0]; *(__be16 *)&data[priv->sreg_proto_min].data[0];
mr.range[0].max.all = (__force __be16) mr.range[0].max.all =
data[priv->sreg_proto_max].data[0]; *(__be16 *)&data[priv->sreg_proto_max].data[0];
mr.range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; mr.range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
} }

View File

@ -27,10 +27,10 @@ static void nft_redir_ipv6_eval(const struct nft_expr *expr,
memset(&range, 0, sizeof(range)); memset(&range, 0, sizeof(range));
if (priv->sreg_proto_min) { if (priv->sreg_proto_min) {
range.min_proto.all = (__force __be16) range.min_proto.all =
data[priv->sreg_proto_min].data[0]; *(__be16 *)&data[priv->sreg_proto_min].data[0];
range.max_proto.all = (__force __be16) range.max_proto.all =
data[priv->sreg_proto_max].data[0]; *(__be16 *)&data[priv->sreg_proto_max].data[0];
range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
} }

View File

@ -183,6 +183,8 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
struct nf_conn *ct; struct nf_conn *ct;
struct net *net; struct net *net;
*diff = 0;
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
/* This application helper doesn't work with IPv6 yet, /* This application helper doesn't work with IPv6 yet,
* so turn this into a no-op for IPv6 packets * so turn this into a no-op for IPv6 packets
@ -191,8 +193,6 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
return 1; return 1;
#endif #endif
*diff = 0;
/* Only useful for established sessions */ /* Only useful for established sessions */
if (cp->state != IP_VS_TCP_S_ESTABLISHED) if (cp->state != IP_VS_TCP_S_ESTABLISHED)
return 1; return 1;
@ -322,6 +322,9 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
struct ip_vs_conn *n_cp; struct ip_vs_conn *n_cp;
struct net *net; struct net *net;
/* no diff required for incoming packets */
*diff = 0;
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
/* This application helper doesn't work with IPv6 yet, /* This application helper doesn't work with IPv6 yet,
* so turn this into a no-op for IPv6 packets * so turn this into a no-op for IPv6 packets
@ -330,9 +333,6 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
return 1; return 1;
#endif #endif
/* no diff required for incoming packets */
*diff = 0;
/* Only useful for established sessions */ /* Only useful for established sessions */
if (cp->state != IP_VS_TCP_S_ESTABLISHED) if (cp->state != IP_VS_TCP_S_ESTABLISHED)
return 1; return 1;

View File

@ -611,16 +611,15 @@ __nf_conntrack_confirm(struct sk_buff *skb)
*/ */
NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
pr_debug("Confirming conntrack %p\n", ct); pr_debug("Confirming conntrack %p\n", ct);
/* We have to check the DYING flag inside the lock to prevent /* We have to check the DYING flag after unlink to prevent
a race against nf_ct_get_next_corpse() possibly called from * a race against nf_ct_get_next_corpse() possibly called from
user context, else we insert an already 'dead' hash, blocking * user context, else we insert an already 'dead' hash, blocking
further use of that particular connection -JM */ * further use of that particular connection -JM.
*/
nf_ct_del_from_dying_or_unconfirmed_list(ct);
if (unlikely(nf_ct_is_dying(ct))) { if (unlikely(nf_ct_is_dying(ct)))
nf_conntrack_double_unlock(hash, reply_hash); goto out;
local_bh_enable();
return NF_ACCEPT;
}
/* See if there's one in the list already, including reverse: /* See if there's one in the list already, including reverse:
NAT could have grabbed it without realizing, since we're NAT could have grabbed it without realizing, since we're
@ -636,8 +635,6 @@ __nf_conntrack_confirm(struct sk_buff *skb)
zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h))) zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
goto out; goto out;
nf_ct_del_from_dying_or_unconfirmed_list(ct);
/* Timer relative to confirmation time, not original /* Timer relative to confirmation time, not original
setting time, otherwise we'd get timer wrap in setting time, otherwise we'd get timer wrap in
weird delay cases. */ weird delay cases. */
@ -673,6 +670,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
return NF_ACCEPT; return NF_ACCEPT;
out: out:
nf_ct_add_to_dying_list(ct);
nf_conntrack_double_unlock(hash, reply_hash); nf_conntrack_double_unlock(hash, reply_hash);
NF_CT_STAT_INC(net, insert_failed); NF_CT_STAT_INC(net, insert_failed);
local_bh_enable(); local_bh_enable();

View File

@ -713,16 +713,12 @@ static int nft_flush_table(struct nft_ctx *ctx)
struct nft_chain *chain, *nc; struct nft_chain *chain, *nc;
struct nft_set *set, *ns; struct nft_set *set, *ns;
list_for_each_entry_safe(chain, nc, &ctx->table->chains, list) { list_for_each_entry(chain, &ctx->table->chains, list) {
ctx->chain = chain; ctx->chain = chain;
err = nft_delrule_by_chain(ctx); err = nft_delrule_by_chain(ctx);
if (err < 0) if (err < 0)
goto out; goto out;
err = nft_delchain(ctx);
if (err < 0)
goto out;
} }
list_for_each_entry_safe(set, ns, &ctx->table->sets, list) { list_for_each_entry_safe(set, ns, &ctx->table->sets, list) {
@ -735,6 +731,14 @@ static int nft_flush_table(struct nft_ctx *ctx)
goto out; goto out;
} }
list_for_each_entry_safe(chain, nc, &ctx->table->chains, list) {
ctx->chain = chain;
err = nft_delchain(ctx);
if (err < 0)
goto out;
}
err = nft_deltable(ctx); err = nft_deltable(ctx);
out: out:
return err; return err;

View File

@ -321,7 +321,8 @@ replay:
nlh = nlmsg_hdr(skb); nlh = nlmsg_hdr(skb);
err = 0; err = 0;
if (nlh->nlmsg_len < NLMSG_HDRLEN) { if (nlmsg_len(nlh) < sizeof(struct nfgenmsg) ||
skb->len < nlh->nlmsg_len) {
err = -EINVAL; err = -EINVAL;
goto ack; goto ack;
} }
@ -469,7 +470,7 @@ static int nfnetlink_bind(struct net *net, int group)
int type; int type;
if (group <= NFNLGRP_NONE || group > NFNLGRP_MAX) if (group <= NFNLGRP_NONE || group > NFNLGRP_MAX)
return -EINVAL; return 0;
type = nfnl_group2type[group]; type = nfnl_group2type[group];

View File

@ -65,10 +65,10 @@ static void nft_nat_eval(const struct nft_expr *expr,
} }
if (priv->sreg_proto_min) { if (priv->sreg_proto_min) {
range.min_proto.all = (__force __be16) range.min_proto.all =
data[priv->sreg_proto_min].data[0]; *(__be16 *)&data[priv->sreg_proto_min].data[0];
range.max_proto.all = (__force __be16) range.max_proto.all =
data[priv->sreg_proto_max].data[0]; *(__be16 *)&data[priv->sreg_proto_max].data[0];
range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
} }