aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2014-01-09 13:42:32 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2014-01-09 14:17:13 -0500
commit4401a862009bca28f02dcea4241191c27328816c (patch)
tree3b701a4a2ff9d600e1591f4539b87c9a1b9c5c13 /net/netfilter
parent57de2a0cd9d7e4cfc6479ecbebfcd36dbc61d5ed (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.c43
1 files changed, 21 insertions, 22 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 30fad4f6322f..d275d384bbc5 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,
880 !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]))) 880 !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME])))
881 return -EEXIST; 881 return -EEXIST;
882 882
883 if (nla[NFTA_CHAIN_POLICY])
884 nft_base_chain(chain)->policy = policy;
885
886 if (nla[NFTA_CHAIN_COUNTERS]) { 883 if (nla[NFTA_CHAIN_COUNTERS]) {
887 if (!(chain->flags & NFT_BASE_CHAIN)) 884 if (!(chain->flags & NFT_BASE_CHAIN))
888 return -EOPNOTSUPP; 885 return -EOPNOTSUPP;
@@ -893,6 +890,9 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
893 return err; 890 return err;
894 } 891 }
895 892
893 if (nla[NFTA_CHAIN_POLICY])
894 nft_base_chain(chain)->policy = policy;
895
896 if (nla[NFTA_CHAIN_HANDLE] && name) 896 if (nla[NFTA_CHAIN_HANDLE] && name)
897 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN); 897 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
898 898
@@ -934,6 +934,24 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
934 if (basechain == NULL) 934 if (basechain == NULL)
935 return -ENOMEM; 935 return -ENOMEM;
936 936
937 if (nla[NFTA_CHAIN_COUNTERS]) {
938 err = nf_tables_counters(basechain,
939 nla[NFTA_CHAIN_COUNTERS]);
940 if (err < 0) {
941 kfree(basechain);
942 return err;
943 }
944 } else {
945 struct nft_stats __percpu *newstats;
946
947 newstats = alloc_percpu(struct nft_stats);
948 if (newstats == NULL) {
949 kfree(basechain);
950 return -ENOMEM;
951 }
952 rcu_assign_pointer(basechain->stats, newstats);
953 }
954
937 basechain->type = type; 955 basechain->type = type;
938 chain = &basechain->chain; 956 chain = &basechain->chain;
939 957
@@ -953,25 +971,6 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
953 971
954 chain->flags |= NFT_BASE_CHAIN; 972 chain->flags |= NFT_BASE_CHAIN;
955 basechain->policy = policy; 973 basechain->policy = policy;
956
957 if (nla[NFTA_CHAIN_COUNTERS]) {
958 err = nf_tables_counters(basechain,
959 nla[NFTA_CHAIN_COUNTERS]);
960 if (err < 0) {
961 free_percpu(basechain->stats);
962 kfree(basechain);
963 return err;
964 }
965 } else {
966 struct nft_stats __percpu *newstats;
967
968 newstats = alloc_percpu(struct nft_stats);
969 if (newstats == NULL)
970 return -ENOMEM;
971
972 rcu_assign_pointer(nft_base_chain(chain)->stats,
973 newstats);
974 }
975 } else { 974 } else {
976 chain = kzalloc(sizeof(*chain), GFP_KERNEL); 975 chain = kzalloc(sizeof(*chain), GFP_KERNEL);
977 if (chain == NULL) 976 if (chain == NULL)