From 9b0a7d432b005cb852f8a013911b386d66935b93 Mon Sep 17 00:00:00 2001 From: claudio Date: Tue, 15 Mar 2022 11:13:48 +0000 Subject: [PATCH] Change how $macros are expanded in the config. Expand $macros not only at the start of a yacc token but also inside STRING elements. STRING elements are used e.g. for community specifications and it makes sense to allow $FOO:$BAR to correctly expand. There is no expansion of macros in quoted strings (both single and double quotes). Factor out the macro expand logic and with this introduce its own lookup buffer for the macro name. For expansion to work inside STRING the char after the makro name must be a character not allowed in macro names (not alpha-numerical or '_'). Add extra checks to set variables. Mainly restrict length of the name and also make sure it does not include not allowed characters. OK tb@ --- usr.sbin/bgpd/parse.y | 108 ++++++++++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 40 deletions(-) diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index f27c7a5d429..e6d8351acd2 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.422 2022/02/23 11:20:35 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.423 2022/03/15 11:13:48 claudio Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer @@ -48,6 +48,8 @@ #include "rde.h" #include "log.h" +#define MACRO_NAME_LEN 128 + TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; @@ -74,6 +76,7 @@ int igetc(void); int lgetc(int); void lungetc(int); int findeol(void); +int expand_macro(void); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { @@ -380,17 +383,25 @@ yesno : STRING { varset : STRING '=' string { char *s = $1; + if (strlen($1) >= MACRO_NAME_LEN) { + yyerror("macro name to long, max %d characters", + MACRO_NAME_LEN - 1); + free($1); + free($3); + YYERROR; + } + do { + if (isalnum((unsigned char)*s) || *s == '_') + continue; + yyerror("macro name can only contain " + "alphanumerics and '_'"); + free($1); + free($3); + YYERROR; + } while (*++s); + if (cmd_opts & BGPD_OPT_VERBOSE) printf("%s = \"%s\"\n", $1, $3); - while (*s++) { - if (isspace((unsigned char)*s)) { - yyerror("macro name cannot contain " - "whitespace"); - free($1); - free($3); - YYERROR; - } - } if (symset($1, $3, 0) == -1) fatal("cannot store variable"); free($1); @@ -3168,11 +3179,47 @@ findeol(void) return (ERROR); } +int +expand_macro(void) +{ + char buf[MACRO_NAME_LEN]; + char *p, *val; + int c; + + p = buf; + while (1) { + if ((c = lgetc('$')) == EOF) + return (ERROR); + if (p + 1 >= buf + sizeof(buf) - 1) { + yyerror("macro name too long"); + return (ERROR); + } + if (isalnum(c) || c == '_') { + *p++ = c; + continue; + } + *p = '\0'; + lungetc(c); + break; + } + val = symget(buf); + if (val == NULL) + yyerror("macro '%s' not defined", buf); + p = val + strlen(val) - 1; + lungetc(DONE_EXPAND); + while (p >= val) { + lungetc((unsigned char)*p); + p--; + } + lungetc(START_EXPAND); + return (0); +} + int yylex(void) { char buf[8096]; - char *p, *val; + char *p; int quotec, next, c; int token; @@ -3186,34 +3233,9 @@ top: while ((c = lgetc(0)) != '\n' && c != EOF) ; /* nothing */ if (c == '$' && !expanding) { - while (1) { - if ((c = lgetc(0)) == EOF) - return (0); - - if (p + 1 >= buf + sizeof(buf) - 1) { - yyerror("string too long"); - return (findeol()); - } - if (isalnum(c) || c == '_') { - *p++ = c; - continue; - } - *p = '\0'; - lungetc(c); - break; - } - val = symget(buf); - if (val == NULL) { - yyerror("macro '%s' not defined", buf); - return (findeol()); - } - p = val + strlen(val) - 1; - lungetc(DONE_EXPAND); - while (p >= val) { - lungetc((unsigned char)*p); - p--; - } - lungetc(START_EXPAND); + c = expand_macro(); + if (c != 0) + return (c); goto top; } @@ -3321,7 +3343,13 @@ nodigits: if (isalnum(c) || c == ':' || c == '_' || c == '*') { do { - *p++ = c; + if (c == '$' && !expanding) { + c = expand_macro(); + if (c != 0) + return (c); + } else + *p++ = c; + if ((size_t)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); -- 2.20.1