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

panic: reg_node overrun in unusual regular expression #14891

Closed
p5pRT opened this issue Sep 5, 2015 · 21 comments
Closed

panic: reg_node overrun in unusual regular expression #14891

p5pRT opened this issue Sep 5, 2015 · 21 comments

Comments

@p5pRT
Copy link

p5pRT commented Sep 5, 2015

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

Searchable as RT125990$

@p5pRT
Copy link
Author

p5pRT commented Sep 5, 2015

From @dcollinsn

Greetings Porters,

I have compiled bleadperl with the afl-gcc compiler using​:

./Configure -Dusedevel -Dprefix='/usr/local/perl-afl' -Dcc=afl-gcc -Duselongdouble -Duse64bitint -Doptimize=-g -Uversiononly -Uman1dir -Uman3dir -Dusethreads -des
AFL_HARDEN=1 make && make test

And then fuzzed the resulting binary using​:

AFL_NO_VAR_CHECK=1 afl-fuzz -i in -o out bin/perl @​@​

After reducing testcases using `afl-tmin` and filtering out testcases that are merely iterations of "#!perl -u", I have located the following testcase that triggers a panic in the perl interpreter. The testcase is the 62-byte binary file​: (octal bytes)

root@​nagios​:/usr/local/perl-afl/out# od -c allcrash/f2i000000
0000000 / \ N { } 0 0 0 0 0 0 0 0 337 337 337
0000020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0000040 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0000060 0 0 0 0 0 0 0 0 0 0 375 / i \n
0000076

When executed, the following bad things happen​:

panic​: reg_node overrun trying to emit 0, 8833280>=8833280 at test line 1.

The program exits cleanly, apart from the panic, so there is no backtrace for GDB to produce, and Valgrind finds no errors. The next bug I am about to submit is an even more esoteric version of this case which fails somewhat more spectacularly.

**PERL -V**

Summary of my perl5 (revision 5 version 23 subversion 3) configuration​:
  Commit id​: 9ae0115
  Platform​:
  osname=linux, osvers=2.6.32-5-686, archname=i686-linux-64int-ld-thread-multi
  uname='linux nagios 2.6.32-5-686 #1 smp tue may 13 16​:33​:32 utc 2014 i686 gnulinux '
  config_args='-Dusedevel -Dprefix=/usr/local/perl-afl -Dcc=afl-gcc -Duselongdouble -Duse64bitint -Doptimize=-g -Uversiononly -Uman1dir -Uman3dir -des'
  hint=previous, useposix=true, d_sigaction=define
  useithreads=define, usemultiplicity=define
  use64bitint=define, use64bitall=undef, uselongdouble=define
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='afl-gcc', ccflags ='-fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
  optimize='-g',
  cppflags='-fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'
  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 /usr/local/lib /usr/lib/gcc/i486-linux-gnu/4.4.5/include-fixed /usr/lib /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 -g -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_PRESERVE_IVUV
  PERL_USE_DEVEL USE_64_BIT_INT USE_ITHREADS
  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
  USE_REENTRANT_API
  Built under linux
  Compiled at Sep 2 2015 09​:16​:23
  @​INC​:
  /usr/local/perl-afl/lib/site_perl/5.23.3/i686-linux-64int-ld
  /usr/local/perl-afl/lib/site_perl/5.23.3
  /usr/local/perl-afl/lib/5.23.3/i686-linux-64int-ld
  /usr/local/perl-afl/lib/5.23.3
  /usr/local/perl-afl/lib/site_perl/5.23.2
  /usr/local/perl-afl/lib/site_perl
  .

@p5pRT
Copy link
Author

p5pRT commented Sep 5, 2015

From @dcollinsn

Greetings Porters,

I have compiled bleadperl with the afl-gcc compiler using​:

./Configure -Dusedevel -Dprefix='/usr/local/perl-afl' -Dcc=afl-gcc -Duselongdouble -Duse64bitint -Doptimize=-g -Uversiononly -Uman1dir -Uman3dir -Dusethreads -des
AFL_HARDEN=1 make && make test

And then fuzzed the resulting binary using​:

AFL_NO_VAR_CHECK=1 afl-fuzz -i in -o out bin/perl @​@​

After reducing testcases using `afl-tmin` and filtering out testcases that are merely iterations of "#!perl -u", I have located the following testcase that triggers a panic in the perl interpreter. The testcase is the 74-byte binary file​: (octal bytes)

