diff options
author | Patrick McHardy <kaber@trash.net> | 2014-01-09 18:42:32 +0000 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2014-01-09 20:17:13 +0100 |
commit | 4401a862009bca28f02dcea4241191c27328816c (patch) | |
tree | 3b701a4a2ff9d600e1591f4539b87c9a1b9c5c13 /net/netfilter | |
parent | 57de2a0cd9d7e4cfc6479ecbebfcd36dbc61d5ed (diff) |
netfilter: nf_tables: restore chain change atomicity
Chain counter validation is performed after the chain policy has
potentially been changed. Move counter validation/setting before
changing of the chain policy to fix this.
Additionally fix a memory leak if chain counter allocation fails
for new chains, remove an unnecessary free_percpu() and move
counter allocation for new chains
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/nf_tables_api.c | 43 |
1 files changed, 21 insertions, 22 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 30fad4f6322..d275d384bbc 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -880,9 +880,6 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]))) return -EEXIST; - if (nla[NFTA_CHAIN_POLICY]) - nft_base_chain(chain)->policy = policy; - if (nla[NFTA_CHAIN_COUNTERS]) { if (!(chain->flags & NFT_BASE_CHAIN)) return -EOPNOTSUPP; @@ -893,6 +890,9 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, return err; } + if (nla[NFTA_CHAIN_POLICY]) + nft_base_chain(chain)->policy = policy; + if (nla[NFTA_CHAIN_HANDLE] && name) nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN); @@ -934,6 +934,24 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, if (basechain == NULL) return -ENOMEM; + if (nla[NFTA_CHAIN_COUNTERS]) { + err = nf_tables_counters(basechain, + nla[NFTA_CHAIN_COUNTERS]); + if (err < 0) { + kfree(basechain); + return err; + } + } else { + struct nft_stats __percpu *newstats; + + newstats = alloc_percpu(struct nft_stats); + if (newstats == NULL) { + kfree(basechain); + return -ENOMEM; + } + rcu_assign_pointer(basechain->stats, newstats); + } + basechain->type = type; chain = &basechain->chain; @@ -953,25 +971,6 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, chain->flags |= NFT_BASE_CHAIN; basechain->policy = policy; - - if (nla[NFTA_CHAIN_COUNTERS]) { - err = nf_tables_counters(basechain, - nla[NFTA_CHAIN_COUNTERS]); - if (err < 0) { - free_percpu(basechain->stats); - kfree(basechain); - return err; - } - } else { - struct nft_stats __percpu *newstats; - - newstats = alloc_percpu(struct nft_stats); - if (newstats == NULL) - return -ENOMEM; - - rcu_assign_pointer(nft_base_chain(chain)->stats, - newstats); - } } else { chain = kzalloc(sizeof(*chain), GFP_KERNEL); if (chain == NULL) |