Re: Memory corruptions in bc(1)

2015-11-20 Thread Sebastian Benoit
ok

Otto Moerbeek(o...@drijf.net) on 2015.11.20 14:22:12 +0100:
> 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  0x19f79fa7c43d in *_libc_fputs (s=0xdfdfdfdfdfdfdfdf  > > Cannot access memory at address 0xdfdfdfdfdfdfdfdf>, fp=0x1) at 
> > > /usr/src/lib/libc/stdio/fputs.c:50
> > > #2  0x19f4ecb0f401 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  0x19f4ecb13f3e in main (argc=1, argv=0x7f7fa570) 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 -  1.48
> +++ bc.y  20 Nov 2015 13:19:07 -
> @@ -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);
> 

-- 



Re: Memory corruptions in bc(1)

2015-11-20 Thread Otto Moerbeek
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  0x19f79fa7c43d in *_libc_fputs (s=0xdfdfdfdfdfdfdfdf  > access memory at address 0xdfdfdfdfdfdfdfdf>, fp=0x1) at 
> > /usr/src/lib/libc/stdio/fputs.c:50
> > #2  0x19f4ecb0f401 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  0x19f4ecb13f3e in main (argc=1, argv=0x7f7fa570) 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.y10 Oct 2015 19:28:54 -  1.48
+++ bc.y20 Nov 2015 13:19:07 -
@@ -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 voidemit(ssize_t);
+static voidemit(ssize_t, int);
 static voidemit_macro(int, ssize_t);
 static voidfree_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);



Re: Memory corruptions in bc(1)

2015-11-20 Thread Otto Moerbeek
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  0x19f79fa7c43d in *_libc_fputs (s=0xdfdfdfdfdfdfdfdf  access memory at address 0xdfdfdfdfdfdfdfdf>, fp=0x1) at 
> /usr/src/lib/libc/stdio/fputs.c:50
> #2  0x19f4ecb0f401 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  0x19f4ecb13f3e in main (argc=1, argv=0x7f7fa570) 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

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.y10 Oct 2015 19:28:54 -  1.48
+++ bc.y20 Nov 2015 10:46:29 -
@@ -808,7 +808,7 @@ emit(ssize_t i)
if (instructions[i].index >= 0)
while (instructions[i].index != END_NODE)
emit(instructions[i++].index);
-   else
+   else if (instructions[i].index != END_NODE)
fputs(instructions[i].u.cstr, stdout);
 }
 
@@ -951,7 +951,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);



Memory corruptions in bc(1)

2015-11-19 Thread Michael McConville
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  0x19f79fa7c43d in *_libc_fputs (s=0xdfdfdfdfdfdfdfdf , fp=0x1) at 
/usr/src/lib/libc/stdio/fputs.c:50
#2  0x19f4ecb0f401 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  0x19f4ecb13f3e in main (argc=1, argv=0x7f7fa570) at 
/usr/src/usr.bin/bc/bc.y:1188