Improved error handling in config parser.
authortobias <tobias@openbsd.org>
Tue, 30 Nov 2021 20:08:15 +0000 (20:08 +0000)
committertobias <tobias@openbsd.org>
Tue, 30 Nov 2021 20:08:15 +0000 (20:08 +0000)
- Escaped newlines confused column counter
- An unclosed quote could have been logged multiple times
- Signed data types could overflow, which is undefined behavior

ok tedu

usr.bin/doas/doas.c
usr.bin/doas/doas.h
usr.bin/doas/parse.y

index 4ceb6b9..0172e0c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: doas.c,v 1.92 2021/10/13 17:41:14 millert Exp $ */
+/* $OpenBSD: doas.c,v 1.93 2021/11/30 20:08:15 tobias Exp $ */
 /*
  * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
  *
@@ -172,7 +172,7 @@ parseconfig(const char *filename, int checkperms)
 
        yyparse();
        fclose(yyfp);
-       if (parse_errors)
+       if (parse_error)
                exit(1);
 }
 
index 3a9bf4d..b98fe35 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: doas.h,v 1.18 2021/09/07 13:46:07 jcs Exp $ */
+/* $OpenBSD: doas.h,v 1.19 2021/11/30 20:08:15 tobias Exp $ */
 /*
  * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
  *
@@ -27,7 +27,7 @@ struct rule {
 
 extern struct rule **rules;
 extern size_t nrules;
-extern int parse_errors;
+extern int parse_error;
 
 extern const char *formerpath;
 
index eaaf8c4..30d4c7d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.29 2021/01/27 17:02:50 millert Exp $ */
+/* $OpenBSD: parse.y,v 1.30 2021/11/30 20:08:15 tobias Exp $ */
 /*
  * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
  *
@@ -18,6 +18,7 @@
 %{
 #include <sys/types.h>
 #include <ctype.h>
+#include <limits.h>
 #include <unistd.h>
 #include <stdint.h>
 #include <stdarg.h>
@@ -39,8 +40,8 @@ typedef struct {
                const char **strlist;
                const char *str;
        };
-       int lineno;
-       int colno;
+       unsigned long lineno;
+       unsigned long colno;
 } yystype;
 #define YYSTYPE yystype
 
@@ -50,7 +51,7 @@ struct rule **rules;
 size_t nrules;
 static size_t maxrules;
 
-int parse_errors = 0;
+int parse_error = 0;
 
 static void yyerror(const char *, ...);
 static int yylex(void);
@@ -198,8 +199,8 @@ yyerror(const char *fmt, ...)
        va_start(va, fmt);
        vfprintf(stderr, fmt, va);
        va_end(va);
-       fprintf(stderr, " at line %d\n", yylval.lineno + 1);
-       parse_errors++;
+       fprintf(stderr, " at line %lu\n", yylval.lineno + 1);
+       parse_error = 1;
 }
 
 static struct keyword {
@@ -222,7 +223,8 @@ int
 yylex(void)
 {
        char buf[1024], *ebuf, *p, *str;
-       int c, quotes = 0, escape = 0, qpos = -1, nonkw = 0;
+       int c, quoted = 0, quotes = 0, qerr = 0, escape = 0, nonkw = 0;
+       unsigned long qpos = 0;
        size_t i;
 
        p = buf;
@@ -258,7 +260,7 @@ repeat:
        for (;; c = getc(yyfp), yylval.colno++) {
                switch (c) {
                case '\0':
-                       yyerror("unallowed character NUL in column %d",
+                       yyerror("unallowed character NUL in column %lu",
                            yylval.colno + 1);
                        escape = 0;
                        continue;
@@ -268,26 +270,27 @@ repeat:
                                continue;
                        break;
                case '\n':
-                       if (quotes)
-                               yyerror("unterminated quotes in column %d",
+                       if (quotes && !qerr) {
+                               yyerror("unterminated quotes in column %lu",
                                    qpos + 1);
+                               qerr = 1;
+                       }
                        if (escape) {
                                nonkw = 1;
                                escape = 0;
-                               yylval.colno = 0;
+                               yylval.colno = ULONG_MAX;
                                yylval.lineno++;
                                continue;
                        }
                        goto eow;
                case EOF:
                        if (escape)
-                               yyerror("unterminated escape in column %d",
+                               yyerror("unterminated escape in column %lu",
                                    yylval.colno);
-                       if (quotes)
-                               yyerror("unterminated quotes in column %d",
+                       if (quotes && !qerr)
+                               yyerror("unterminated quotes in column %lu",
                                    qpos + 1);
                        goto eow;
-                       /* FALLTHROUGH */
                case '{':
                case '}':
                case '#':
@@ -298,9 +301,11 @@ repeat:
                        break;
                case '"':
                        if (!escape) {
+                               quoted = 1;
                                quotes = !quotes;
                                if (quotes) {
                                        nonkw = 1;
+                                       qerr = 0;
                                        qpos = yylval.colno;
                                }
                                continue;
@@ -326,7 +331,7 @@ eow:
                 */
                if (c == EOF)
                        goto eof;
-               else if (qpos == -1)    /* accept, e.g., empty args: cmd foo args "" */
+               else if (!quoted)    /* accept, e.g., empty args: cmd foo args "" */
                        goto repeat;
        }
        if (!nonkw) {