Re: Memory corruptions in bc(1)
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)
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)
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)
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