root@​nagios​:/usr/local/perl-afl/out# od -c allcrash/f2i000000
0000000 / 0 0 0 0 0 0 0 0 0 \ N { } 0 0
0000020 0 0 0 0 0 337 337 0 337 337 337 337 337 0 0 0
0000040 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0000060 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0000100 0 0 0 0 0 0 0 375 / i
0000112

Attached as "f2i000000".

I'm reasonably certain that this is a duplicate of another bug, because I've seen the below sort of backtrace in a different bug, that also related to a "creative" regular expression. However, I can't find that bug. I'm also not sure if this is an upstream, because Perl is trying to croak here, and does so successfully under very similar circumstances.

When executed, the following bad things happen​:

root@​nagios​:/usr/local/perl-afl/out# ../bin/perl allcrash/f2i000000
*** glibc detected *** ../bin/perl​: free()​: invalid next size (normal)​: 0x0a3a2260 ***
======= Backtrace​: =========
/lib/i686/cmov/libc.so.6(+0x6af71)[0xb7619f71]
/lib/i686/cmov/libc.so.6(+0x6c7c8)[0xb761b7c8]
/lib/i686/cmov/libc.so.6(+0x703ba)[0xb761f3ba]
/lib/i686/cmov/libc.so.6(realloc+0xdd)[0xb761f97d]
../bin/perl(Perl_safesysrealloc+0xc8)[0x82d4ff8]
../bin/perl(Perl_sv_grow+0x4c4)[0x83dc5b4]
../bin/perl(Perl_sv_catpvn_flags+0x306)[0x83fbd76]
../bin/perl(Perl_sv_vcatpvfn_flags+0x4fea)[0x83ba5ea]
../bin/perl(Perl_sv_vsetpvfn+0xcb)[0x84047fb]
../bin/perl(Perl_vmess+0x13f)[0x82e35af]
../bin/perl(Perl_vcroak+0x98)[0x82ddf58]
../bin/perl(Perl_parse_unicode_opts+0x0)[0x82de1f0]
../bin/perl[0x82076df]
../bin/perl[0x826295c]
../bin/perl(Perl_re_op_compile+0x306a)[0x829873a]
../bin/perl(Perl_pmruntime+0x1380)[0x80d7580]
../bin/perl(Perl_yyparse+0x4593)[0x81d88b3]
../bin/perl[0x811467f]
../bin/perl(perl_parse+0x189f)[0x8117b1f]
../bin/perl(main+0x119)[0x80629d9]
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xb75c5ca6]
../bin/perl[0x8062821]
======= Memory map​: ========
08048000-0875c000 r-xp 00000000 08​:01 734611 /usr/local/perl-afl/bin/perl
0875c000-0875e000 rw-p 00713000 08​:01 734611 /usr/local/perl-afl/bin/perl
0a387000-0a3a8000 rw-p 00000000 00​:00 0 [heap]
b7300000-b7321000 rw-p 00000000 00​:00 0
b7321000-b7400000 ---p 00000000 00​:00 0
b741a000-b7437000 r-xp 00000000 08​:01 432483 /lib/libgcc_s.so.1
b7437000-b7438000 rw-p 0001c000 08​:01 432483 /lib/libgcc_s.so.1
b7438000-b75ad000 r--p 00000000 08​:01 99452 /usr/lib/locale/locale-archive
b75ad000-b75af000 rw-p 00000000 00​:00 0
b75af000-b76ef000 r-xp 00000000 08​:01 449158 /lib/i686/cmov/libc-2.11.3.so
b76ef000-b76f0000 ---p 00140000 08​:01 449158 /lib/i686/cmov/libc-2.11.3.so
b76f0000-b76f2000 r--p 00140000 08​:01 449158 /lib/i686/cmov/libc-2.11.3.so
b76f2000-b76f3000 rw-p 00142000 08​:01 449158 /lib/i686/cmov/libc-2.11.3.so
b76f3000-b76f6000 rw-p 00000000 00​:00 0
b76f6000-b76f8000 r-xp 00000000 08​:01 449149 /lib/i686/cmov/libutil-2.11.3.so
b76f8000-b76f9000 r--p 00001000 08​:01 449149 /lib/i686/cmov/libutil-2.11.3.so
b76f9000-b76fa000 rw-p 00002000 08​:01 449149 /lib/i686/cmov/libutil-2.11.3.so
b76fa000-b7703000 r-xp 00000000 08​:01 449143 /lib/i686/cmov/libcrypt-2.11.3.so
b7703000-b7704000 r--p 00008000 08​:01 449143 /lib/i686/cmov/libcrypt-2.11.3.so
b7704000-b7705000 rw-p 00009000 08​:01 449143 /lib/i686/cmov/libcrypt-2.11.3.so
b7705000-b772c000 rw-p 00000000 00​:00 0
b772c000-b7750000 r-xp 00000000 08​:01 449140 /lib/i686/cmov/libm-2.11.3.so
b7750000-b7751000 r--p 00023000 08​:01 449140 /lib/i686/cmov/libm-2.11.3.so
b7751000-b7752000 rw-p 00024000 08​:01 449140 /lib/i686/cmov/libm-2.11.3.so
b7752000-b7754000 r-xp 00000000 08​:01 449139 /lib/i686/cmov/libdl-2.11.3.so
b7754000-b7755000 r--p 00001000 08​:01 449139 /lib/i686/cmov/libdl-2.11.3.so
b7755000-b7756000 rw-p 00002000 08​:01 449139 /lib/i686/cmov/libdl-2.11.3.so
b7756000-b7757000 rw-p 00000000 00​:00 0
b7757000-b776a000 r-xp 00000000 08​:01 449142 /lib/i686/cmov/libnsl-2.11.3.so
b776a000-b776b000 r--p 00012000 08​:01 449142 /lib/i686/cmov/libnsl-2.11.3.so
b776b000-b776c000 rw-p 00013000 08​:01 449142 /lib/i686/cmov/libnsl-2.11.3.so
b776c000-b776e000 rw-p 00000000 00​:00 0
b776e000-b7783000 r-xp 00000000 08​:01 449148 /lib/i686/cmov/libpthread-2.11.3.so
b7783000-b7784000 r--p 00014000 08​:01 449148 /lib/i686/cmov/libpthread-2.11.3.so
b7784000-b7785000 rw-p 00015000 08​:01 449148 /lib/i686/cmov/libpthread-2.11.3.so
b7785000-b7787000 rw-p 00000000 00​:00 0
b7797000-b7799000 rw-p 00000000 00​:00 0
b7799000-b779a000 r-xp 00000000 00​:00 0 [vdso]
b779a000-b77b5000 r-xp 00000000 08​:01 432496 /lib/ld-2.11.3.so
b77b5000-b77b6000 r--p 0001b000 08​:01 432496 /lib/ld-2.11.3.so
b77b6000-b77b7000 rw-p 0001c000 08​:01 432496 /lib/ld-2.11.3.so
bf8b7000-bf8cc000 rw-p 00000000 00​:00 0 [stack]
Aborted

