On Fri, Nov 20, 2015 at 11:52:16AM +0100, Otto Moerbeek wrote:

> On Thu, Nov 19, 2015 at 05:52:39PM -0500, Michael McConville wrote:
> 
> > I'm already cache-thrashing with all of my side projects, so if anyone's
> > interested I'll leave this to them.
> > 
> > A few days ago, I wanted to try American Fuzzy Lop (afl), and bc(1)
> > seemed like a good first target: it pretty much just goes from stdin to
> > stdout, so there's no code reorganization needed.
> > 
> > For those not familiar, bc compiles its input to dc(1)'s syntax and
> > forks to dc.
> > 
> > There are many unique crash paths - 1041 before I killed afl. Most
> > center around emit(), which emits a dc instr. Many pass NULL to fputs()
> > in emit(). I found at least one (crashes/id:001041*) that
> > nondeterministically passes the str pointer 0xdfdfdfdfdfdfdfdf to
> > fputs(), which is probably uninitialized or already-freed memory.
> > Backtrace below.
> > 
> > malloc.conf(5) may be useful.
> > 
> > Here's the full afl directory:
> > 
> >     http://www.sccs.swarthmore.edu/users/16/mmcconv1/bc-afl/
> > 
> > 
> > Core was generated by `bc'.
> > Program terminated with signal SIGBUS, Bus error.
> > #0  strlen () at /usr/src/lib/libc/arch/amd64/string/strlen.S:152
> > 152             movq    (%rax),%rdx             /* first data in high bytes 
> > */
> > (gdb) bt
> > #0  strlen () at /usr/src/lib/libc/arch/amd64/string/strlen.S:152
> > #1  0x000019f79fa7c43d in *_libc_fputs (s=0xdfdfdfdfdfdfdfdf <error: Cannot 
> > access memory at address 0xdfdfdfdfdfdfdfdf>, fp=0x1) at 
> > /usr/src/lib/libc/stdio/fputs.c:50
> > #2  0x000019f4ecb0f401 in emit (i=28548786530304) at 
> > /usr/src/usr.bin/bc/bc.y:810
> > #3  yyparse () at /usr/src/usr.bin/bc/bc.y:178
> > #4  0x000019f4ecb13f3e in main (argc=1, argv=0x7f7fffffa570) at 
> > /usr/src/usr.bin/bc/bc.y:1188
> 
> This fixes at least one case  (id-000141*) and make the printing of
> non-ascci chars better
> 
>       -Otto
> 

New version, which solves all cases found in crashes, hangs and queue
above.  The remaining cases were emit going into an infinite recursion
becuse the tree wasn't a tree but a cyclic graph.

Regress still succeeds.

        -Otto

Index: bc.y
===================================================================
RCS file: /cvs/src/usr.bin/bc/bc.y,v
retrieving revision 1.48
diff -u -p -r1.48 bc.y
--- bc.y        10 Oct 2015 19:28:54 -0000      1.48
+++ bc.y        20 Nov 2015 13:19:07 -0000
@@ -72,7 +72,7 @@ static void           grow(void);
 static ssize_t         cs(const char *);
 static ssize_t         as(const char *);
 static ssize_t         node(ssize_t, ...);
-static void            emit(ssize_t);
+static void            emit(ssize_t, int);
 static void            emit_macro(int, ssize_t);
 static void            free_tree(void);
 static ssize_t         numnode(int);
@@ -175,7 +175,7 @@ program             : /* empty */
 
 input_item     : semicolon_list NEWLINE
                        {
-                               emit($1);
+                               emit($1, 0);
                                macro_char = reset_macro_char;
                                putchar('\n');
                                free_tree();
@@ -803,12 +803,17 @@ node(ssize_t arg, ...)
 }
 
 static void
-emit(ssize_t i)
+emit(ssize_t i, int level)
 {
-       if (instructions[i].index >= 0)
-               while (instructions[i].index != END_NODE)
-                       emit(instructions[i++].index);
-       else
+       if (level > 1000)
+               errx(1, "internal error: tree level > 1000");
+       if (instructions[i].index >= 0) {
+               while (instructions[i].index != END_NODE &&
+                   instructions[i].index != i)  {
+                       emit(instructions[i].index, level + 1);
+                       i++;
+               }
+       } else if (instructions[i].index != END_NODE)
                fputs(instructions[i].u.cstr, stdout);
 }
 
@@ -816,7 +821,7 @@ static void
 emit_macro(int node, ssize_t code)
 {
        putchar('[');
-       emit(code);
+       emit(code, 0);
        printf("]s%s\n", instructions[node].u.cstr);
        nesting--;
 }
@@ -951,7 +956,7 @@ yyerror(char *s)
            !isprint((unsigned char)yytext[0]))
                n = asprintf(&str,
                    "%s: %s:%d: %s: ascii char 0x%02x unexpected",
-                   __progname, filename, lineno, s, yytext[0]);
+                   __progname, filename, lineno, s, yytext[0] & 0xff);
        else
                n = asprintf(&str, "%s: %s:%d: %s: %s unexpected",
                    __progname, filename, lineno, s, yytext);

Reply via email to