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 | |
| 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')
| -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) |