When Perl is instead configured with PERL_MALLOC_WRAP and DEBUGGING, or when the testcase is shortened by removing even one zero, an error such as the following appears, which I've reported as a separate bug, [perl #125990]

panic​: reg_node overrun trying to emit 0, a18b1fc>=a18b1f8 at test line 1.

**GDB**

(the above output, followed by...)
Program received signal SIGABRT, Aborted.
0xb7fe2424 in __kernel_vsyscall ()
(gdb) bt
#0 0xb7fe2424 in __kernel_vsyscall ()
#1 0xb7e22781 in *__GI_raise (sig=6)
  at ../nptl/sysdeps/unix/sysv/linux/raise.c​:64
#2 0xb7e25bb2 in *__GI_abort () at abort.c​:92
#3 0xb7e58e75 in __libc_message (do_abort=2,
  fmt=0xb7f1dbd8 "*** glibc detected *** %s​: %s​: 0x%s ***\n")
  at ../sysdeps/unix/sysv/linux/libc_fatal.c​:189
#4 0xb7e62f71 in malloc_printerr (action=<value optimized out>,
  str=0x6 <Address 0x6 out of bounds>, ptr=0x87792a0) at malloc.c​:6267
#5 0xb7e647c8 in _int_free (av=<value optimized out>, p=<value optimized out>)
  at malloc.c​:4795
#6 0xb7e683ba in _int_realloc (av=0x3464, oldp=0x8779268, oldsize=16, nb=48)
  at malloc.c​:5353
#7 0xb7e6897d in *__GI___libc_realloc (oldmem=0x8779270, bytes=44)
  at malloc.c​:3822
#8 0x082d4ff8 in Perl_safesysrealloc (where=0x6, size=0) at util.c​:270
#9 0x083dc5b4 in Perl_sv_grow (my_perl=0x875e008, sv=0x8771cd8, newlen=44)
  at sv.c​:1621
