Hi,

While generating big prefixlists macros with bgpq3 (big like as2914:as-europe-v6
for example), OpenBGPd cannot load the config file (error "string too long").
This diff implements a dynamic buffer to overcome this limitation.

Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
retrieving revision 1.331
diff -u -p -r1.331 parse.y
--- parse.y     27 Aug 2018 19:32:37 -0000      1.331
+++ parse.y     4 Sep 2018 18:13:48 -0000
@@ -2746,13 +2746,22 @@ findeol(void)
        return (ERROR);
 }
 
+#define READBUFFERSIZE 1024
+
 int
 yylex(void)
 {
-       u_char   buf[8096];
+       u_char  *buf = NULL;
        u_char  *p, *val;
        int      quotec, next, c;
        int      token;
+       u_int32_t bufsize = READBUFFERSIZE;
+
+       buf = malloc(bufsize);
+       if (buf == NULL) {
+               yyerror("malloc failed");
+               return (findeol());
+       }
 
 top:
        p = buf;
@@ -2765,12 +2774,19 @@ top:
                        ; /* nothing */
        if (c == '$' && !expanding) {
                while (1) {
-                       if ((c = lgetc(0)) == EOF)
+                       if ((c = lgetc(0)) == EOF) {
+                               free(buf);
                                return (0);
+                       }
 
-                       if (p + 1 >= buf + sizeof(buf) - 1) {
-                               yyerror("string too long");
-                               return (findeol());
+                       if (p + 1 >= buf + bufsize - 1) {
+                               bufsize += READBUFFERSIZE;
+                               buf = realloc(buf, bufsize);
+                               if (buf == NULL) {
+                                       yyerror("realloc failed");
+                                       return (findeol());
+                               }
+                               p = buf + bufsize - READBUFFERSIZE - 2;
                        }
                        if (isalnum(c) || c == '_') {
                                *p++ = c;
@@ -2783,6 +2799,7 @@ top:
                val = symget(buf);
                if (val == NULL) {
                        yyerror("macro '%s' not defined", buf);
+                       free(buf);
                        return (findeol());
                }
                p = val + strlen(val) - 1;
@@ -2800,14 +2817,18 @@ top:
        case '"':
                quotec = c;
                while (1) {
-                       if ((c = lgetc(quotec)) == EOF)
+                       if ((c = lgetc(quotec)) == EOF) {
+                               free(buf);
                                return (0);
+                       }
                        if (c == '\n') {
                                file->lineno++;
                                continue;
                        } else if (c == '\\') {
-                               if ((next = lgetc(quotec)) == EOF)
+                               if ((next = lgetc(quotec)) == EOF) {
+                                       free(buf);
                                        return (0);
+                               }
                                if (next == quotec || c == ' ' || c == '\t')
                                        c = next;
                                else if (next == '\n') {
@@ -2820,36 +2841,52 @@ top:
                                break;
                        } else if (c == '\0') {
                                yyerror("syntax error");
+                               free(buf);
                                return (findeol());
                        }
-                       if (p + 1 >= buf + sizeof(buf) - 1) {
-                               yyerror("string too long");
-                               return (findeol());
+                       if (p + 1 >= buf + bufsize - 1) {
+                               bufsize += READBUFFERSIZE;
+                               buf = realloc(buf, bufsize);
+                               if (buf == NULL) {
+                                       yyerror("realloc failed");
+                                       return (findeol());
+                               }
+                               p = buf + bufsize - READBUFFERSIZE - 2;
                        }
                        *p++ = c;
                }
                yylval.v.string = strdup(buf);
-               if (yylval.v.string == NULL)
+               if (yylval.v.string == NULL) {
+                       free(buf);
                        fatal("yylex: strdup");
+               }
                return (STRING);
        case '!':
                next = lgetc(0);
-               if (next == '=')
+               if (next == '=') {
+                       free(buf);
                        return (NE);
+               }
                lungetc(next);
                break;
        case '<':
                next = lgetc(0);
-               if (next == '=')
+               if (next == '=') {
+                       free(buf);
                        return (LE);
+               }
                lungetc(next);
                break;
        case '>':
                next = lgetc(0);
-               if (next == '<')
+               if (next == '<') {
+                       free(buf);
                        return (XRANGE);
-               else if (next == '=')
+               }
+               else if (next == '=') {
+                       free(buf);
                        return (GE);
+               }
                lungetc(next);
                break;
        }
@@ -2860,9 +2897,14 @@ top:
        if (c == '-' || isdigit(c)) {
                do {
                        *p++ = c;
-                       if ((unsigned)(p-buf) >= sizeof(buf)) {
-                               yyerror("string too long");
-                               return (findeol());
+                       if ((unsigned)(p-buf) >= bufsize) {
+                               bufsize += READBUFFERSIZE;
+                               buf = realloc(buf, bufsize);
+                               if (buf == NULL) {
+                                       yyerror("realloc failed");
+                                       return (findeol());
+                               }
+                               p = buf + bufsize - READBUFFERSIZE;
                        }
                } while ((c = lgetc(0)) != EOF && isdigit(c));
                lungetc(c);
@@ -2877,16 +2919,20 @@ top:
                        if (errstr) {
                                yyerror("\"%s\" invalid number: %s",
                                    buf, errstr);
+                               free(buf);
                                return (findeol());
                        }
+                       free(buf);
                        return (NUMBER);
                } else {
 nodigits:
                        while (p > buf + 1)
                                lungetc(*--p);
                        c = *--p;
-                       if (c == '-')
+                       if (c == '-') {
+                               free(buf);
                                return (c);
+                       }
                }
        }
 
@@ -2899,22 +2945,31 @@ nodigits:
        if (isalnum(c) || c == ':' || c == '_' || c == '*') {
                do {
                        *p++ = c;
-                       if ((unsigned)(p-buf) >= sizeof(buf)) {
-                               yyerror("string too long");
-                               return (findeol());
+                       if ((unsigned)(p-buf) >= bufsize) {
+                               bufsize += READBUFFERSIZE;
+                               buf = realloc(buf, bufsize);
+                               if (buf == NULL) {
+                                       yyerror("realloc failed");
+                                       return (findeol());
+                               }
+                               p = buf + bufsize - READBUFFERSIZE;
                        }
                } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
                lungetc(c);
                *p = '\0';
                if ((token = lookup(buf)) == STRING)
-                       if ((yylval.v.string = strdup(buf)) == NULL)
+                       if ((yylval.v.string = strdup(buf)) == NULL) {
+                               free(buf);
                                fatal("yylex: strdup");
+                       }
+               free(buf);
                return (token);
        }
        if (c == '\n') {
                yylval.lineno = file->lineno;
                file->lineno++;
        }
+       free(buf);
        if (c == EOF)
                return (0);
        return (c);


Reply via email to