Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segmentation fault in Perl5 while fuzzing Perl binary (possible stack overflow?) #14391

Closed
p5pRT opened this issue Jan 4, 2015 · 16 comments
Closed

Comments

@p5pRT
Copy link

p5pRT commented Jan 4, 2015

Migrated from rt.perl.org#123542 (status was 'resolved')

Searchable as RT123542$

@p5pRT
Copy link
Author

p5pRT commented Jan 4, 2015

From @geeknik

I'm still fuzzing a Perl binary that I built from git source on 01/02/2015
using the afl-gcc compiler​:

CC=/path/to/afl-gcc ./Configure
AFL_HARDEN=1 make

This is perl 5, version 21, subversion 8 (v5.21.8 (v5.21.7-209-g4e27940))
built for x86_64-linux

Besides the above information, this version of Perl was compiled using all
defaults (enter was pressed for every question).

While fuzzing the perl binary, I found another testcase which causes a
segfault (and possible stack overflow). I've attached the testcase and the
resulting core dump to this email.

geeknik@​deb7fuzz​:~/findings/perl/fuzzer02/crashes$ /home/geeknik/perl5/perl
id\​:000023\,sig\​:11\,src\​:004555+020002\,op\​:splice\,rep\​:16

String found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 8, near
"print3"Hello World.\n""
Backslash found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 11, near "is\"
String found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 11, near "Mnt ""
(Missing semicolon on previous line?)
Array found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 11, at end of line
(Missing operator before ?)
Bareword found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 11, near "<P>Note"
(Missing operator before Note?)
Bareword found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 11, near "]g"
(Missing operator before g?)
String found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 11, near "print ""
(Missing semicolon on previous line?)
Bareword found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 12, near "print
"into"
  (Might be a runaway multi-line "" string starting on line 11)
(Do you need to predeclare print?)
String found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 15, near "n"
  }
print ""
Segmentation fault (core dumped)

geeknik@​deb7fuzz​:~/findings/perl/fuzzer02/crashes$ valgrind -q
/home/geeknik/perl5/perl
id\​:000023\,sig\​:11\,src\​:004555+020002\,op\​:splice\,rep\​:16

String found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 8, near
"print3"Hello World.\n""
Backslash found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 11, near "is\"
String found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 11, near "Mnt ""
(Missing semicolon on previous line?)
Array found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 11, at end of line
(Missing operator before ?)
Bareword found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 11, near "<P>Note"
(Missing operator before Note?)
Bareword found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 11, near "]g"
(Missing operator before g?)
String found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 11, near "print ""
(Missing semicolon on previous line?)
Bareword found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 12, near "print
"into"
  (Might be a runaway multi-line "" string starting on line 11)
(Do you need to predeclare print?)
String found where operator expected at
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16 line 15, near "n"
  }
print ""
==55834== Invalid read of size 8
==55834== at 0x4C0100​: Perl_pmruntime (op.c​:5481)
==55834== by 0x5CBEBC​: Perl_yyparse (perly.y​:1000)
==55834== by 0x4F3114​: perl_parse (perl.c​:2273)
==55834== by 0x42A92B​: main (perlmain.c​:114)
==55834== Address 0x8 is not stack'd, malloc'd or (recently) free'd
==55834==
==55834==
==55834== Process terminating with default action of signal 11 (SIGSEGV)​:
dumping core
==55834== Access not within mapped region at address 0x8
==55834== at 0x4C0100​: Perl_pmruntime (op.c​:5481)
==55834== by 0x5CBEBC​: Perl_yyparse (perly.y​:1000)
==55834== by 0x4F3114​: perl_parse (perl.c​:2273)
==55834== by 0x42A92B​: main (perlmain.c​:114)
==55834== If you believe this happened as a result of a stack
==55834== overflow in your program's main thread (unlikely but
==55834== possible), you can try to increase the size of the
==55834== main thread stack using the --main-stacksize= flag.
==55834== The main thread stack size used in this run was 8388608.
Segmentation fault

