]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
evaluate: reject tunnel section if another one is already present
authorFlorian Westphal <fw@strlen.de>
Thu, 16 Oct 2025 14:59:36 +0000 (16:59 +0200)
committerFlorian Westphal <fw@strlen.de>
Fri, 17 Oct 2025 07:41:56 +0000 (09:41 +0200)
Included bogon causes a crash because the list head isn't initialised
due to tunnel->type == VXLAN.

Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de>
src/parser_bison.y
tests/shell/testcases/bogons/nft-f/tunnel_in_tunnel_crash [new file with mode: 0644]

index 4e028d31c165fbb9f0743d15ac318e9f4996a6c5..3c21c7584d01fb296f8a7ddeef7919dd04faec13 100644 (file)
@@ -144,6 +144,19 @@ static bool already_set(const void *attr, const struct location *loc,
        return true;
 }
 
+static bool tunnel_set_type(const struct location *loc,
+                           struct obj *obj, enum tunnel_type type, const char *name,
+                           struct parser_state *state)
+{
+       if (obj->tunnel.type) {
+               erec_queue(error(loc, "Cannot create new %s section inside another tunnel", name), state->msgs);
+               return false;
+       }
+
+       obj->tunnel.type = type;
+       return true;
+}
+
 static struct expr *ifname_expr_alloc(const struct location *location,
                                      struct list_head *queue,
                                      const char *name)
@@ -4980,11 +4993,15 @@ erspan_block            :       /* empty */     { $$ = $<obj>-1; }
 erspan_block_alloc     :       /* empty */
                        {
                                $$ = $<obj>-1;
+
+                               if (!tunnel_set_type(&$$->location, $$, TUNNEL_ERSPAN, "erspan", state))
+                                       YYERROR;
                        }
                        ;
 
 erspan_config          :       HDRVERSION      NUM
                        {
+                               assert($<obj>0->tunnel.type == TUNNEL_ERSPAN);
                                $<obj>0->tunnel.erspan.version = $2;
                        }
                        |       INDEX           NUM
@@ -5017,6 +5034,10 @@ geneve_block             :       /* empty */     { $$ = $<obj>-1; }
 geneve_block_alloc     :       /* empty */
                        {
                                $$ = $<obj>-1;
+                               if (!tunnel_set_type(&$$->location, $$, TUNNEL_GENEVE, "geneve", state))
+                                       YYERROR;
+
+                               init_list_head(&$$->tunnel.geneve_opts);
                        }
                        ;
 
@@ -5024,6 +5045,8 @@ geneve_config             :       CLASS   NUM     OPTTYPE NUM     DATA    string
                        {
                                struct tunnel_geneve *geneve;
 
+                               assert($<obj>0->tunnel.type == TUNNEL_GENEVE);
+
                                geneve = xmalloc(sizeof(struct tunnel_geneve));
                                geneve->geneve_class = $2;
                                geneve->type = $4;
@@ -5034,10 +5057,6 @@ geneve_config            :       CLASS   NUM     OPTTYPE NUM     DATA    string
                                        YYERROR;
                                }
 
-                               if (!$<obj>0->tunnel.type) {
-                                       $<obj>0->tunnel.type = TUNNEL_GENEVE;
-                                       init_list_head(&$<obj>0->tunnel.geneve_opts);
-                               }
                                list_add_tail(&geneve->list, &$<obj>0->tunnel.geneve_opts);
                                free_const($6);
                        }
@@ -5055,11 +5074,15 @@ vxlan_block             :       /* empty */     { $$ = $<obj>-1; }
 vxlan_block_alloc      :       /* empty */
                        {
                                $$ = $<obj>-1;
+
+                               if (!tunnel_set_type(&$$->location, $$, TUNNEL_VXLAN, "vxlan", state))
+                                       YYERROR;
                        }
                        ;
 
 vxlan_config           :       GBP     NUM
                        {
+                               assert($<obj>0->tunnel.type == TUNNEL_VXLAN);
                                $<obj>0->tunnel.vxlan.gbp = $2;
                        }
                        ;
@@ -5123,13 +5146,16 @@ tunnel_config           :       ID      NUM
                        }
                        |       ERSPAN  erspan_block_alloc '{' erspan_block '}'
                        {
-                               $<obj>0->tunnel.type = TUNNEL_ERSPAN;
+                               $2->location = @2;
                        }
                        |       VXLAN   vxlan_block_alloc '{' vxlan_block '}'
                        {
-                               $<obj>0->tunnel.type = TUNNEL_VXLAN;
+                               $2->location = @2;
                        }
                        |       GENEVE  geneve_block_alloc '{' geneve_block '}'
+                       {
+                               $2->location = @2;
+                       }
                        ;
 
 tunnel_block           :       /* empty */     { $$ = $<obj>-1; }
diff --git a/tests/shell/testcases/bogons/nft-f/tunnel_in_tunnel_crash b/tests/shell/testcases/bogons/nft-f/tunnel_in_tunnel_crash
new file mode 100644 (file)
index 0000000..9f02980
--- /dev/null
@@ -0,0 +1,10 @@
+table netdev x {
+       tunnel geneve-t {
+               vxlan {
+                       gbp 200
+               }
+               geneve {
+                       class 0x1 opt-type 0x1 data "0x12345678"
+               }
+       }
+