aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2015-04-05 08:41:06 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2015-04-08 10:58:27 -0400
commit3dd0673ac3cd7d05cde103396ec7ec410a901de2 (patch)
tree4daf53c5aef7eade635652cd37c023fbd4e75bc1 /net
parent4a8678efbec6b0ea46baafb77cd297e6e02da933 (diff)
netfilter: nf_tables: prepare set element accounting for async updates
Use atomic operations for the element count to avoid races with async updates. To properly handle the transactional semantics during netlink updates, deleted but not yet committed elements are accounted for seperately and are treated as being already removed. This means for the duration of a netlink transaction, the limit might be exceeded by the amount of elements deleted. Set implementations must be prepared to handle this. 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.c21
-rw-r--r--net/netfilter/nft_hash.c3
2 files changed, 14 insertions, 10 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 0dab872e821b..27d1bf55a581 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -3238,9 +3238,6 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
3238 u32 flags; 3238 u32 flags;
3239 int err; 3239 int err;
3240 3240
3241 if (set->size && set->nelems == set->size)
3242 return -ENFILE;
3243
3244 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr, 3241 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
3245 nft_set_elem_policy); 3242 nft_set_elem_policy);
3246 if (err < 0) 3243 if (err < 0)
@@ -3391,11 +3388,15 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
3391 return -EBUSY; 3388 return -EBUSY;
3392 3389
3393 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { 3390 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
3391 if (set->size &&
3392 !atomic_add_unless(&set->nelems, 1, set->size + set->ndeact))
3393 return -ENFILE;
3394
3394 err = nft_add_set_elem(&ctx, set, attr); 3395 err = nft_add_set_elem(&ctx, set, attr);
3395 if (err < 0) 3396 if (err < 0) {
3397 atomic_dec(&set->nelems);
3396 break; 3398 break;
3397 3399 }
3398 set->nelems++;
3399 } 3400 }
3400 return err; 3401 return err;
3401} 3402}
@@ -3477,7 +3478,7 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
3477 if (err < 0) 3478 if (err < 0)
3478 break; 3479 break;
3479 3480
3480 set->nelems--; 3481 set->ndeact++;
3481 } 3482 }
3482 return err; 3483 return err;
3483} 3484}
@@ -3810,6 +3811,8 @@ static int nf_tables_commit(struct sk_buff *skb)
3810 &te->elem, 3811 &te->elem,
3811 NFT_MSG_DELSETELEM, 0); 3812 NFT_MSG_DELSETELEM, 0);
3812 te->set->ops->remove(te->set, &te->elem); 3813 te->set->ops->remove(te->set, &te->elem);
3814 atomic_dec(&te->set->nelems);
3815 te->set->ndeact--;
3813 break; 3816 break;
3814 } 3817 }
3815 } 3818 }
@@ -3913,16 +3916,16 @@ static int nf_tables_abort(struct sk_buff *skb)
3913 nft_trans_destroy(trans); 3916 nft_trans_destroy(trans);
3914 break; 3917 break;
3915 case NFT_MSG_NEWSETELEM: 3918 case NFT_MSG_NEWSETELEM:
3916 nft_trans_elem_set(trans)->nelems--;
3917 te = (struct nft_trans_elem *)trans->data; 3919 te = (struct nft_trans_elem *)trans->data;
3918 3920
3919 te->set->ops->remove(te->set, &te->elem); 3921 te->set->ops->remove(te->set, &te->elem);
3922 atomic_dec(&te->set->nelems);
3920 break; 3923 break;
3921 case NFT_MSG_DELSETELEM: 3924 case NFT_MSG_DELSETELEM:
3922 te = (struct nft_trans_elem *)trans->data; 3925 te = (struct nft_trans_elem *)trans->data;
3923 3926
3924 nft_trans_elem_set(trans)->nelems++;
3925 te->set->ops->activate(te->set, &te->elem); 3927 te->set->ops->activate(te->set, &te->elem);
3928 te->set->ndeact--;
3926 3929
3927 nft_trans_destroy(trans); 3930 nft_trans_destroy(trans);
3928 break; 3931 break;
diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c
index 5923ec547268..c74e2bf1a1e4 100644
--- a/net/netfilter/nft_hash.c
+++ b/net/netfilter/nft_hash.c
@@ -203,7 +203,7 @@ out:
203 203
204static void nft_hash_gc(struct work_struct *work) 204static void nft_hash_gc(struct work_struct *work)
205{ 205{
206 const struct nft_set *set; 206 struct nft_set *set;
207 struct nft_hash_elem *he; 207 struct nft_hash_elem *he;
208 struct nft_hash *priv; 208 struct nft_hash *priv;
209 struct nft_set_gc_batch *gcb = NULL; 209 struct nft_set_gc_batch *gcb = NULL;
@@ -237,6 +237,7 @@ static void nft_hash_gc(struct work_struct *work)
237 if (gcb == NULL) 237 if (gcb == NULL)
238 goto out; 238 goto out;
239 rhashtable_remove_fast(&priv->ht, &he->node, nft_hash_params); 239 rhashtable_remove_fast(&priv->ht, &he->node, nft_hash_params);
240 atomic_dec(&set->nelems);
240 nft_set_gc_batch_add(gcb, he); 241 nft_set_gc_batch_add(gcb, he);
241 } 242 }
242out: 243out: