netfilter: nf_tables: uninitialize element key/data from the commit path
authorPablo Neira Ayuso <pablo@netfilter.org>
Fri, 1 Aug 2014 17:32:41 +0000 (19:32 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 8 Aug 2014 13:38:46 +0000 (15:38 +0200)
This should happen once the element has been effectively released in
the commit path, not before. This fixes a possible chain refcount leak
if the transaction is aborted.

Reported-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nf_tables_api.c

index b8035c2..c6f9d3d 100644 (file)
@@ -3139,11 +3139,6 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
 
        nft_trans_elem(trans) = elem;
        list_add_tail(&trans->list, &ctx->net->nft.commit_list);
-
-       nft_data_uninit(&elem.key, NFT_DATA_VALUE);
-       if (set->flags & NFT_SET_MAP)
-               nft_data_uninit(&elem.data, set->dtype);
-
        return 0;
 err2:
        nft_data_uninit(&elem.key, desc.type);
@@ -3310,7 +3305,7 @@ static int nf_tables_commit(struct sk_buff *skb)
 {
        struct net *net = sock_net(skb->sk);
        struct nft_trans *trans, *next;
-       struct nft_set *set;
+       struct nft_trans_elem *te;
 
        /* Bump generation counter, invalidate any dump in progress */
        while (++net->nft.base_seq == 0);
@@ -3396,13 +3391,17 @@ static int nf_tables_commit(struct sk_buff *skb)
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_DELSETELEM:
-                       nf_tables_setelem_notify(&trans->ctx,
-                                                nft_trans_elem_set(trans),
-                                                &nft_trans_elem(trans),
+                       te = (struct nft_trans_elem *)trans->data;
+                       nf_tables_setelem_notify(&trans->ctx, te->set,
+                                                &te->elem,
                                                 NFT_MSG_DELSETELEM, 0);
-                       set = nft_trans_elem_set(trans);
-                       set->ops->get(set, &nft_trans_elem(trans));
-                       set->ops->remove(set, &nft_trans_elem(trans));
+                       te->set->ops->get(te->set, &te->elem);
+                       te->set->ops->remove(te->set, &te->elem);
+                       nft_data_uninit(&te->elem.key, NFT_DATA_VALUE);
+                       if (te->elem.flags & NFT_SET_MAP) {
+                               nft_data_uninit(&te->elem.data,
+                                               te->set->dtype);
+                       }
                        nft_trans_destroy(trans);
                        break;
                }