geeknik@​deb7fuzz​:~/findings/perl/fuzzer02/crashes$ gdb
/home/geeknik/perl5/perl core

GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+​: GNU GPL version 3 or later <http​://gnu.org/licenses/gpl.html

This is free software​: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see​:
<http​://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/geeknik/perl5/perl...done.
[New LWP 46515]

warning​: Can't read pathname for load map​: Input/output error.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `/home/geeknik/perl5/perl
id​:000023,sig​:11,src​:004555+020002,op​:splice,rep​:16'.
Program terminated with signal 11, Segmentation fault.
#0 Perl_pmruntime (o=0x2c6b550, expr=0x2c6b290, isreg=true, floor=0) at
op.c​:5481
5481 while (OpSIBLING(kid) != repl)
(gdb) bt
#0 Perl_pmruntime (o=0x2c6b550, expr=0x2c6b290, isreg=true, floor=0) at
op.c​:5481
#1 0x00000000005cbebd in Perl_yyparse (gramtype=<optimized out>) at
perly.y​:1000
#2 0x00000000004f3115 in S_parse_body (xsinit=0x42ad20 <xs_init>, env=0x0)
at perl.c​:2273
#3 perl_parse (my_perl=<optimized out>, xsinit=0x42ad20 <xs_init>,
argc=<optimized out>, argv=<optimized out>, env=0x0) at perl.c​:1607
#4 0x000000000042a92c in main (argc=2, argv=0x7fff492c7348,
env=0x7fff492c7360) at perlmain.c​:114
#5 0x00007fc0bf96dead in __libc_start_main (main=<optimized out>,
argc=<optimized out>, ubp_av=<optimized out>, init=<optimized out>,
  fini=<optimized out>, rtld_fini=<optimized out>,
stack_end=0x7fff492c7338) at libc-start.c​:244
#6 0x000000000042ac45 in _start ()
(gdb)

./perlbug -d


Flags​:
  category=core
  severity=low


This perlbug was built using Perl 5.21.8 - Fri Jan 2 19​:02​:59 CST 2015
It is being executed now by Perl 5.21.7 - Thu Dec 18 14​:34​:01 CST 2014.

Site configuration information for perl 5.21.7​:

Configured by geeknik at Thu Dec 18 14​:34​:01 CST 2014.

Summary of my perl5 (revision 5 version 21 subversion 7) configuration​:
  Commit id​: e9d2bd8
  Platform​:
  osname=linux, osvers=3.2.0-4-amd64, archname=x86_64-linux
  uname='linux deb7fuzz 3.2.0-4-amd64 #1 smp debian 3.2.63-2+deb7u2
x86_64 gnulinux '
  config_args=''
  hint=recommended, useposix=true, d_sigaction=define
  useithreads=undef, usemultiplicity=undef
  use64bitint=define, use64bitall=define, uselongdouble=undef
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='/home/geeknik/afl/afl-gcc', ccflags ='-fwrapv -fno-strict-aliasing
-pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE
-D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2',
  optimize='-O2',
  cppflags='-fwrapv -fno-strict-aliasing -pipe -fstack-protector
-I/usr/local/include'
  ccversion='', gccversion='4.7.2', gccosandvers=''
  intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678,
doublekind=3
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16,
longdblkind=3
  ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t',
lseeksize=8
  alignbytes=8, prototype=define
  Linker and Libraries​:
  ld='/home/geeknik/afl/afl-gcc', ldflags =' -fstack-protector
-L/usr/local/lib'
  libpth=/usr/local/lib /usr/lib/gcc/x86_64-linux-gnu/4.7/include-fixed
/usr/include/x86_64-linux-gnu /usr/lib /lib/x86_64-linux-gnu /lib/../lib
/usr/lib/x86_64-linux-gnu /usr/lib/../lib /lib
  libs=-lnsl -ldl -lm -lcrypt -lutil -lc -lpthread
  perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc -lpthread
  libc=libc-2.13.so, so=so, useshrplib=false, libperl=libperl.a
  gnulibc_version='2.13'
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
  cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib
