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 Perl 5.23.2 while fuzzing Perl binary #14843

Closed
p5pRT opened this issue Aug 10, 2015 · 6 comments
Closed

Segmentation fault in Perl 5.23.2 while fuzzing Perl binary #14843

p5pRT opened this issue Aug 10, 2015 · 6 comments

Comments

@p5pRT
Copy link

p5pRT commented Aug 10, 2015

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

Searchable as RT125781$

@p5pRT
Copy link
Author

p5pRT commented Aug 10, 2015

From @dcollinsn

While fuzzing the blead Perl binary (as a learning exercise), I found a testcase that causes a segfault under -Duse64bitint but which works fine (exits with an error but without receiving a fatal signal) without 64bitint. Perl -V, Valgrind, and GDB output are below. The original testcase reads​:

f$x 1...888888888888888
g

hexdump​:
0000000 66 24 78 20 20 31 2e 2e 2e 38 38 38 38 38 38 38
0000020 38 38 38 38 38 38 38 38 0a 67 0a
0000033

A reduced version of this testcase reads​:

f$0 1..880000000000000g

hexdump​:
0000000 66 24 30 20 31 2e 2e 38 38 30 30 30 30 30 30 30
0000020 30 30 30 30 30 30 67
0000027

Miniperl simply hangs under this testcase. A git bisect revealed that under old versions of Perl, this resulted in a hang. The hang changed to "Killed" at​:
ef00320 is the first bad commit
commit ef00320
Author​: Father Chrysostomos <sprout@​cpan.org>
Date​: Thu Oct 9 20​:32​:58 2014 -0700

  op.c​:allocmy​: Don’t depend on null termination

  This function has a len argument, but still depends on its argument’s
  being null-terminated in one spot. (All other parts of the function
  use the length.)

:100644 100644 d54651bacf6748b59d4c76645aa3019191f00158 0f646ed853fdfb519512c85fc3d5839dd6e237b5 M op.c

