]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
parser_bison: fix ct scope underflow if ct helper section is duplicated
authorFlorian Westphal <fw@strlen.de>
Tue, 12 Dec 2023 09:22:58 +0000 (10:22 +0100)
committerFlorian Westphal <fw@strlen.de>
Tue, 12 Dec 2023 15:33:48 +0000 (16:33 +0100)
table inet filter {
ct helper sip-5060u {
type "sip" protocol udp
l3proto ip
}5060t {
type "sip" protocol tcp
l3pownerip
}

Will close the 'ct' scope twice, it has to be closed AFTER the separator
has been parsed.

While not strictly needed, also error out if the protocol is already
given, this provides a better error description.

Also make sure we release the string in all error branches.

Signed-off-by: Florian Westphal <fw@strlen.de>
src/parser_bison.y
tests/shell/testcases/bogons/nft-f/ct_helper_yystate_underflow [new file with mode: 0644]

index d13fb961eaf966a22f6f5882248ec5958473b426..ce80bcd917c311fa7cf66523c9bcb83aeb4e8937 100644 (file)
@@ -1971,7 +1971,7 @@ table_block               :       /* empty */     { $$ = $<table>-1; }
                                list_add_tail(&$4->list, &$1->objs);
                                $$ = $1;
                        }
-                       |       table_block     CT      HELPER  obj_identifier  obj_block_alloc '{'     ct_helper_block     '}' close_scope_ct stmt_separator
+                       |       table_block     CT      HELPER  obj_identifier  obj_block_alloc '{'     ct_helper_block     '}' stmt_separator close_scope_ct
                        {
                                $5->location = @4;
                                $5->type = NFT_OBJECT_CT_HELPER;
@@ -1980,7 +1980,7 @@ table_block               :       /* empty */     { $$ = $<table>-1; }
                                list_add_tail(&$5->list, &$1->objs);
                                $$ = $1;
                        }
-                       |       table_block     CT      TIMEOUT obj_identifier obj_block_alloc '{'      ct_timeout_block        '}' close_scope_ct stmt_separator
+                       |       table_block     CT      TIMEOUT obj_identifier obj_block_alloc '{'      ct_timeout_block        '}' stmt_separator close_scope_ct
                        {
                                $5->location = @4;
                                $5->type = NFT_OBJECT_CT_TIMEOUT;
@@ -1989,7 +1989,7 @@ table_block               :       /* empty */     { $$ = $<table>-1; }
                                list_add_tail(&$5->list, &$1->objs);
                                $$ = $1;
                        }
-                       |       table_block     CT      EXPECTATION obj_identifier obj_block_alloc '{'  ct_expect_block '}' close_scope_ct stmt_separator
+                       |       table_block     CT      EXPECTATION obj_identifier obj_block_alloc '{'  ct_expect_block '}' stmt_separator close_scope_ct
                        {
                                $5->location = @4;
                                $5->type = NFT_OBJECT_CT_EXPECT;
@@ -4827,16 +4827,23 @@ ct_l4protoname          :       TCP     close_scope_tcp { $$ = IPPROTO_TCP; }
                        |       UDP     close_scope_udp { $$ = IPPROTO_UDP; }
                        ;
 
-ct_helper_config               :       TYPE    QUOTED_STRING   PROTOCOL        ct_l4protoname  stmt_separator  close_scope_type
+ct_helper_config       :       TYPE    QUOTED_STRING   PROTOCOL        ct_l4protoname  stmt_separator  close_scope_type
                        {
                                struct ct_helper *ct;
                                int ret;
 
                                ct = &$<obj>0->ct_helper;
 
+                               if (ct->l4proto) {
+                                       erec_queue(error(&@2, "You can only specify this once. This statement is already set for %s.", ct->name), state->msgs);
+                                       free_const($2);
+                                       YYERROR;
+                               }
+
                                ret = snprintf(ct->name, sizeof(ct->name), "%s", $2);
                                if (ret <= 0 || ret >= (int)sizeof(ct->name)) {
                                        erec_queue(error(&@2, "invalid name '%s', max length is %u\n", $2, (int)sizeof(ct->name)), state->msgs);
+                                       free_const($2);
                                        YYERROR;
                                }
                                free_const($2);
diff --git a/tests/shell/testcases/bogons/nft-f/ct_helper_yystate_underflow b/tests/shell/testcases/bogons/nft-f/ct_helper_yystate_underflow
new file mode 100644 (file)
index 0000000..18eb25e
--- /dev/null
@@ -0,0 +1,14 @@
+table inet filter {
+       ct helper sip-5060u {
+               type "sip" protocol udp
+               l3proto ip
+       }5060t {
+               type "sip" protocol tcp
+               l3pownerip
+       }
+
+       chain input {
+               type filtol/dev/stdinok input priority f)lser; policy accept;
+               ct helper set ip protocol . th dport map { udp . 1-20000 : "si60u", tcp . 10000-20000 : "sip-5060t" }
+       }
+}