#10 0x083fbd76 in Perl_sv_catpvn_flags (my_perl=0x875e008, dsv=0x8771cd8,
  sstr=0x873cd0c "panic​: reg_node overrun trying to emit %d, %p>=%p",
  slen=39, flags=0) at sv.c​:5366
#11 0x083ba5ea in Perl_sv_vcatpvfn_flags (my_perl=0x875e008, sv=0x8771cd8,
  pat=0x873cd0c "panic​: reg_node overrun trying to emit %d, %p>=%p",
  patlen=49, args=0xbfffeca8, svargs=0x0, svmax=0, maybe_tainted=0x0,
---Type <return> to continue, or q <return> to quit---
  flags=<value optimized out>) at sv.c​:11245
#12 0x084047fb in Perl_sv_vsetpvfn (my_perl=0x875e008, sv=0x8771cd8,
  pat=0x873cd0c "panic​: reg_node overrun trying to emit %d, %p>=%p",
  patlen=49, args=0xbfffeca8, svargs=0x0, svmax=0, maybe_tainted=0x0)
  at sv.c​:10580
#13 0x082e35af in Perl_vmess (my_perl=0x875e008,
  pat=0x873cd0c "panic​: reg_node overrun trying to emit %d, %p>=%p",
  args=0xbfffeca8) at util.c​:1466
#14 0x082ddf58 in Perl_vcroak (my_perl=0x875e008, pat=0x0, args=0x6)
  at util.c​:1695
#15 0x082de1f0 in Perl_croak (my_perl=0x875e008,
  pat=0x873cd0c "panic​: reg_node overrun trying to emit %d, %p>=%p")
  at util.c​:1742
#16 0x082076df in S_regnode_guts (my_perl=<value optimized out>,
  pRExC_state=<value optimized out>, op=100 'd') at regcomp.c​:16400
#17 S_reg_node (my_perl=<value optimized out>,
  pRExC_state=<value optimized out>, op=100 'd') at regcomp.c​:16429
#18 0x0826295c in S_reg (my_perl=<value optimized out>,
  pRExC_state=0xbfffeff4, paren=<value optimized out>, flagp=0xbfffeefc,
  depth=1) at regcomp.c​:10596
#19 0x0829873a in Perl_re_op_compile (my_perl=0x875e008, patternp=0x0,
  pat_count=0, expr=0x877919c, eng=0x873f960, old_re=0x0, is_bare_re=0x0,
  orig_rx_flags=4, pm_flags=4) at regcomp.c​:6902
#20 0x080d7580 in Perl_pmruntime (my_perl=0x875e008, o=0x87791bc,
---Type <return> to continue, or q <return> to quit---
  expr=0x877919c, repl=0x0, isreg=true, floor=0) at op.c​:5579
#21 0x081d88b3 in Perl_yyparse (my_perl=0x875e008, gramtype=258)
  at perly.y​:1038
#22 0x0811467f in S_parse_body (my_perl=0x875e008, env=<value optimized out>,
  xsinit=<value optimized out>) at perl.c​:2296
#23 0x08117b1f in perl_parse (my_perl=0x875e008, xsinit=0x8062c90 <xs_init>,
  argc=2, argv=0xbffff4d4, env=0x0) at perl.c​:1626
#24 0x080629d9 in main (argc=2, argv=0xbffff4d4, env=0xbffff4e0)
  at perlmain.c​:114
(gdb)

**VALGRIND**

Valgrind seems to cause different behavior in this testcase, allowing Perl to panic rather than throw the glibc error above. Not sure how to get around that.