This may just be an out-of-memory condition, I can't actually find the first segfault right now, however it is definitely segfaulting in​:
commit a953aca
Author​: Daniel Dragan <bulk88@​hotmail.com>
Date​: Fri Oct 10 13​:29​:33 2014 -0400

  optimize & rmv from public API Perl_tmps_grow and related code

  Previously in PUSH_EXTEND_MORTAL__SV_C, "PL_tmps_ix + 1" would execute
  twice, once for the nonmutable if(>=), then again after the potential
  tmps_grow call. tmps_grow has an unused return register/void proto, put it
  to use by returning ix. Also change tmps_grow to take the result of
  "PL_tmps_ix + the constant (usually 1) or non-constant (EXTEND_MORTAL)".
  This avoid having to put the constant twice in machine code, once for the
  if test, 2nd time for extend length param for tmps_grow call. For
  non-constant/EXTEND_MORTAL usage, it allows the C optimizer to have the
  length var to go out of liveness sooner if possible. Also the var used for
  the if(>=) test is more likely to be in a register than length var.
  So "if test variable" is closer on hand to the CPU than length var. In some
  cases, if non-const len var isn't used again, it becomes the "ix" variable
  by having PL_tmps_ix added to it. Change sv_2mortal to return sv instead
  of NULL to remove a unique branch/block of machine code that assigns 0 to
  return variable (Visual C didn't figure out return sv == returned NULL,
  not sv). See also [perl #121845].

Summary of my perl5 (revision 5 version 23 subversion 2) configuration​:
  Commit id​: 749f0eb
  Platform​:
  osname=linux, osvers=2.6.32-5-686, archname=i686-linux-thread-multi-ld-64int
  uname='linux nagios 2.6.32-5-686 #1 smp tue may 13 16​:33​:32 utc 2014 i686 gnulinux '
  config_args=''
  hint=previous, useposix=true, d_sigaction=define
  useithreads=undef, usemultiplicity=define
  use64bitint=define, use64bitall=undef, uselongdouble=define
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='afl-gcc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -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='-D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2'
  ccversion='', gccversion='4.4.5', gccosandvers=''
  intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=12345678, doublekind=3
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12, longdblkind=3
  ivtype='long long', ivsize=8, nvtype='long double', nvsize=12, Off_t='off_t', lseeksize=8
  alignbytes=4, prototype=define
  Linker and Libraries​:
  ld='afl-gcc', ldflags =' -fstack-protector -L/usr/local/lib'
  libpth=/usr/local/lib /usr/lib/gcc/i486-linux-gnu/4.4.5/include-fixed /usr/lib /lib/../lib /usr/lib/../lib /lib /usr/lib/i486-linux-gnu /usr/lib64 /usr/local/lib /usr/lib/gcc/i486-linux-gnu/4.4.5/include-fixed /usr/lib
  libs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
  perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
  libc=libc-2.11.3.so, so=so, useshrplib=false, libperl=libperl.a
  gnulibc_version='2.11.3'
  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'

Characteristics of this binary (from libperl)​:
  Compile-time options​: HAS_TIMES MULTIPLICITY PERLIO_LAYERS
  PERL_COPY_ON_WRITE PERL_DONT_CREATE_GVSV
  PERL_HASH_FUNC_ONE_AT_A_TIME_HARD
  PERL_IMPLICIT_CONTEXT PERL_MALLOC_WRAP
  PERL_PRESERVE_IVUV USE_64_BIT_INT USE_LARGE_FILES
  USE_LOCALE USE_LOCALE_COLLATE USE_LOCALE_CTYPE
  USE_LOCALE_NUMERIC USE_LOCALE_TIME USE_LONG_DOUBLE
  USE_PERLIO USE_PERL_ATOF
  Built under linux
  Compiled at Aug 7 2015 19​:24​:52
  @​INC​:
  /usr/local/perl-afl/lib/site_perl/5.23.2/i686-linux-thread-multi-ld
  /usr/local/perl-afl/lib/site_perl/5.23.2
  /usr/local/perl-afl/lib/5.23.2/i686-linux-thread-multi-ld
  /usr/local/perl-afl/lib/5.23.2
  .

***VALGRIND OUTPUT***
==10717== Memcheck, a memory error detector
==10717== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==10717== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==10717== Command​: ../../bin/perl 000000_min.pl
==10717==
Bareword found where operator expected at 000000_min.pl line 1, near "880000000000000g"
  (Missing operator before g?)
==10717== Invalid write of size 4
==10717== at 0x84D4ACD​: Perl_pp_flop (pp_ctl.c​:1221)
==10717== by 0x836459F​: Perl_runops_standard (run.c​:41)
==10717== by 0x80AF547​: Perl_list (op.c​:4420)
==10717== by 0x80AF8CB​: Perl_ck_entersub_args_list (op.c​:11321)
==10717== by 0x80B0842​: Perl_ck_subr (op.c​:11911)
==10717== by 0x80C84C5​: Perl_op_convert_list (op.c​:4605)
==10717== by 0x81D71D5​: Perl_yyparse (perly.y​:707)
==10717== by 0x810FE82​: S_parse_body (perl.c​:2296)
==10717== by 0x81131DE​: perl_parse (perl.c​:1626)
==10717== by 0x806217C​: main (perlmain.c​:114)
==10717== Address 0x42179d0 is 0 bytes after a block of size 512 alloc'd
==10717== at 0x4023F50​: malloc (vg_replace_malloc.c​:236)
==10717== by 0x82CC357​: Perl_safesysmalloc (util.c​:149)
==10717== by 0x835BB89​: Perl_av_extend_guts (av.c​:182)
==10717== by 0x835BD6D​: Perl_av_extend (av.c​:80)
==10717== by 0x8473F0F​: Perl_new_stackinfo (scope.c​:56)
==10717== by 0x80F3D8C​: Perl_init_stacks (perl.c​:4055)
==10717== by 0x80F63E0​: perl_construct (perl.c​:249)
==10717== by 0x80623BF​: main (perlmain.c​:110)
==10717==
--10717-- VALGRIND INTERNAL ERROR​: Valgrind received a signal 11 (SIGSEGV) - exiting
--10717-- si_code=1; Faulting address​: 0x65736165; sp​: 0x62db7a38

valgrind​: the 'impossible' happened​:
  Killed by fatal signal
==10717== at 0x3809DE01​: myvprintf_str (m_debuglog.c​:530)
==10717== by 0x3809E5E2​: vgPlain_debugLog_vprintf (m_debuglog.c​:877)
==10717== by 0x380297F5​: vprintf_WRK (m_libcprint.c​:111)
==10717== by 0x380298B7​: vgPlain_printf (m_libcprint.c​:143)
==10717== by 0x38027966​: vgPlain_assert_fail (m_libcassert.c​:259)
==10717== by 0x61206F66​: ???

sched status​:
  running_tid=1

Thread 1​: status = VgTs_Runnable
==10717== at 0x4024046​: realloc (vg_replace_malloc.c​:525)
==10717== by 0x82CCE03​: Perl_safesysrealloc (util.c​:270)
==10717== by 0x84713A9​: Perl_tmps_grow_p (scope.c​:161)
==10717== by 0x839A16F​: Perl_sv_2mortal (sv.c​:8979)
==10717== by 0x84D4AC1​: Perl_pp_flop (pp_ctl.c​:1220)
==10717== by 0x836459F​: Perl_runops_standard (run.c​:41)
==10717== by 0x80AF547​: Perl_list (op.c​:4420)
==10717== by 0x80AF8CB​: Perl_ck_entersub_args_list (op.c​:11321)
==10717== by 0x80B0842​: Perl_ck_subr (op.c​:11911)
==10717== by 0x80C84C5​: Perl_op_convert_list (op.c​:4605)
==10717== by 0x81D71D5​: Perl_yyparse (perly.y​:707)
==10717== by 0x810FE82​: S_parse_body (perl.c​:2296)
==10717== by 0x81131DE​: perl_parse (perl.c​:1626)
==10717== by 0x806217C​: main (perlmain.c​:114)

***GDB OUTPUT***
(gdb) run
Starting program​: /usr/local/perl-afl/bin/perl 000000_min.pl
[Thread debugging using libthread_db enabled]
Bareword found where operator expected at 000000_min.pl line 1, near "880000000000000g"
  (Missing operator before g?)

Program received signal SIGSEGV, Segmentation fault.
0xb7e65a59 in _int_malloc (av=<value optimized out>,
  bytes=<value optimized out>) at malloc.c​:4534
4534 malloc.c​: No such file or directory.
  in malloc.c
(gdb) bt
#0 0xb7e65a59 in _int_malloc (av=<value optimized out>,
  bytes=<value optimized out>) at malloc.c​:4534
