]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
netfilter: nf_tables: reject loops from set element jump to chain
authorPablo Neira Ayuso <pablo@netfilter.org>
Sat, 11 Jun 2016 04:20:27 +0000 (12:20 +0800)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 15 Jun 2016 10:17:23 +0000 (12:17 +0200)
Liping Zhang says:

"Users may add such a wrong nft rules successfully, which will cause an
endless jump loop:

  # nft add rule filter test tcp dport vmap {1: jump test}

This is because before we commit, the element in the current anonymous
set is inactive, so osp->walk will skip this element and miss the
validate check."

To resolve this problem, this patch passes the generation mask to the
walk function through the iter container structure depending on the code
path:

1) If we're dumping the elements, then we have to check if the element
   is active in the current generation. Thus, we check for the current
   bit in the genmask.

2) If we're checking for loops, then we have to check if the element is
   active in the next generation, as we're in the middle of a
   transaction. Thus, we check for the next bit in the genmask.

Based on original patch from Liping Zhang.

Reported-by: Liping Zhang <liping.zhang@spreadtrum.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Tested-by: Liping Zhang <liping.zhang@spreadtrum.com>
include/net/netfilter/nf_tables.h
net/netfilter/nf_tables_api.c
net/netfilter/nft_hash.c
net/netfilter/nft_rbtree.c

index 092235458691fd5eadc09cab3266d100f7140dc6..f7c291ff4074510333888184b3b481c77eefc546 100644 (file)
@@ -167,6 +167,7 @@ struct nft_set_elem {
 
 struct nft_set;
 struct nft_set_iter {
+       u8              genmask;
        unsigned int    count;
        unsigned int    skip;
        int             err;
index 492f6f8efdda308d13b625179ad0a73741345f21..0fd69988f00b0759aadb5a20a84b1da4f0fcb8d2 100644 (file)
@@ -2951,6 +2951,7 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
                                goto bind;
                }
 
+               iter.genmask    = nft_genmask_next(ctx->net);
                iter.skip       = 0;
                iter.count      = 0;
                iter.err        = 0;
@@ -3192,12 +3193,13 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
        if (nest == NULL)
                goto nla_put_failure;
 
-       args.cb         = cb;
-       args.skb        = skb;
-       args.iter.skip  = cb->args[0];
-       args.iter.count = 0;
-       args.iter.err   = 0;
-       args.iter.fn    = nf_tables_dump_setelem;
+       args.cb                 = cb;
+       args.skb                = skb;
+       args.iter.genmask       = nft_genmask_cur(ctx.net);
+       args.iter.skip          = cb->args[0];
+       args.iter.count         = 0;
+       args.iter.err           = 0;
+       args.iter.fn            = nf_tables_dump_setelem;
        set->ops->walk(&ctx, set, &args.iter);
 
        nla_nest_end(skb, nest);
@@ -4284,6 +4286,7 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
                            binding->chain != chain)
                                continue;
 
+                       iter.genmask    = nft_genmask_next(ctx->net);
                        iter.skip       = 0;
                        iter.count      = 0;
                        iter.err        = 0;
index 6fa016564f90cbf821a4ae45ac580b2e4e7c43ec..f39c53a159eba6cbe9586599b04147e8247d9523 100644 (file)
@@ -189,7 +189,6 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
        struct nft_hash_elem *he;
        struct rhashtable_iter hti;
        struct nft_set_elem elem;
-       u8 genmask = nft_genmask_cur(read_pnet(&set->pnet));
        int err;
 
        err = rhashtable_walk_init(&priv->ht, &hti, GFP_KERNEL);
@@ -218,7 +217,7 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
                        goto cont;
                if (nft_set_elem_expired(&he->ext))
                        goto cont;
-               if (!nft_set_elem_active(&he->ext, genmask))
+               if (!nft_set_elem_active(&he->ext, iter->genmask))
                        goto cont;
 
                elem.priv = he;
index f762094af7c1ca7e7684448381e7e49ee430045e..7201d57b5a932ebbb8d7fe72c691d5e69ff99784 100644 (file)
@@ -211,7 +211,6 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,
        struct nft_rbtree_elem *rbe;
        struct nft_set_elem elem;
        struct rb_node *node;
-       u8 genmask = nft_genmask_cur(read_pnet(&set->pnet));
 
        spin_lock_bh(&nft_rbtree_lock);
        for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) {
@@ -219,7 +218,7 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,
 
                if (iter->count < iter->skip)
                        goto cont;
-               if (!nft_set_elem_active(&rbe->ext, genmask))
+               if (!nft_set_elem_active(&rbe->ext, iter->genmask))
                        goto cont;
 
                elem.priv = rbe;