diff options
author | Patrick McHardy <kaber@trash.net> | 2014-01-09 13:42:32 -0500 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2014-01-09 14:17:13 -0500 |
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 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) |