Skip Menu |
Report information
Id: 125781
Status: resolved
Priority: 0/
Queue: perl5

Owner: Nobody
Requestors: dcollinsn [at] gmail.com
Cc:
AdminCc:

Operating System: (no value)
PatchStatus: (no value)
Severity: low
Type: unknown
Perl Version: (no value)
Fixed In: (no value)

Attachments
0001-perl-125781-handle-range-overflow-when-Size_t-is-sma.patch



Subject: Segmentation fault in Perl 5.23.2 while fuzzing Perl binary
Download (untitled) / with headers
text/plain 10.3k
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: ef00320bc9879f8f099601e89cecb3a191f372f6 is the first bad commit commit ef00320bc9879f8f099601e89cecb3a191f372f6 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 a953aca586d48d6f0b2c4db3572de328ed6d85e8 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: 749f0eb1485a7bb7561d71f9539d9b7655363136 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
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 757b
On Mon Aug 10 07:48:19 2015, dcollinsn@gmail.com wrote: Show quoted text
> 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
Subject: 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
RT-Send-CC: perl5-porters [...] perl.org
Download (untitled) / with headers
text/plain 904b
On Mon Aug 10 23:13:43 2015, tonyc wrote: Show quoted text
> 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 a1e27170fc118bb226e97988b42fb9a970689740. Tony


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

For issues related to this RT instance (aka "perlbug"), please contact perlbug-admin at perl.org