-fstack-protector'


@​INC for perl 5.21.7​:
  /usr/local/lib/perl5/site_perl/5.21.7/x86_64-linux
  /usr/local/lib/perl5/site_perl/5.21.7
  /usr/local/lib/perl5/5.21.7/x86_64-linux
  /usr/local/lib/perl5/5.21.7
  .


Environment for perl 5.21.7​:
  HOME=/home/geeknik
  LANG=en_US.UTF-8
  LANGUAGE (unset)
  LD_LIBRARY_PATH (unset)
  LOGDIR (unset)
  PATH=/usr/local/bin​:/usr/bin​:/bin​:/usr/local/games​:/usr/games
  PERL_BADLANG (unset)
  SHELL=/bin/bash

Details on AFL can be found here​: http​://lcamtuf.coredump.cx/afl/

@p5pRT
Copy link
Author

p5pRT commented Jan 4, 2015

From @geeknik

core.gz

@p5pRT
Copy link
Author

p5pRT commented Jan 4, 2015

From @geeknik

crash.gz

@p5pRT
Copy link
Author

p5pRT commented Jan 5, 2015

From @jkeenan

The patch provided by khw in RT #123539 to address a different segfault reported by the same tester does not address the problem in *this* ticket. So this is a different problem.

#####
$ git branch
* 123539-segfault
#####
$ ./perl -Ilib -c ~/learn/perl/p5p/noshebang-123542-crash
String found where operator expected at /home/jkeenan/learn/perl/p5p/noshebang-123542-crash line 8, near "print3"Hello World.\n""
Backslash found where operator expected at /home/jkeenan/learn/perl/p5p/noshebang-123542-crash line 11, near "is\"
String found where operator expected at /home/jkeenan/learn/perl/p5p/noshebang-123542-crash line 11, near "Mnt ""
  (Missing semicolon on previous line?)
Array found where operator expected at /home/jkeenan/learn/perl/p5p/noshebang-123542-crash line 11, at end of line
  (Missing operator before ?)
Bareword found where operator expected at /home/jkeenan/learn/perl/p5p/noshebang-123542-crash line 11, near "<P>Note"
  (Missing operator before Note?)
Bareword found where operator expected at /home/jkeenan/learn/perl/p5p/noshebang-123542-crash line 11, near "]g"
  (Missing operator before g?)
String found where operator expected at /home/jkeenan/learn/perl/p5p/noshebang-123542-crash line 11, near "print ""
  (Missing semicolon on previous line?)
Bareword found where operator expected at /home/jkeenan/learn/perl/p5p/noshebang-123542-crash line 12, near "print "into"
  (Might be a runaway multi-line "" string starting on line 11)
  (Do you need to predeclare print?)
String found where operator expected at /home/jkeenan/learn/perl/p5p/noshebang-123542-crash line 15, near "n"
  }
print ""
Segmentation fault (core dumped)
#####

--
James E Keenan (jkeenan@​cpan.org)

@p5pRT
Copy link
Author

p5pRT commented Jan 5, 2015

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Jan 5, 2015

From @tonycoz

On Sun Jan 04 16​:23​:21 2015, jkeenan wrote​:

The patch provided by khw in RT #123539 to address a different
segfault reported by the same tester does not address the problem in
*this* ticket. So this is a different problem.

Right, this is a problem with the construction of the op-tree.

The loop​:

  while (OpSIBLING(kid) != repl)
  kid = OpSIBLING(kid);
  op_sibling_splice(expr, kid, 1, NULL);

attempts to deref a NULL kid because it can't find repl in the op's children.

Adding NULL checks here crashes in op_free() instead.

I'm working on producing a smaller test-case.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jan 5, 2015

From @tonycoz