==9005== Memcheck, a memory error detector
==9005== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==9005== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==9005== Command​: ../bin/perl allcrash/f2i000000
==9005==
==9005== Invalid write of size 1
==9005== at 0x8289A46​: S_regpiece (regcomp.c​:12725)
==9005== by 0x8294A7E​: S_regbranch (regcomp.c​:10754)
==9005== by 0x825DFB0​: S_reg (regcomp.c​:10504)
==9005== by 0x8298739​: Perl_re_op_compile (regcomp.c​:6902)
==9005== by 0x80D757F​: Perl_pmruntime (op.c​:5579)
==9005== by 0x81D88B2​: Perl_yyparse (perly.y​:1038)
==9005== by 0x811467E​: S_parse_body (perl.c​:2296)
==9005== by 0x8117B1E​: perl_parse (perl.c​:1626)
==9005== by 0x80629D8​: main (perlmain.c​:114)
==9005== Address 0x4237164 is 0 bytes after a block of size 116 alloc'd
==9005== at 0x4023F50​: malloc (vg_replace_malloc.c​:236)
==9005== by 0x82D4537​: Perl_safesysmalloc (util.c​:149)
==9005== by 0x8297CC1​: Perl_re_op_compile (regcomp.c​:6752)
==9005== by 0x80D757F​: Perl_pmruntime (op.c​:5579)
==9005== by 0x81D88B2​: Perl_yyparse (perly.y​:1038)
==9005== by 0x811467E​: S_parse_body (perl.c​:2296)
==9005== by 0x8117B1E​: perl_parse (perl.c​:1626)
==9005== by 0x80629D8​: main (perlmain.c​:114)
==9005==
panic​: reg_node overrun trying to emit 0, 4237168>=4237164 at allcrash/f2i000000 line 1.
==9005==
==9005== HEAP SUMMARY​:
==9005== in use at exit​: 89,869 bytes in 582 blocks
==9005== total heap usage​: 757 allocs, 175 frees, 122,964 bytes allocated
==9005==
==9005== LEAK SUMMARY​:
==9005== definitely lost​: 6,243 bytes in 15 blocks
==9005== indirectly lost​: 83,626 bytes in 567 blocks
==9005== possibly lost​: 0 bytes in 0 blocks
==9005== still reachable​: 0 bytes in 0 blocks
==9005== suppressed​: 0 bytes in 0 blocks
==9005== Rerun with --leak-check=full to see details of leaked memory
==9005==
==9005== For counts of detected and suppressed errors, rerun with​: -v
==9005== ERROR SUMMARY​: 1 errors from 1 contexts (suppressed​: 25 from 8)

**BISECT**

First commit that crashes in this particular way is​:
commit 75697d6
Author​: Karl Williamson <khw@​cpan.org>
Date​: Sun Dec 21 22​:02​:30 2014 -0700

  Empty \N{} in regex pattern should force /d to /u
 
  \N{} is for Unicode names, even if the name is actually omitted.
  (Accepting an empty name is, I believe, an accident, and now is
  supported only for backwards compatibility.)

**PERL -V**

Summary of my perl5 (revision 5 version 23 subversion 3) configuration​:
  Commit id​: 9ae0115
  Platform​:
  osname=linux, osvers=2.6.32-5-686, archname=i686-linux-64int-ld-thread-multi
  uname='linux nagios 2.6.32-5-686 #1 smp tue may 13 16​:33​:32 utc 2014 i686 gnulinux '
  config_args='-Dusedevel -Dprefix=/usr/local/perl-afl -Dcc=afl-gcc -Duselongdouble -Duse64bitint -Doptimize=-g -Uversiononly -Uman1dir -Uman3dir -des'
  hint=previous, useposix=true, d_sigaction=define
  useithreads=define, usemultiplicity=define
  use64bitint=define, use64bitall=undef, uselongdouble=define
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='afl-gcc', ccflags ='-fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
  optimize='-g',
  cppflags='-fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fwrapv -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'
  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 /usr/local/lib /usr/lib/gcc/i486-linux-gnu/4.4.5/include-fixed /usr/lib /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 -g -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_PRESERVE_IVUV
  PERL_USE_DEVEL USE_64_BIT_INT USE_ITHREADS
  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
  USE_REENTRANT_API
  Built under linux
  Compiled at Sep 2 2015 09​:16​:23
  @​INC​:
  /usr/local/perl-afl/lib/site_perl/5.23.3/i686-linux-64int-ld
  /usr/local/perl-afl/lib/site_perl/5.23.3
  /usr/local/perl-afl/lib/5.23.3/i686-linux-64int-ld
  /usr/local/perl-afl/lib/5.23.3
  /usr/local/perl-afl/lib/site_perl/5.23.2
  /usr/local/perl-afl/lib/site_perl
  .

@p5pRT
Copy link
Author

p5pRT commented Sep 5, 2015

From @dcollinsn

f2i000000

@p5pRT
Copy link
Author

p5pRT commented Sep 7, 2015

From @tonycoz

On Fri Sep 04 17​:27​:40 2015, dcollinsn@​gmail.com wrote​:

root@​nagios​:/usr/local/perl-afl/out# od -c allcrash/f2i000000
0000000 / \ N { } 0 0 0 0 0 0 0 0 337 337
337
0000020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0
0000040 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0
0000060 0 0 0 0 0 0 0 0 0 0 375 / i \n
0000076

Could you attach this file please?

Thanks,
Tony

@p5pRT
Copy link
Author

p5pRT commented Sep 7, 2015

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

@p5pRT
Copy link
Author

p5pRT commented Sep 8, 2015

From @tonycoz

On Sun Sep 06 21​:20​:19 2015, tonyc wrote​:

On Fri Sep 04 17​:27​:40 2015, dcollinsn@​gmail.com wrote​:

root@​nagios​:/usr/local/perl-afl/out# od -c allcrash/f2i000000
0000000 / \ N { } 0 0 0 0 0 0 0 0 337 337
337
0000020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0
0000040 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0
0000060 0 0 0 0 0 0 0 0 0 0 375 / i \n
0000076

Could you attach this file please?

I ended up generating it, attached as 125990.pl.

The problem is len at line 12988 is different between pass 1 and pass 2, with values of 54 and 57.

This leads to a simplified reproducer​:

tony@​mars​:.../git/perl$ od -c ../125990b.pl
0000000 / \ N { } 337 337 337 375 / i \n
0000014

attached as 125990b.pl, which should be simpler to debug to find where the mismatch occurs (which I'll do tomorrow if someone else doesn't beat me to it.)

Tony

@p5pRT
Copy link
Author

p5pRT commented Sep 8, 2015

From @tonycoz

125990.pl

@p5pRT
Copy link
Author

p5pRT commented Sep 8, 2015

From @tonycoz

125990b.pl

@p5pRT
Copy link
Author

p5pRT commented Sep 8, 2015

From @tonycoz

On Mon Sep 07 23​:57​:17 2015, tonyc wrote​:

On Sun Sep 06 21​:20​:19 2015, tonyc wrote​:

On Fri Sep 04 17​:27​:40 2015, dcollinsn@​gmail.com wrote​:

root@​nagios​:/usr/local/perl-afl/out# od -c allcrash/f2i000000
0000000 / \ N { } 0 0 0 0 0 0 0 0 337 337
337
0000020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0
0000040 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0
0000060 0 0 0 0 0 0 0 0 0 0 375 / i \n
0000076

Could you attach this file please?

I ended up generating it, attached as 125990.pl.

RT seems to have attached the same content for both files. Trying 125990.pl again.

Tony

@p5pRT
Copy link
Author

p5pRT commented Sep 8, 2015

From @tonycoz

125990.pl

@p5pRT
Copy link
Author

p5pRT commented Sep 8, 2015

From @khwilliamson

This is likely from my code, so I'm taking the ticket to look at it.

On 09/08/2015 12​:58 AM, Tony Cook via RT wrote​:

On Mon Sep 07 23​:57​:17 2015, tonyc wrote​:

On Sun Sep 06 21​:20​:19 2015, tonyc wrote​:

On Fri Sep 04 17​:27​:40 2015, dcollinsn@​gmail.com wrote​:

root@​nagios​:/usr/local/perl-afl/out# od -c allcrash/f2i000000
0000000 / \ N { } 0 0 0 0 0 0 0 0 337 337
337
0000020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0
0000040 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0
0000060 0 0 0 0 0 0 0 0 0 0 375 / i \n
0000076

Could you attach this file please?

I ended up generating it, attached as 125990.pl.

RT seems to have attached the same content for both files. Trying 125990.pl again.

Tony

---
via perlbug​: queue​: perl5 status​: open
https://rt-archive.perl.org/perl5/Ticket/Display.html?id=125990

@p5pRT
Copy link
Author

p5pRT commented Sep 8, 2015

From @tonycoz

On Fri Sep 04 17​:28​:18 2015, dcollinsn@​gmail.com wrote​:

Greetings Porters,

I have compiled bleadperl with the afl-gcc compiler using​:

./Configure -Dusedevel -Dprefix='/usr/local/perl-afl' -Dcc=afl-gcc
-Duselongdouble -Duse64bitint -Doptimize=-g -Uversiononly -Uman1dir
-Uman3dir -Dusethreads -des
AFL_HARDEN=1 make && make test

And then fuzzed the resulting binary using​:

AFL_NO_VAR_CHECK=1 afl-fuzz -i in -o out bin/perl @​@​

After reducing testcases using `afl-tmin` and filtering out testcases
that are merely iterations of "#!perl -u", I have located the
following testcase that triggers a panic in the perl interpreter. The
testcase is the 74-byte binary file​: (octal bytes)

root@​nagios​:/usr/local/perl-afl/out# od -c allcrash/f2i000000
0000000 / 0 0 0 0 0 0 0 0 0 \ N { } 0
0
0000020 0 0 0 0 0 337 337 0 337 337 337 337 337 0 0
0
0000040 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0
0000060 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0
0000100 0 0 0 0 0 0 0 375 / i
0000112

I strongly suspect this is the same bug as 125990.

The base case of 125990 has enough ß (ss) characters for the generated string to take up the space for one extra regnode over the calculated length, the case in this ticket overflows even further.

Your case doesn't produce an error (even with valgrind) on my 64-bit system, but a modified (and shorter version) can be made to​:

tony@​mars​:.../git/perl$ od -c ../125991b.pl
0000000 / \ N { } 337 337 337 337 337 337 337 337 337 337 337
0000020 375 / i
0000023

though it's only errors for me with valgrind.

I'm reasonably certain that this is a duplicate of another bug,
because I've seen the below sort of backtrace in a different bug, that
also related to a "creative" regular expression. However, I can't find
that bug. I'm also not sure if this is an upstream, because Perl is
trying to croak here, and does so successfully under very similar
circumstances.

When executed, the following bad things happen​:

root@​nagios​:/usr/local/perl-afl/out# ../bin/perl allcrash/f2i000000
*** glibc detected *** ../bin/perl​: free()​: invalid next size
(normal)​: 0x0a3a2260 ***
======= Backtrace​: =========
/lib/i686/cmov/libc.so.6(+0x6af71)[0xb7619f71]
/lib/i686/cmov/libc.so.6(+0x6c7c8)[0xb761b7c8]
/lib/i686/cmov/libc.so.6(+0x703ba)[0xb761f3ba]
/lib/i686/cmov/libc.so.6(realloc+0xdd)[0xb761f97d]
../bin/perl(Perl_safesysrealloc+0xc8)[0x82d4ff8]
../bin/perl(Perl_sv_grow+0x4c4)[0x83dc5b4]
../bin/perl(Perl_sv_catpvn_flags+0x306)[0x83fbd76]
...

I expect this is caused by the buffer overflow from the above corrupting the malloc() arena.

**BISECT**

First commit that crashes in this particular way is​:
commit 75697d6
Author​: Karl Williamson <khw@​cpan.org>
Date​: Sun Dec 21 22​:02​:30 2014 -0700

Empty \N{} in regex pattern should force /d to /u

\N{} is for Unicode names, even if the name is actually omitted.
(Accepting an empty name is, I believe, an accident, and now is
supported only for backwards compatibility.)

While in this case it's \N{} forcing the regexp to be unicode, other mechanisms can cause it too​:

tony@​mars​:.../git/perl$ od -c ../125991c.pl
0000000 / \ p A 337 337 337 337 337 337 337 337 337 337 337 375
0000020 / i
0000022

Tony

@p5pRT
Copy link
Author

p5pRT commented Sep 8, 2015

From @tonycoz

125991b.pl

@p5pRT
Copy link
Author

p5pRT commented Sep 8, 2015

From @tonycoz

125991c.pl

@p5pRT
Copy link
Author

p5pRT commented Sep 8, 2015

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

@p5pRT
Copy link
Author

p5pRT commented Sep 8, 2015

From @tonycoz

On Tue Sep 08 08​:04​:55 2015, public@​khwilliamson.com wrote​:

This is likely from my code, so I'm taking the ticket to look at it.

Ok, 125991 looks like the same bug (but a larger overflow that corrupts the memory arena).

Tony

@p5pRT
Copy link
Author

p5pRT commented Sep 9, 2015

From @khwilliamson

Thanks for finding this.

I have figured out the cause, and am now contemplating the best solution. Tony Cook was correct that #125990 and #125991 are from the same cause, and so I have merged the two tickets.

This bug arises when a pattern is compiled under /id rules, has a ß in it, and has something else in it, such as a \p or a \N{}, that causes it to switch to /iu rules. The latter will try to fold the ß to 'ss', the former does not. Thus the latter takes up 2 bytes and the former takes up 1. The sizing pass is done under /id rules, and the allocation pass is done under /iu, so the space allocated is less than the space actually used, and you get the problem.

Anything under compiled under 'use 5.012' or higher or 'use utf8' is by default compiled with /u rules, so this bug won't likely appear in such code. One would have to explicitly say /d to override the default; this is unlikely.


Karl Williamson

@p5pRT
Copy link
Author

p5pRT commented Sep 11, 2015

From @khwilliamson

Fixed by commit 512c0f5 whose message is below​:

  This is a result of a design flaw that I introduced in earlier releases
  when attempting to fix earlier design flaws in dealing with the outlier
  character ß, LATIN SMALL LETTER SHARP S. The uppercase of this letter
  is SS, so that when comparing case-insensitively, it should match 'ss',
  and hence, in Unicode terminology, it folds to 'ss'. This character is
  the only one representable without using UTF-8 whose fold is longer than
  1 byte, and so has to have special treatment. Similarly, the sequence
  'ss' can match caselessly the single byte ß, and this is the only such
  sequence that can match something shorter than it, unless UTF-8 is
  involved. The matter is complicated by the fact that under /di rules,
  the ß and 'ss' don't match each other, unless the target string is in
  UTF-8. The solution I used earlier (and continue to use) was to create
  a special regnode EXACTFU_SS under /ui rules, in which any ß is folded
  to 'ss'. But under /di rules, a regular EXACTF regnode is used, and any
  ß is retained as-is.
 
  The problem reported here arises when something during the sizing pass
  tells perl to use /ui rules rather than the /di rules that were in
  effect at the beginning. Recall that perl uses /d rules, for backward
  compatibility, unless something overrides them. This can be a 'use'
  declaration, an explicit character set pattern modifier, or something in
  the pattern. This bug happens only with the final case. There are
  several Unicode-defined constructs that can occur in patterns; if one is
  found, the perl interpreter infers that Unicode is desired, and switches
  from /d to /u for the whole pattern. Two such constructs are a Unicode
  property, \p{}, and a Unicode named character, \N{}. The
  problem-reproducing code for this ticket uses the latter.
 
  The problem was that the switch from /di to /ui was deferred until AFTER
  the sizing pass. (A flag was set when one of these constructs was
  encountered to tell the parser to later do the switch.)
 
  During the second pass, the code realizes it is under /ui, so creates an
  EXACTFU_SS node and folds the ß into 'ss'. But the first pass thought
  it was under /di, so it sized for just the ß, i.e., for 1 byte, so we
  exceed the allocated space and do a wild write. This may not cause a
  problem if the malloc'd space had rounded-up and there were only a few
  of these ß characters.
 
  One solution I considered was just keeping a global count of the ß
  characters in EXACTF nodes. One could just add these to the space
  reserved if /ui rules ended up being used. The problem with this is that
  nodes that are near their maximum size without the extra space could
  exceed it with, and thus have to be split into 2 nodes, and the extra
  node would have an unplanned-for header, taking up more unaccounted-for
  space. So that doesn't work. One could also just reserve two bytes for
  every ß in an EXACTF node, thus wasting space unless /ui ends up being
  used. But the bigger problem is that the code that splits nodes would
  have to be made more complicated. It has to find a suitable splitting
  spot, by searching through the text of the node, and now it would have
  to deal with some of that space not being set.
 
  Instead, I opted to change the code so that when it finds one of these
  Unicode-defined constructs, it switches to /u immediately during the
  sizing pass. That means that the parse afterwards knows that it is /u
  and allocates the correct space. (We now have to remain in /u for the
  remainder of the pass, so some code had to change that reverted this.)
  This fixes the test case in the ticket. But there remains a problem if
  the sizing has happened earlier in the parse before the construct that
  changes from /d to /u is encountered. Like​:
 
  qr/.....ß....\N{}/di
 
  The incorrect sizing has already happened by the time the \N{} is
  encountered. One could solve this by restarting the parse whenever the
  /d goes to /u (under /i, as this issue isn't a problem except when
  folding ß). That slows things down. Instead, I opted to set a global
  flag whenever a ß is found in an EXACTF node. If that flag isn't set at
  the time of the /d to /u switch, there's no need to restart the parse.
 
  A 'use utf8' or 'use 5.012' or higher selects /u over /d, so the problem
  did not happen with them, nor if the pattern has to be converted to
  UTF-8, which restarts the sizing pass, and it only happens with the
  sharp s character. And probably unless there a several ß characters,
  the rounding-up of malloc space, would cause this to not be an issue.
  These explain why this hasn't been reported from the field.
--
Karl Williamson

@p5pRT
Copy link
Author

p5pRT commented Sep 11, 2015

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

@p5pRT
Copy link
Author

p5pRT commented May 13, 2016

From @khwilliamson

Thank you for submitting this report. You have helped make Perl better.
 
With the release of Perl 5.24.0 on May 9, 2016, this and 149 other issues have been resolved.

Perl 5.24.0 may be downloaded via https://metacpan.org/release/RJBS/perl-5.24.0

@p5pRT
Copy link
Author

p5pRT commented May 13, 2016

@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
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant