On Tue, Sep 17, 2019 at 11:56:26PM +0800, Michael Mikonos wrote:
> Hello,
> 
> I was wondering why fuzz input was sometimes crashing flex(1).
> Now that assert() is enabled in the build I am able to
> trigger it with the following input.
> 
> $ cat test.l
> %{ 
> hello
> %}
> 
> %%
> 
> )))
> world
> $ /usr/bin/lex -d - < test.l
> assertion "_sf_top_ix > 0" failed: file "scanflags.c", line 55, function 
> "sf_pop"
> Abort trap (core dumped) 
> 
> $ gdb -c lex.core -e /usr/bin/lex
> GNU gdb 6.3
> Copyright 2004 Free Software Foundation, Inc.
> GDB is free software, covered by the GNU General Public License, and you are
> welcome to change it and/or distribute copies of it under certain conditions.
> Type "show copying" to see the conditions.
> There is absolutely no warranty for GDB.  Type "show warranty" for details.
> This GDB was configured as "i386-unknown-openbsd6.6".
> Core was generated by `lex'.
> Program terminated with signal 6, Aborted.
> Loaded symbols for /usr/bin/lex.assert.debug
> Reading symbols from /usr/lib/libm.so.10.1...done.
> Loaded symbols for /usr/lib/libm.so.10.1
> Reading symbols from /usr/lib/libc.so.95.1...done.
> Loaded symbols for /usr/lib/libc.so.95.1
> Reading symbols from /usr/libexec/ld.so...done.
> Loaded symbols for /usr/libexec/ld.so
> #0  thrkill () at -:3
> 3     -: No such file or directory.
>       in -
> (gdb) bt
> #0  thrkill () at -:3
> #1  0x0d0fce40 in _libc_raise (s=6) at /usr/src/lib/libc/gen/raise.c:37
> #2  0x0d104e3b in _libc_abort () at /usr/src/lib/libc/stdlib/abort.c:51
> #3  0x0d0c3b30 in _libc___assert2 (file=0x1a14d90e "scanflags.c", line=55, 
>     func=0x1a1526a2 "sf_pop", failedexpr=0x1a158462 "_sf_top_ix > 0")
>     at /usr/src/lib/libc/gen/assert.c:52
> #4  0x1a189024 in sf_pop () at scanflags.c:55
> #5  0x1a186eec in flexscan () at scan.l:744
> #6  0x1a18cfa6 in yylex () at yylex.c:52
> #7  0x1a17ffc5 in yyparse () at parse.c:687
> #8  0x1a179a97 in readin () at main.c:1445
> #9  0x1a178d81 in flex_main (argc=3, argv=0xcf7e8d74) at main.c:175
> #10 0x1a17b535 in main (argc=3, argv=0xcf7e8d74) at main.c:223
> Current language:  auto; currently asm
> 
> Stack trace from gdb shows flexscan() calls sf_pop() but the stack _sf_stk
> is empty and has nothing to pop.
> flexscan() calls sf_push() when it sees "(", but fails to check the size of
> _sf_stk before calling sf_pop() when ")" is seen.
> The diff below prints a syntax error message instead of aborting in this case.
> It looks like this for the test file:
> 
> $ lex -d - < test.l
> <stdin>:7: ')' with no matching '('
> 
> Before assert() was enabled, calling sf_pop() would wrap the array
> index _sf_top_ix from 0 to 0xffffffff and a SEGV could happen later.
> Does this look OK?
> 
> - Michael
> 
> 
> Index: scan.l
> ===================================================================
> RCS file: /cvs/src/usr.bin/lex/scan.l,v
> retrieving revision 1.12
> diff -u -p -u -r1.12 scan.l
> --- scan.l    19 Nov 2015 23:34:56 -0000      1.12
> +++ scan.l    17 Sep 2019 15:35:27 -0000
> @@ -741,7 +741,14 @@ nmstr[yyleng - 2 - end_is_ws] = '\0';  /
>                      return '(';
>                  }
>      "("         sf_push(); return '(';
> -    ")"         sf_pop(); return ')';
> +    ")"         {
> +                    if (_sf_top_ix == 0) {
> +                        synerr( _("')' with no matching '('\n"));
> +                        FLEX_EXIT(EXIT_FAILURE);
> +                    }
> +                    sf_pop();
> +                    return ')';
> +                }
>  
>       [/|*+?.(){}]    return (unsigned char) yytext[0];
>       .               RETURNCHAR;

When I remembered to check if upstream flex had fixed the sf_pop()
issue I found their fix was a little different:
https://github.com/westes/flex/commit/9ba6e5283efd2fe454d3bc92eca960b3ebd91294

Notably, FLEX_EXIT() is not called so flexscan() won't immediately
terminate. This allows other syntax errors to be reported.
The following patch applies what they have.

Index: scan.l
===================================================================
RCS file: /cvs/src/usr.bin/lex/scan.l,v
retrieving revision 1.12
diff -u -p -u -r1.12 scan.l
--- scan.l      19 Nov 2015 23:34:56 -0000      1.12
+++ scan.l      21 Sep 2019 12:08:36 -0000
@@ -741,7 +741,13 @@ nmstr[yyleng - 2 - end_is_ws] = '\0';  /
                     return '(';
                 }
     "("         sf_push(); return '(';
-    ")"         sf_pop(); return ')';
+    ")"         {
+                    if (_sf_top_ix > 0) {
+                        sf_pop();
+                        return ')';
+                    } else
+                        synerr(_("unbalanced parenthesis"));
+                }
 
        [/|*+?.(){}]    return (unsigned char) yytext[0];
        .               RETURNCHAR;

Reply via email to