On Sun Jan 04 18​:21​:03 2015, tonyc wrote​:

I'm working on producing a smaller test-case.

Attached a smaller test case.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jan 5, 2015

From @tonycoz

123542-fuzz-crash-mod.pl

@p5pRT
Copy link
Author

p5pRT commented Jan 5, 2015

From @cpansprout

On Sun Jan 04 18​:21​:03 2015, tonyc wrote​:

On Sun Jan 04 16​:23​:21 2015, jkeenan wrote​:

The patch provided by khw in RT #123539 to address a different
segfault reported by the same tester does not address the problem in
*this* ticket. So this is a different problem.

Right, this is a problem with the construction of the op-tree.

The loop​:

while (OpSIBLING(kid) != repl)
kid = OpSIBLING(kid);
op_sibling_splice(expr, kid, 1, NULL);

attempts to deref a NULL kid because it can't find repl in the op's
children.

Adding NULL checks here crashes in op_free() instead.

I'm working on producing a smaller test-case.

I cannot reproduce this on a Mac. I do get a crash on dromedary, but no debugging symbols, which makes it a little hard to debug. :-(

This has to be some sort of memory corruption if op_last points to something not found in the op_first->op_sibling->... chain.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jan 5, 2015

From @cpansprout

On Sun Jan 04 23​:41​:14 2015, sprout wrote​:

On Sun Jan 04 18​:21​:03 2015, tonyc wrote​:

On Sun Jan 04 16​:23​:21 2015, jkeenan wrote​:

The patch provided by khw in RT #123539 to address a different
segfault reported by the same tester does not address the problem
in
*this* ticket. So this is a different problem.

Right, this is a problem with the construction of the op-tree.

The loop​:

while (OpSIBLING(kid) != repl)
kid = OpSIBLING(kid);
op_sibling_splice(expr, kid, 1, NULL);

attempts to deref a NULL kid because it can't find repl in the op's
children.

Adding NULL checks here crashes in op_free() instead.

I'm working on producing a smaller test-case.

I cannot reproduce this on a Mac. I do get a crash on dromedary, but
no debugging symbols, which makes it a little hard to debug. :-(

This has to be some sort of memory corruption if op_last points to
something not found in the op_first->op_sibling->... chain.

A bisect blames it on me​:

8be227a is the first bad commit
commit 8be227a
Author​: Father Chrysostomos <sprout@​cpan.org>
Date​: Sat Jun 23 09​:54​:31 2012 -0700

  CV-based slab allocation for ops

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jan 5, 2015

From @andk

In case you still need a stacktrace, I have produced one with
v5.17.1-224-g8be227a​:

Program terminated with signal SIGABRT, Aborted.
#0 0x00007ff4faf42107 in __GI_raise (sig=sig@​entry=6)
  at ../nptl/sysdeps/unix/sysv/linux/raise.c​:56
56 ../nptl/sysdeps/unix/sysv/linux/raise.c​: No such file or directory.
(gdb) bt
#0 0x00007ff4faf42107 in __GI_raise (sig=sig@​entry=6)
  at ../nptl/sysdeps/unix/sysv/linux/raise.c​:56
#1 0x00007ff4faf434e8 in __GI_abort () at abort.c​:89
#2 0x00007ff4faf80044 in __libc_message (do_abort=do_abort@​entry=1,
  fmt=fmt@​entry=0x7ff4fb072c60 "*** Error in `%s'​: %s​: 0x%s ***\n")
  at ../sysdeps/posix/libc_fatal.c​:175
#3 0x00007ff4faf8581e in malloc_printerr (action=1,
  str=0x7ff4fb06ed1e "free()​: invalid pointer", ptr=<optimized out>)
  at malloc.c​:4996
#4 0x00007ff4faf86526 in _int_free (av=<optimized out>, p=<optimized out>,
  have_lock=0) at malloc.c​:3840
#5 0x000000000041e589 in Perl_opslab_force_free (
  my_perl=my_perl@​entry=0x187c010, slab=0x18a5cd0) at op.c​:482