#1 0xb7e6797c in *__GI___libc_malloc (bytes=4080) at malloc.c​:3661
#2 0x082cc358 in Perl_safesysmalloc (size=4080) at util.c​:149
#3 0x08397ee0 in S_more_sv (my_perl=0x8734008) at sv.c​:304
#4 0x083d5a57 in Perl_newSViv (my_perl=0x8734008, i=20388) at sv.c​:9252
#5 0x084d4ab3 in Perl_pp_flop (my_perl=0x8734008) at pp_ctl.c​:1220
#6 0x083645a0 in Perl_runops_standard (my_perl=0x8734008) at run.c​:41
#7 0x080af548 in S_gen_constant_list (my_perl=0x8734008, o=0x8750754)
  at op.c​:4420
#8 Perl_list (my_perl=0x8734008, o=0x8750754) at op.c​:2215
#9 0x080af8cc in Perl_ck_entersub_args_list (my_perl=0x8734008,
  entersubop=0x875070c) at op.c​:11321
#10 0x080b0843 in Perl_ck_subr (my_perl=0x8734008, o=0x875070c) at op.c​:11911
#11 0x080c84c6 in Perl_op_convert_list (my_perl=0x8734008, type=185, flags=0,
  o=0x1) at op.c​:4605
#12 0x081d71d6 in Perl_yyparse (my_perl=0x8734008, gramtype=258) at perly.y​:707
#13 0x0810fe83 in S_parse_body (my_perl=0x8734008, env=<value optimized out>,
  xsinit=<value optimized out>) at perl.c​:2296
#14 0x081131df in perl_parse (my_perl=0x8734008, xsinit=0x8062430 <xs_init>,
  argc=2, argv=0xbffff7e4, env=0x0) at perl.c​:1626
#15 0x0806217d in main (argc=2, argv=0xbffff7e4, env=0xbffff7f0)
  at perlmain.c​:114

@p5pRT
Copy link
Author

p5pRT commented Aug 11, 2015

From @tonycoz

On Mon Aug 10 07​:48​:19 2015, dcollinsn@​gmail.com wrote​:

While fuzzing the blead Perl binary (as a learning exercise), I found
a testcase that causes a segfault under -Duse64bitint but which works
fine (exits with an error but without receiving a fatal signal)
without 64bitint. Perl -V, Valgrind, and GDB output are below. The
original testcase reads​:

f$x 1...888888888888888
g

hexdump​:
0000000 66 24 78 20 20 31 2e 2e 2e 38 38 38 38 38 38 38
0000020 38 38 38 38 38 38 38 38 0a 67 0a
0000033

A reduced version of this testcase reads​:

f$0 1..880000000000000g

hexdump​:
0000000 66 24 30 20 31 2e 2e 38 38 30 30 30 30 30 30 30
0000020 30 30 30 30 30 30 67
0000027

The attached fixes both of these for me.

Tony

@p5pRT
Copy link
Author

p5pRT commented Aug 11, 2015

From @tonycoz

0001-perl-125781-handle-range-overflow-when-Size_t-is-sma.patch
From ea697ae3ebfc94d365efb0e69a56c9b4f3ac44c0 Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Tue, 11 Aug 2015 15:49:37 +1000
Subject: [perl #125781] handle range overflow when Size_t is smaller than IV

---
 pp_ctl.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/pp_ctl.c b/pp_ctl.c
index cc6a55f..499e382 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -1206,7 +1206,11 @@ PP(pp_flop)
                     /* The wraparound of signed integers is undefined
                      * behavior, but here we aim for count >=1, and
                      * negative count is just wrong. */
-                    if (n < 1)
+                    if (n < 1
+#if IVSIZE > Size_t_size
+                        || n > SSize_t_MAX
+#endif
+                        )
                         overflow = TRUE;
                 }
                 if (overflow)
-- 
2.5.0

@p5pRT
Copy link
Author

p5pRT commented Aug 11, 2015

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

@p5pRT
Copy link
Author

p5pRT commented Aug 18, 2015

From @tonycoz

On Mon Aug 10 23​:13​:43 2015, tonyc wrote​:

On Mon Aug 10 07​:48​:19 2015, dcollinsn@​gmail.com wrote​:

While fuzzing the blead Perl binary (as a learning exercise), I found
a testcase that causes a segfault under -Duse64bitint but which works
fine (exits with an error but without receiving a fatal signal)
without 64bitint. Perl -V, Valgrind, and GDB output are below. The
original testcase reads​:

f$x 1...888888888888888
g

hexdump​:
0000000 66 24 78 20 20 31 2e 2e 2e 38 38 38 38 38 38 38
0000020 38 38 38 38 38 38 38 38 0a 67 0a
0000033

A reduced version of this testcase reads​:

f$0 1..880000000000000g

hexdump​:
0000000 66 24 30 20 31 2e 2e 38 38 30 30 30 30 30 30 30
0000020 30 30 30 30 30 30 67
0000027

The attached fixes both of these for me.

Applied as a1e2717.

Tony

@p5pRT p5pRT closed this as completed Aug 18, 2015
@p5pRT
Copy link
Author

p5pRT commented Aug 18, 2015

@tonycoz - Status changed from 'open' to 'resolved'

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

No branches or pull requests

1 participant