From patchwork Tue Jun 5 14:30:49 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Fabian X-Patchwork-Id: 925509 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=bosson.cz Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=bosson.cz header.i=@bosson.cz header.b="OaV9NF5T"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 410ZD574DJz9s0W for ; Wed, 6 Jun 2018 00:38:13 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752485AbeFEOiK (ORCPT ); Tue, 5 Jun 2018 10:38:10 -0400 Received: from mailalternative.uvtmail.cz ([109.205.75.52]:36160 "EHLO mail.hosting.cldn.cz" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752486AbeFEOiF (ORCPT ); Tue, 5 Jun 2018 10:38:05 -0400 Received: from linux.local (linux.uvt.cz [178.17.1.67]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: fabian@bosson.cz) by mail.hosting.cldn.cz (Postfix) with ESMTPSA id CD61127D55 for ; Tue, 5 Jun 2018 16:31:24 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bosson.cz; s=mail; t=1528209085; bh=8JyRWgElBWf9fzb4K8OMxs14+STjhew6IawcZZa3eFY=; h=From:To:Subject:Date:In-Reply-To:References; b=OaV9NF5Te+VQj9Fbi2aNU4fXyPe4a3g8UKGPZepLwSNyTYXGRAWVNsb0Ue1+e4up8 7wZWjE27TmdSLFoPoyjybyF87SH22GtSWE1FfjJrOkfUkxrBMnDe+ZSCyrFAgGq7u0 jzqAdW5n3DQqOyS1VRnbiYxGyeHTRaDm2+q06lM+uRva99SBN3SpFbjjtMCdWQNgIc XUkacmhxsEAw+sv9TWVOHZT4gVCMxv5Zxrfqbd/p+FmhlRlXYaUXHLML7zGVipM8vj 08Q1dtt5QGO6Cohl1F/7DMnnSL06UD9pcjZru9aeTLj6acG+O1LLphqUsmiTpeiqv6 N301xf5pFtupg== From: David Fabian To: netfilter-devel@vger.kernel.org Subject: [PATCH v2 2/4] Added support for global variable definitions. Date: Tue, 5 Jun 2018 16:30:49 +0200 Message-Id: <20180605143051.19274-3-david.fabian@bosson.cz> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180605143051.19274-1-david.fabian@bosson.cz> References: <20180605143051.19274-1-david.fabian@bosson.cz> Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Global variables live only in the top-level scope and can be accessed from anywhere. They are unloaded at the end of parsing. Global definitions cannot contain local variables because those may get deleted when the local scope goes away and the subsequent use of the global would lead to a SIGSEGV. --- include/rule.h | 5 +- src/parser_bison.y | 335 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/rule.c | 15 ++- src/scanner.l | 1 + 4 files changed, 347 insertions(+), 9 deletions(-) mode change 100644 => 100755 src/parser_bison.y mode change 100644 => 100755 src/scanner.l diff --git a/include/rule.h b/include/rule.h index cfecf7f..8991025 100644 --- a/include/rule.h +++ b/include/rule.h @@ -109,8 +109,9 @@ extern void symbol_bind(struct scope *scope, const char *identifier, struct expr *expr); extern int symbol_unbind(const struct scope *scope, const char *identifier); extern struct symbol *symbol_lookup(const struct scope *scope, - const char *identifier); -struct symbol *symbol_get(const struct scope *scope, const char *identifier); + const char *identifier, int *global); +struct symbol *symbol_get(const struct scope *scope, const char *identifier, + int *global); enum table_flags { TABLE_F_DORMANT = (1 << 0), diff --git a/src/parser_bison.y b/src/parser_bison.y old mode 100644 new mode 100755 index 16a1f75..4500aac --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -62,6 +62,11 @@ static void yyerror(struct location *loc, struct nft_ctx *nft, void *scanner, erec_queue(error(loc, "%s", s), state->msgs); } +static struct scope *toplevel_scope(const struct parser_state *state) +{ + return state->scopes[0]; +} + struct scope *current_scope(const struct parser_state *state) { return state->scopes[state->scope]; @@ -192,6 +197,7 @@ int nft_lex(void *, void *, void *); %token DEFINE "define" %token REDEFINE "redefine" %token UNDEFINE "undefine" +%token GLOBAL "global" %token FIB "fib" @@ -739,6 +745,18 @@ int nft_lex(void *, void *, void *); %type ct_l4protoname ct_obj_type +%type global_list_rhs_expr global_rhs_expr global_variable_expr global_basic_rhs_expr global_primary_rhs_expr global_symbol_expr +%destructor { expr_free($$); } global_list_rhs_expr global_rhs_expr global_variable_expr global_basic_rhs_expr global_primary_rhs_expr global_symbol_expr + +%type global_set_lhs_expr global_set_rhs_expr global_shift_rhs_expr global_and_rhs_expr global_exclusive_or_rhs_expr global_inclusive_or_rhs_expr +%destructor { expr_free($$); } global_set_lhs_expr global_set_rhs_expr global_shift_rhs_expr global_and_rhs_expr global_exclusive_or_rhs_expr global_inclusive_or_rhs_expr + +%type global_concat_rhs_expr global_prefix_rhs_expr global_initializer_expr +%destructor { expr_free($$); } global_concat_rhs_expr global_prefix_rhs_expr global_initializer_expr + +%type global_range_rhs_expr global_set_list_expr global_set_list_member_expr global_set_elem_expr_alloc global_set_expr global_set_elem_expr global_multiton_rhs_expr +%destructor { expr_free($$); } global_range_rhs_expr global_set_list_expr global_set_list_member_expr global_set_elem_expr_alloc global_set_expr global_set_elem_expr global_multiton_rhs_expr + %% input : /* empty */ @@ -780,7 +798,7 @@ common_block : INCLUDE QUOTED_STRING stmt_separator { struct scope *scope = current_scope(state); - if (symbol_lookup(scope, $2) != NULL) { + if (symbol_lookup(scope, $2, NULL) != NULL) { erec_queue(error(&@2, "redefinition of symbol '%s'", $2), state->msgs); xfree($2); @@ -807,8 +825,43 @@ common_block : INCLUDE QUOTED_STRING stmt_separator state->msgs); YYERROR; } + xfree($2); } + | GLOBAL DEFINE identifier '=' global_initializer_expr stmt_separator + { + struct scope *scope = toplevel_scope(state); + + if (symbol_lookup(scope, $3, NULL) != NULL) { + erec_queue(error(&@2, "redefinition of global symbol '%s'", $3), + state->msgs); + xfree($3); + expr_free($5); + YYERROR; + } + + symbol_bind(scope, $3, $5); + xfree($3); + } + | GLOBAL REDEFINE identifier '=' global_initializer_expr stmt_separator + { + struct scope *scope = toplevel_scope(state); + + symbol_bind(scope, $3, $5); + xfree($3); + } + | GLOBAL UNDEFINE identifier stmt_separator + { + struct scope *scope = toplevel_scope(state); + + if (symbol_unbind(scope, $3) < 0) { + erec_queue(error(&@2, "undefined global symbol '%s'", $3), + state->msgs); + YYERROR; + } + + xfree($3); + } | error stmt_separator { if (++state->nerrs == nft->parser_max_errors) @@ -2823,8 +2876,9 @@ variable_expr : '$' identifier { struct scope *scope = current_scope(state); struct symbol *sym; + int global; - sym = symbol_get(scope, $2); + sym = symbol_get(scope, $2, &global); if (!sym) { erec_queue(error(&@2, "unknown identifier '%s'", $2), state->msgs); @@ -2832,7 +2886,13 @@ variable_expr : '$' identifier YYERROR; } - $$ = variable_expr_alloc(&@$, scope, sym); + if (global) + /* global variables can only access top-level scope + this prevents SIGSEGVs when the local scope in which + the global is used has been freed */ + $$ = variable_expr_alloc(&@$, toplevel_scope(state), sym); + else + $$ = variable_expr_alloc(&@$, scope, sym); xfree($2); } ; @@ -4093,4 +4153,273 @@ exthdr_key : HBH { $$ = IPPROTO_HOPOPTS; } | MH { $$ = IPPROTO_MH; } ; +global_initializer_expr : global_rhs_expr + | global_list_rhs_expr + ; + +global_list_rhs_expr : global_basic_rhs_expr COMMA global_basic_rhs_expr + { + $$ = list_expr_alloc(&@$); + compound_expr_add($$, $1); + compound_expr_add($$, $3); + } + | global_list_rhs_expr COMMA global_basic_rhs_expr + { + $1->location = @$; + compound_expr_add($1, $3); + $$ = $1; + } + ; + +global_rhs_expr : global_concat_rhs_expr { $$ = $1; } + | global_multiton_rhs_expr { $$ = $1; } + | global_set_expr { $$ = $1; } + ; + +global_variable_expr : '$' identifier + { + struct scope *scope = toplevel_scope(state); + struct symbol *sym; + + sym = symbol_get(scope, $2, NULL); + if (!sym) { + scope = current_scope(state); + if (symbol_lookup(scope, $2, NULL) != NULL) { + erec_queue(error(&@2, "local variable '%s' not allowed in global definition", $2), + state->msgs); + } else { + erec_queue(error(&@2, "unknown identifier '%s'", $2), + state->msgs); + } + xfree($2); + YYERROR; + } + $$ = variable_expr_alloc(&@$, scope, sym); + xfree($2); + } + ; + +global_symbol_expr : global_variable_expr + | string + { + $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE, + toplevel_scope(state), + $1); + xfree($1); + } + | AT identifier + { + $$ = symbol_expr_alloc(&@$, SYMBOL_SET, + toplevel_scope(state), + $2); + xfree($2); + } + ; + +global_primary_rhs_expr : global_symbol_expr { $$ = $1; } + | integer_expr { $$ = $1; } + | boolean_expr { $$ = $1; } + | keyword_expr { $$ = $1; } + | TCP + { + uint8_t data = IPPROTO_TCP; + $$ = constant_expr_alloc(&@$, &inet_protocol_type, + BYTEORDER_HOST_ENDIAN, + sizeof(data) * BITS_PER_BYTE, &data); + } + | UDP + { + uint8_t data = IPPROTO_UDP; + $$ = constant_expr_alloc(&@$, &inet_protocol_type, + BYTEORDER_HOST_ENDIAN, + sizeof(data) * BITS_PER_BYTE, &data); + } + | UDPLITE + { + uint8_t data = IPPROTO_UDPLITE; + $$ = constant_expr_alloc(&@$, &inet_protocol_type, + BYTEORDER_HOST_ENDIAN, + sizeof(data) * BITS_PER_BYTE, &data); + } + | ESP + { + uint8_t data = IPPROTO_ESP; + $$ = constant_expr_alloc(&@$, &inet_protocol_type, + BYTEORDER_HOST_ENDIAN, + sizeof(data) * BITS_PER_BYTE, &data); + } + | AH + { + uint8_t data = IPPROTO_AH; + $$ = constant_expr_alloc(&@$, &inet_protocol_type, + BYTEORDER_HOST_ENDIAN, + sizeof(data) * BITS_PER_BYTE, &data); + } + | ICMP + { + uint8_t data = IPPROTO_ICMP; + $$ = constant_expr_alloc(&@$, &inet_protocol_type, + BYTEORDER_HOST_ENDIAN, + sizeof(data) * BITS_PER_BYTE, &data); + } + | ICMP6 + { + uint8_t data = IPPROTO_ICMPV6; + $$ = constant_expr_alloc(&@$, &inet_protocol_type, + BYTEORDER_HOST_ENDIAN, + sizeof(data) * BITS_PER_BYTE, &data); + } + | COMP + { + uint8_t data = IPPROTO_COMP; + $$ = constant_expr_alloc(&@$, &inet_protocol_type, + BYTEORDER_HOST_ENDIAN, + sizeof(data) * BITS_PER_BYTE, &data); + } + | DCCP + { + uint8_t data = IPPROTO_DCCP; + $$ = constant_expr_alloc(&@$, &inet_protocol_type, + BYTEORDER_HOST_ENDIAN, + sizeof(data) * BITS_PER_BYTE, &data); + } + | SCTP + { + uint8_t data = IPPROTO_SCTP; + $$ = constant_expr_alloc(&@$, &inet_protocol_type, + BYTEORDER_HOST_ENDIAN, + sizeof(data) * BITS_PER_BYTE, &data); + } + | REDIRECT + { + uint8_t data = ICMP_REDIRECT; + $$ = constant_expr_alloc(&@$, &icmp_type_type, + BYTEORDER_HOST_ENDIAN, + sizeof(data) * BITS_PER_BYTE, &data); + } + ; + +global_shift_rhs_expr : global_primary_rhs_expr + | global_shift_rhs_expr LSHIFT global_primary_rhs_expr + { + $$ = binop_expr_alloc(&@$, OP_LSHIFT, $1, $3); + } + | global_shift_rhs_expr RSHIFT global_primary_rhs_expr + { + $$ = binop_expr_alloc(&@$, OP_RSHIFT, $1, $3); + } + ; + +global_and_rhs_expr : global_shift_rhs_expr + | global_and_rhs_expr AMPERSAND global_shift_rhs_expr + { + $$ = binop_expr_alloc(&@$, OP_AND, $1, $3); + } + ; + +global_exclusive_or_rhs_expr : global_and_rhs_expr + | global_exclusive_or_rhs_expr CARET global_and_rhs_expr + { + $$ = binop_expr_alloc(&@$, OP_XOR, $1, $3); + } + ; + +global_inclusive_or_rhs_expr : global_exclusive_or_rhs_expr + | global_inclusive_or_rhs_expr '|' global_exclusive_or_rhs_expr + { + $$ = binop_expr_alloc(&@$, OP_OR, $1, $3); + } + ; + +global_basic_rhs_expr : global_inclusive_or_rhs_expr + ; + +global_concat_rhs_expr : global_basic_rhs_expr + | global_concat_rhs_expr DOT global_basic_rhs_expr + { + if ($$->ops->type != EXPR_CONCAT) { + $$ = concat_expr_alloc(&@$); + compound_expr_add($$, $1); + } else { + struct location rhs[] = { + [1] = @2, + [2] = @3, + }; + location_update(&$3->location, rhs, 2); + + $$ = $1; + $$->location = @$; + } + compound_expr_add($$, $3); + } + ; + +global_prefix_rhs_expr : global_basic_rhs_expr SLASH NUM + { + $$ = prefix_expr_alloc(&@$, $1, $3); + } + ; + +global_range_rhs_expr : global_basic_rhs_expr DASH global_basic_rhs_expr + { + $$ = range_expr_alloc(&@$, $1, $3); + } + ; + +global_multiton_rhs_expr : global_prefix_rhs_expr + | global_range_rhs_expr + | wildcard_expr + ; + +global_set_list_expr : global_set_list_member_expr + { + $$ = set_expr_alloc(&@$, NULL); + compound_expr_add($$, $1); + } + | global_set_list_expr COMMA global_set_list_member_expr + { + compound_expr_add($1, $3); + $$ = $1; + } + | global_set_list_expr COMMA opt_newline + ; + +global_set_list_member_expr : opt_newline global_set_expr opt_newline + { + $$ = $2; + } + | opt_newline global_set_elem_expr opt_newline + { + $$ = $2; + } + | opt_newline global_set_elem_expr COLON global_set_rhs_expr opt_newline + { + $$ = mapping_expr_alloc(&@$, $2, $4); + } + ; + +global_set_lhs_expr : global_concat_rhs_expr + | global_multiton_rhs_expr + ; + +global_set_rhs_expr : global_concat_rhs_expr + | verdict_expr + ; + +global_set_elem_expr : global_set_elem_expr_alloc + | global_set_elem_expr_alloc set_elem_options + ; + +global_set_elem_expr_alloc : global_set_lhs_expr + { + $$ = set_elem_expr_alloc(&@1, $1); + } + ; + +global_set_expr : '{' global_set_list_expr '}' + { + $2->location = @$; + $$ = $2; + } + ; %% diff --git a/src/rule.c b/src/rule.c index 38529af..d40ec50 100644 --- a/src/rule.c +++ b/src/rule.c @@ -526,11 +526,12 @@ void symbol_bind(struct scope *scope, const char *identifier, struct expr *expr) list_add(&sym->list, &scope->symbols); } -struct symbol *symbol_get(const struct scope *scope, const char *identifier) +struct symbol *symbol_get(const struct scope *scope, const char *identifier, + int *global) { struct symbol *sym; - sym = symbol_lookup(scope, identifier); + sym = symbol_lookup(scope, identifier, global); if (!sym) return NULL; @@ -566,14 +567,20 @@ int symbol_unbind(const struct scope *scope, const char *identifier) return 0; } -struct symbol *symbol_lookup(const struct scope *scope, const char *identifier) +struct symbol *symbol_lookup(const struct scope *scope, const char *identifier, + int *global) { struct symbol *sym; + if (global) + *global = 0; while (scope != NULL) { list_for_each_entry(sym, &scope->symbols, list) { - if (!strcmp(sym->identifier, identifier)) + if (!strcmp(sym->identifier, identifier)) { + if (global && scope->parent == NULL) + *global = 1; return sym; + } } scope = scope->parent; } diff --git a/src/scanner.l b/src/scanner.l old mode 100644 new mode 100755 index e6e255d..96bb307 --- a/src/scanner.l +++ b/src/scanner.l @@ -236,6 +236,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "define" { return DEFINE; } "redefine" { return REDEFINE; } "undefine" { return UNDEFINE; } +"global" { return GLOBAL; } "describe" { return DESCRIBE; }