#6 0x000000000045f075 in Perl_cv_undef (my_perl=0x187c010, cv=0x187fbe0)
  at pad.c​:372
#7 0x00000000004ae342 in Perl_sv_clear (my_perl=0x187c010, orig_sv=0x3836,
  orig_sv@​entry=0x187fbe0) at sv.c​:6106
#8 0x00000000004ae794 in Perl_sv_free2 (my_perl=my_perl@​entry=0x187c010,
  sv=0x187fbe0) at sv.c​:6524
#9 0x00000000004379c1 in perl_destruct (my_perl=0x187c010) at perl.c​:758
#10 0x000000000041bd03 in main (argc=2, argv=0x7fffa166ef08,
  env=0x7fffa166ef20) at perlmain.c​:131

--
andreas

@p5pRT
Copy link
Author

p5pRT commented Jan 9, 2015

From @cpansprout

On Sun Jan 04 18​:21​:03 2015, tonyc wrote​:

On Sun Jan 04 16​:23​:21 2015, jkeenan wrote​:

The patch provided by khw in RT #123539 to address a different
segfault reported by the same tester does not address the problem in
*this* ticket. So this is a different problem.

Right, this is a problem with the construction of the op-tree.

The loop​:

while (OpSIBLING(kid) != repl)
kid = OpSIBLING(kid);
op_sibling_splice(expr, kid, 1, NULL);

attempts to deref a NULL kid because it can't find repl in the op's
children.

In this case kid and repl are the op_first and op_last, respectively, of expr. But expr is an unop with no op_last field. So cLISTOPx(...)->op_last reads past the end of the op struct into the next op slot, and repl ends up holding an opslot pointer. That can’t be found in the kids (there is only one kid), so we crash when doing OpSIBLING(NULL), as you observed.

Adding NULL checks here crashes in op_free() instead.

Because substrepl is pointing to something that is not an op.

I'm working on producing a smaller test-case.

I got it down to s/${<>{})//.

On Mon Jan 05 06​:05​:53 2015, sprout wrote​:

A bisect blames it on me​:

8be227a is the first bad commit
commit 8be227a
Author​: Father Chrysostomos <sprout@​cpan.org>
Date​: Sat Jun 23 09​:54​:31 2012 -0700

CV\-based slab allocation for ops

It started failing then because previously ops were allocated via calloc, so cLISTOPx(unop)->op_last would produce a null pointer. So kid->op_sibling == repl was true on the very first kid (the only kid), and the loop would end.

I fixed this in 08b999a.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jan 9, 2015

@cpansprout - Status changed from 'open' to 'pending release'

@p5pRT
Copy link
Author

p5pRT commented Jan 9, 2015

From @cpansprout

On Thu Jan 08 18​:12​:29 2015, sprout wrote​:

I got it down to s/${<>{})//.

On Mon Jan 05 06​:05​:53 2015, sprout wrote​:

A bisect blames it on me​:

8be227a is the first bad commit
commit 8be227a
Author​: Father Chrysostomos <sprout@​cpan.org>
Date​: Sat Jun 23 09​:54​:31 2012 -0700

CV-based slab allocation for ops

It started failing then because previously ops were allocated via
calloc, so cLISTOPx(unop)->op_last would produce a null pointer. So
kid->op_sibling == repl was true on the very first kid (the only kid),
and the loop would end.

Actually, my reduced case *does* crash in 5.10-14, but not in 5.8[789].

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jun 2, 2015

From @khwilliamson

Thanks for submitting this ticket

The issue should be resolved with the release today of Perl v5.22, available at http​://www.perl.org/get.html
If you find that the problem persists, feel free to reopen this ticket

--
Karl Williamson for the Perl 5 porters team

@p5pRT
Copy link
Author

p5pRT commented Jun 2, 2015

@khwilliamson - Status changed from 'pending release' to 'resolved'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant