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

7-byte file causes Perl 5.21.8 to segfault #14401

Closed
p5pRT opened this issue Jan 6, 2015 · 29 comments
Closed

7-byte file causes Perl 5.21.8 to segfault #14401

p5pRT opened this issue Jan 6, 2015 · 29 comments

Comments

@p5pRT
Copy link

p5pRT commented Jan 6, 2015

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

Searchable as RT123554$

@p5pRT
Copy link
Author

p5pRT commented Jan 5, 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/fuzzer01/crashes$ /home/geeknik/perl5/perl
id\​:000001\,sig\​:11\,src\​:009058\,op\​:flip1\,pos\​:37
Bareword found where operator expected at
id​:000001,sig​:11,src​:009058,op​:flip1,pos​:37 line 1, near "3333333333epl"
(Missing operator before epl?)
Segmentation fault (core dumped)
geeknik@​deb7fuzz​:~/findings/perl/fuzzer01/crashes$ valgrind -q
/home/geeknik/perl5/perl
id\​:000001\,sig\​:11\,src\​:009058\,op\​:flip1\,pos\​:37
Bareword found where operator expected at
id​:000001,sig​:11,src​:009058,op​:flip1,pos​:37 line 1, near "3333333333epl"
(Missing operator before epl?)
==6718== Invalid write of size 1
==6718== at 0x4C2A7C8​: memcpy (mc_replace_strmem.c​:838)
==6718== by 0x6DDF9A​: Perl_repeatcpy (string3.h​:52)
==6718== by 0x84DF7B​: Perl_pp_repeat (pp.c​:1759)
==6718== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==6718== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==6718== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==6718== by 0x4F3114​: perl_parse (perl.c​:2273)
==6718== by 0x42A92B​: main (perlmain.c​:114)
==6718== Address 0x5edec91 is 7 bytes after a block of size 10 alloc'd
==6718== at 0x4C28BED​: malloc (vg_replace_malloc.c​:263)
==6718== by 0x6CEFBC​: Perl_safesysmalloc (util.c​:144)
==6718== by 0x7EDB8F​: Perl_sv_grow (sv.c​:1623)
==6718== by 0x7FCCBF​: Perl_sv_2pv_flags (sv.c​:3095)
==6718== by 0x81754D​: Perl_sv_pvn_force_flags (sv.c​:9861)
==6718== by 0x84E526​: Perl_pp_repeat (pp.c​:1748)
==6718== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==6718== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==6718== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==6718== by 0x4F3114​: perl_parse (perl.c​:2273)
==6718== by 0x42A92B​: main (perlmain.c​:114)
==6718==
==6718== Invalid write of size 2
==6718== at 0x4C2A846​: memcpy (mc_replace_strmem.c​:838)
==6718== by 0x6DDF9A​: Perl_repeatcpy (string3.h​:52)
==6718== by 0x84DF7B​: Perl_pp_repeat (pp.c​:1759)
==6718== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==6718== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==6718== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==6718== by 0x4F3114​: perl_parse (perl.c​:2273)
==6718== by 0x42A92B​: main (perlmain.c​:114)
==6718== Address 0x5edec8e is 4 bytes after a block of size 10 alloc'd
==6718== at 0x4C28BED​: malloc (vg_replace_malloc.c​:263)
==6718== by 0x6CEFBC​: Perl_safesysmalloc (util.c​:144)
==6718== by 0x7EDB8F​: Perl_sv_grow (sv.c​:1623)
==6718== by 0x7FCCBF​: Perl_sv_2pv_flags (sv.c​:3095)
==6718== by 0x81754D​: Perl_sv_pvn_force_flags (sv.c​:9861)
==6718== by 0x84E526​: Perl_pp_repeat (pp.c​:1748)
==6718== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==6718== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==6718== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==6718== by 0x4F3114​: perl_parse (perl.c​:2273)
==6718== by 0x42A92B​: main (perlmain.c​:114)
==6718==
==6718== Invalid read of size 1
==6718== at 0x4C2A7C1​: memcpy (mc_replace_strmem.c​:838)
==6718== by 0x6DDF9A​: Perl_repeatcpy (string3.h​:52)
==6718== by 0x84DF7B​: Perl_pp_repeat (pp.c​:1759)
==6718== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==6718== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==6718== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==6718== by 0x4F3114​: perl_parse (perl.c​:2273)
==6718== by 0x42A92B​: main (perlmain.c​:114)
==6718== Address 0x5edec91 is 7 bytes after a block of size 10 alloc'd
==6718== at 0x4C28BED​: malloc (vg_replace_malloc.c​:263)
==6718== by 0x6CEFBC​: Perl_safesysmalloc (util.c​:144)
==6718== by 0x7EDB8F​: Perl_sv_grow (sv.c​:1623)
==6718== by 0x7FCCBF​: Perl_sv_2pv_flags (sv.c​:3095)
==6718== by 0x81754D​: Perl_sv_pvn_force_flags (sv.c​:9861)
==6718== by 0x84E526​: Perl_pp_repeat (pp.c​:1748)
==6718== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==6718== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==6718== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==6718== by 0x4F3114​: perl_parse (perl.c​:2273)
==6718== by 0x42A92B​: main (perlmain.c​:114)
==6718==
==6718== Invalid read of size 8
==6718== at 0x4C2A7E8​: memcpy (mc_replace_strmem.c​:838)
==6718== by 0x6DDF9A​: Perl_repeatcpy (string3.h​:52)
==6718== by 0x84DF7B​: Perl_pp_repeat (pp.c​:1759)
==6718== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==6718== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==6718== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==6718== by 0x4F3114​: perl_parse (perl.c​:2273)
==6718== by 0x42A92B​: main (perlmain.c​:114)
==6718== Address 0x5edec88 is 8 bytes inside a block of size 10 alloc'd
==6718== at 0x4C28BED​: malloc (vg_replace_malloc.c​:263)
==6718== by 0x6CEFBC​: Perl_safesysmalloc (util.c​:144)
==6718== by 0x7EDB8F​: Perl_sv_grow (sv.c​:1623)
==6718== by 0x7FCCBF​: Perl_sv_2pv_flags (sv.c​:3095)
==6718== by 0x81754D​: Perl_sv_pvn_force_flags (sv.c​:9861)
==6718== by 0x84E526​: Perl_pp_repeat (pp.c​:1748)
==6718== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==6718== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==6718== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==6718== by 0x4F3114​: perl_parse (perl.c​:2273)
==6718== by 0x42A92B​: main (perlmain.c​:114)
==6718==
==6718== Invalid write of size 8
==6718== at 0x4C2A7ED​: memcpy (mc_replace_strmem.c​:838)
==6718== by 0x6DDF9A​: Perl_repeatcpy (string3.h​:52)
==6718== by 0x84DF7B​: Perl_pp_repeat (pp.c​:1759)
==6718== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==6718== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==6718== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==6718== by 0x4F3114​: perl_parse (perl.c​:2273)
==6718== by 0x42A92B​: main (perlmain.c​:114)
==6718== Address 0x5edec98 is 14 bytes after a block of size 10 alloc'd
==6718== at 0x4C28BED​: malloc (vg_replace_malloc.c​:263)
==6718== by 0x6CEFBC​: Perl_safesysmalloc (util.c​:144)
==6718== by 0x7EDB8F​: Perl_sv_grow (sv.c​:1623)
==6718== by 0x7FCCBF​: Perl_sv_2pv_flags (sv.c​:3095)
==6718== by 0x81754D​: Perl_sv_pvn_force_flags (sv.c​:9861)
==6718== by 0x84E526​: Perl_pp_repeat (pp.c​:1748)
==6718== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==6718== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==6718== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==6718== by 0x4F3114​: perl_parse (perl.c​:2273)
==6718== by 0x42A92B​: main (perlmain.c​:114)
==6718==
==6718== Invalid read of size 8
==6718== at 0x4C2A7FA​: memcpy (mc_replace_strmem.c​:838)
==6718== by 0x6DDF9A​: Perl_repeatcpy (string3.h​:52)
==6718== by 0x84DF7B​: Perl_pp_repeat (pp.c​:1759)
==6718== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==6718== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==6718== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==6718== by 0x4F3114​: perl_parse (perl.c​:2273)
==6718== by 0x42A92B​: main (perlmain.c​:114)
==6718== Address 0x5edec88 is 8 bytes inside a block of size 10 alloc'd
==6718== at 0x4C28BED​: malloc (vg_replace_malloc.c​:263)
==6718== by 0x6CEFBC​: Perl_safesysmalloc (util.c​:144)
==6718== by 0x7EDB8F​: Perl_sv_grow (sv.c​:1623)
==6718== by 0x7FCCBF​: Perl_sv_2pv_flags (sv.c​:3095)
==6718== by 0x81754D​: Perl_sv_pvn_force_flags (sv.c​:9861)
==6718== by 0x84E526​: Perl_pp_repeat (pp.c​:1748)
==6718== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==6718== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==6718== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==6718== by 0x4F3114​: perl_parse (perl.c​:2273)
==6718== by 0x42A92B​: main (perlmain.c​:114)
==6718==
==6718==
==6718== Process terminating with default action of signal 11 (SIGSEGV)​:
dumping core
==6718== Access not within mapped region at address 0x62DEC81
==6718== at 0x4C2A7C8​: memcpy (mc_replace_strmem.c​:838)
==6718== by 0x6DDF9A​: Perl_repeatcpy (string3.h​:52)
==6718== by 0x84DF7B​: Perl_pp_repeat (pp.c​:1759)
==6718== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==6718== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==6718== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==6718== by 0x4F3114​: perl_parse (perl.c​:2273)
==6718== by 0x42A92B​: main (perlmain.c​:114)
==6718== If you believe this happened as a result of a stack
==6718== overflow in your program's main thread (unlikely but
==6718== possible), you can try to increase the size of the
==6718== main thread stack using the --main-stacksize= flag.
==6718== The main thread stack size used in this run was 8388608.
Segmentation fault

geeknik@​deb7fuzz​:~/findings/perl/fuzzer01/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 63197]

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​:000001,sig​:11,src​:009058,op​:flip1,pos​:37'.
Program terminated with signal 11, Segmentation fault.
#0 __memcpy_ssse3_back ()
  at ../sysdeps/x86_64/multiarch/memcpy-ssse3-back.S​:199
199 ../sysdeps/x86_64/multiarch/memcpy-ssse3-back.S​: No such file or
directory.
(gdb) bt
#0 __memcpy_ssse3_back ()
  at ../sysdeps/x86_64/multiarch/memcpy-ssse3-back.S​:199
#1 0x00000000006ddf9b in memcpy (__len=65536, __src=0x134ab02,
  __dest=<optimized out>) at
/usr/include/x86_64-linux-gnu/bits/string3.h​:52
#2 Perl_repeatcpy (to=0x134ab02 '3' <repeats 200 times>...,
  from=0x134ab00 '3' <repeats 200 times>..., len=2,
  count=9223372036854775806) at util.c​:3107
#3 0x000000000084df7c in Perl_pp_repeat () at pp.c​:1759
#4 0x000000000077b87b in Perl_runops_standard () at run.c​:41
#5 0x000000000045ac0e in S_fold_constants (o=0x134aa30) at op.c​:4343
#6 0x00000000005ca051 in Perl_yyparse (gramtype=<optimized out>)
  at perly.y​:769
#7 0x00000000004f3115 in S_parse_body (xsinit=0x42ad20 <xs_init>, env=0x0)
  at perl.c​:2273
#8 perl_parse (my_perl=<optimized out>, xsinit=0x42ad20 <xs_init>,
  argc=<optimized out>, argv=<optimized out>, env=0x0) at perl.c​:1607
#9 0x000000000042a92c in main (argc=2, argv=0x7fffd50cd148,
  env=0x7fffd50cd160) at perlmain.c​:114
#10 0x00007f44c7d86ead 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=0x7fffd50cd138)
  at libc-start.c​:244
#11 0x000000000042ac45 in _start ()
(gdb) i r
rax 0x135ab02 20294402
rbx 0x136ab02 20359938
rcx 0x10000 65536
rdx 0xff7e 65406
rsi 0x135ab00 20294400
rdi 0x136ab00 20359936
rbp 0x134ab02 0x134ab02
rsp 0x7fffd50cca58 0x7fffd50cca58
r8 0x136aaf2 20359922
r9 0x0 0
r10 0x134ab08 20228872
r11 0x7f44c7ebe3f0 139933388628976
r12 0x2 2
r13 0x10000 65536
r14 0x3fffffffffffffff 4611686018427387903
r15 0x10000 65536
rip 0x7f44c7e91c3b 0x7f44c7e91c3b <__memcpy_ssse3_back+427>
eflags 0x10206 [ PF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb)

hexdump id\​:000001\,sig\​:11\,src\​:009058\,op\​:flip1\,pos\​:37.gz
0000000 8b1f 0808 6aac 54aa 0300 6469 303a 3030
0000010 3030 2c31 6973 3a67 3131 732c 6372 303a
0000020 3930 3530 2c38 706f 663a 696c 3170 702c
0000030 736f 333a 0037 3633 0226 1b58 571b 21d4
0000040 a9b8 3905 2509 fa1a fa6a f94a ffff 16a7
0000050 9429 26a7 a429 25e6 a7e7 fffc c0df 9310
0000060 64a7 05cd 3200 1f6b 5675 0000 0000
000006d

@p5pRT
Copy link
Author

p5pRT commented Jan 5, 2015

From @geeknik

core.gz

@p5pRT
Copy link
Author

p5pRT commented Jan 5, 2015

@p5pRT
Copy link
Author

p5pRT commented Jan 6, 2015

From @geeknik

I'm still fuzzing a Perl binary that I built from git source on 01/02/2015
using the afl-gcc (http​://lcamtuf.coredump.cx/afl/) 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 a 7-byte test case which causes a
segfault (and possible stack overflow).

geeknik@​deb7fuzz​:~/findings/perl/fuzzer04/crashes$ /home/geeknik/perl5/perl
id\​:000291\,sig\​:11\,src\​:008346\,op\​:havoc\,rep\​:16
Segmentation fault (core dumped)

geeknik@​deb7fuzz​:~/findings/perl/fuzzer04/crashes$ valgrind -q
/home/geeknik/perl5/perl
id\​:000291\,sig\​:11\,src\​:008346\,op\​:havoc\,rep\​:16
==58205== Invalid write of size 1
==58205== at 0x4C2A7C8​: memcpy (mc_replace_strmem.c​:838)
==58205== by 0x6DDF9A​: Perl_repeatcpy (string3.h​:52)
==58205== by 0x84DF7B​: Perl_pp_repeat (pp.c​:1759)
==58205== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==58205== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==58205== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==58205== by 0x4F3114​: perl_parse (perl.c​:2273)
==58205== by 0x42A92B​: main (perlmain.c​:114)
==58205== Address 0x5edc1a1 is 7 bytes after a block of size 10 alloc'd
==58205== at 0x4C28BED​: malloc (vg_replace_malloc.c​:263)
==58205== by 0x6CEFBC​: Perl_safesysmalloc (util.c​:144)
==58205== by 0x7EDB8F​: Perl_sv_grow (sv.c​:1623)
==58205== by 0x7FCCBF​: Perl_sv_2pv_flags (sv.c​:3095)
==58205== by 0x81754D​: Perl_sv_pvn_force_flags (sv.c​:9861)
==58205== by 0x84E526​: Perl_pp_repeat (pp.c​:1748)
==58205== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==58205== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==58205== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==58205== by 0x4F3114​: perl_parse (perl.c​:2273)
==58205== by 0x42A92B​: main (perlmain.c​:114)
==58205==
==58205== Invalid write of size 2
==58205== at 0x4C2A846​: memcpy (mc_replace_strmem.c​:838)
==58205== by 0x6DDF9A​: Perl_repeatcpy (string3.h​:52)
==58205== by 0x84DF7B​: Perl_pp_repeat (pp.c​:1759)
==58205== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==58205== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==58205== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==58205== by 0x4F3114​: perl_parse (perl.c​:2273)
==58205== by 0x42A92B​: main (perlmain.c​:114)
==58205== Address 0x5edc19e is 4 bytes after a block of size 10 alloc'd
==58205== at 0x4C28BED​: malloc (vg_replace_malloc.c​:263)
==58205== by 0x6CEFBC​: Perl_safesysmalloc (util.c​:144)
==58205== by 0x7EDB8F​: Perl_sv_grow (sv.c​:1623)
==58205== by 0x7FCCBF​: Perl_sv_2pv_flags (sv.c​:3095)
==58205== by 0x81754D​: Perl_sv_pvn_force_flags (sv.c​:9861)
==58205== by 0x84E526​: Perl_pp_repeat (pp.c​:1748)
==58205== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==58205== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==58205== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==58205== by 0x4F3114​: perl_parse (perl.c​:2273)
==58205== by 0x42A92B​: main (perlmain.c​:114)
==58205==
==58205== Invalid read of size 1
==58205== at 0x4C2A7C1​: memcpy (mc_replace_strmem.c​:838)
==58205== by 0x6DDF9A​: Perl_repeatcpy (string3.h​:52)
==58205== by 0x84DF7B​: Perl_pp_repeat (pp.c​:1759)
==58205== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==58205== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==58205== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==58205== by 0x4F3114​: perl_parse (perl.c​:2273)
==58205== by 0x42A92B​: main (perlmain.c​:114)
==58205== Address 0x5edc1a1 is 7 bytes after a block of size 10 alloc'd
==58205== at 0x4C28BED​: malloc (vg_replace_malloc.c​:263)
==58205== by 0x6CEFBC​: Perl_safesysmalloc (util.c​:144)
==58205== by 0x7EDB8F​: Perl_sv_grow (sv.c​:1623)
==58205== by 0x7FCCBF​: Perl_sv_2pv_flags (sv.c​:3095)
==58205== by 0x81754D​: Perl_sv_pvn_force_flags (sv.c​:9861)
==58205== by 0x84E526​: Perl_pp_repeat (pp.c​:1748)
==58205== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==58205== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==58205== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==58205== by 0x4F3114​: perl_parse (perl.c​:2273)
==58205== by 0x42A92B​: main (perlmain.c​:114)
==58205==
==58205== Invalid read of size 8
==58205== at 0x4C2A7E8​: memcpy (mc_replace_strmem.c​:838)
==58205== by 0x6DDF9A​: Perl_repeatcpy (string3.h​:52)
==58205== by 0x84DF7B​: Perl_pp_repeat (pp.c​:1759)
==58205== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==58205== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==58205== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==58205== by 0x4F3114​: perl_parse (perl.c​:2273)
==58205== by 0x42A92B​: main (perlmain.c​:114)
==58205== Address 0x5edc198 is 8 bytes inside a block of size 10 alloc'd
==58205== at 0x4C28BED​: malloc (vg_replace_malloc.c​:263)
==58205== by 0x6CEFBC​: Perl_safesysmalloc (util.c​:144)
==58205== by 0x7EDB8F​: Perl_sv_grow (sv.c​:1623)
==58205== by 0x7FCCBF​: Perl_sv_2pv_flags (sv.c​:3095)
==58205== by 0x81754D​: Perl_sv_pvn_force_flags (sv.c​:9861)
==58205== by 0x84E526​: Perl_pp_repeat (pp.c​:1748)
==58205== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==58205== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==58205== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==58205== by 0x4F3114​: perl_parse (perl.c​:2273)
==58205== by 0x42A92B​: main (perlmain.c​:114)
==58205==
==58205== Invalid write of size 8
==58205== at 0x4C2A7ED​: memcpy (mc_replace_strmem.c​:838)
==58205== by 0x6DDF9A​: Perl_repeatcpy (string3.h​:52)
==58205== by 0x84DF7B​: Perl_pp_repeat (pp.c​:1759)
==58205== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==58205== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==58205== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==58205== by 0x4F3114​: perl_parse (perl.c​:2273)
==58205== by 0x42A92B​: main (perlmain.c​:114)
==58205== Address 0x5edc1a8 is 14 bytes after a block of size 10 alloc'd
==58205== at 0x4C28BED​: malloc (vg_replace_malloc.c​:263)
==58205== by 0x6CEFBC​: Perl_safesysmalloc (util.c​:144)
==58205== by 0x7EDB8F​: Perl_sv_grow (sv.c​:1623)
==58205== by 0x7FCCBF​: Perl_sv_2pv_flags (sv.c​:3095)
==58205== by 0x81754D​: Perl_sv_pvn_force_flags (sv.c​:9861)
==58205== by 0x84E526​: Perl_pp_repeat (pp.c​:1748)
==58205== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==58205== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==58205== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==58205== by 0x4F3114​: perl_parse (perl.c​:2273)
==58205== by 0x42A92B​: main (perlmain.c​:114)
==58205==
==58205== Invalid read of size 8
==58205== at 0x4C2A7FA​: memcpy (mc_replace_strmem.c​:838)
==58205== by 0x6DDF9A​: Perl_repeatcpy (string3.h​:52)
==58205== by 0x84DF7B​: Perl_pp_repeat (pp.c​:1759)
==58205== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==58205== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==58205== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==58205== by 0x4F3114​: perl_parse (perl.c​:2273)
==58205== by 0x42A92B​: main (perlmain.c​:114)
==58205== Address 0x5edc198 is 8 bytes inside a block of size 10 alloc'd
==58205== at 0x4C28BED​: malloc (vg_replace_malloc.c​:263)
==58205== by 0x6CEFBC​: Perl_safesysmalloc (util.c​:144)
==58205== by 0x7EDB8F​: Perl_sv_grow (sv.c​:1623)
==58205== by 0x7FCCBF​: Perl_sv_2pv_flags (sv.c​:3095)
==58205== by 0x81754D​: Perl_sv_pvn_force_flags (sv.c​:9861)
==58205== by 0x84E526​: Perl_pp_repeat (pp.c​:1748)
==58205== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==58205== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==58205== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==58205== by 0x4F3114​: perl_parse (perl.c​:2273)
==58205== by 0x42A92B​: main (perlmain.c​:114)
==58205==
==58205==
==58205== Process terminating with default action of signal 11 (SIGSEGV)​:
dumping core
==58205== Access not within mapped region at address 0x62DC191
==58205== at 0x4C2A7C8​: memcpy (mc_replace_strmem.c​:838)
==58205== by 0x6DDF9A​: Perl_repeatcpy (string3.h​:52)
==58205== by 0x84DF7B​: Perl_pp_repeat (pp.c​:1759)
==58205== by 0x77B87A​: Perl_runops_standard (run.c​:41)
==58205== by 0x45AC0D​: S_fold_constants (op.c​:4343)
==58205== by 0x5CA050​: Perl_yyparse (perly.y​:769)
==58205== by 0x4F3114​: perl_parse (perl.c​:2273)
==58205== by 0x42A92B​: main (perlmain.c​:114)
==58205== If you believe this happened as a result of a stack
==58205== overflow in your program's main thread (unlikely but
==58205== possible), you can try to increase the size of the
==58205== main thread stack using the --main-stacksize= flag.
==58205== The main thread stack size used in this run was 8388608.
Segmentation fault

geeknik@​deb7fuzz​:~/findings/perl/fuzzer04/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 52892]

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​:000291,sig​:11,src​:008346,op​:havoc,rep​:16'.
Program terminated with signal 11, Segmentation fault.
#0 __memcpy_ssse3_back ()
  at ../sysdeps/x86_64/multiarch/memcpy-ssse3-back.S​:1664
1664 ../sysdeps/x86_64/multiarch/memcpy-ssse3-back.S​: No such file or
directory.
(gdb) bt
#0 __memcpy_ssse3_back ()
  at ../sysdeps/x86_64/multiarch/memcpy-ssse3-back.S​:1664
#1 0x00000000006ddf9b in memcpy (__len=131072, __src=0x2304502,
  __dest=<optimized out>) at
/usr/include/x86_64-linux-gnu/bits/string3.h​:52
#2 Perl_repeatcpy (to=0x2304502 '3' <repeats 200 times>...,
  from=0x2304500 '3' <repeats 200 times>..., len=2,
  count=9223372036854775806) at util.c​:3107
#3 0x000000000084df7c in Perl_pp_repeat () at pp.c​:1759
#4 0x000000000077b87b in Perl_runops_standard () at run.c​:41
#5 0x000000000045ac0e in S_fold_constants (o=0x23043f0) at op.c​:4343
#6 0x00000000005ca051 in Perl_yyparse (gramtype=<optimized out>)
  at perly.y​:769
#7 0x00000000004f3115 in S_parse_body (xsinit=0x42ad20 <xs_init>, env=0x0)
  at perl.c​:2273
#8 perl_parse (my_perl=<optimized out>, xsinit=0x42ad20 <xs_init>,
  argc=<optimized out>, argv=<optimized out>, env=0x0) at perl.c​:1607
#9 0x000000000042a92c in main (argc=2, argv=0x7fffa43513e8,
  env=0x7fffa4351400) at perlmain.c​:114
#10 0x00007fef77441ead 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=0x7fffa43513d8)
  at libc-start.c​:244
#11 0x000000000042ac45 in _start ()
(gdb) i r
rax 0x2324502 36848898
rbx 0x2344502 36979970
rcx 0x1fffe 131070
rdx 0x1fefe 130814
rsi 0x2324500 36848896
rdi 0x2344500 36979968
rbp 0x2304502 0x2304502
rsp 0x7fffa4350cf8 0x7fffa4350cf8
r8 0x23444f2 36979954
r9 0x2 2
r10 0x2304508 36717832
r11 0x7fef775793f0 140666476139504
r12 0x2 2
r13 0x20000 131072
r14 0x3fffffffffffffff 4611686018427387903
r15 0x20000 131072
rip 0x7fef7754e5f8 0x7fef7754e5f8 <__memcpy_ssse3_back+7016>
eflags 0x10202 [ IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb)

hexdump output of the test case file​:
0000000 3333 7e78 3b33 000a
0000007

similar test cases that also cause a segfault​:
0000000 3333 7e78 3b33 0a0a
0000008

0000000 3333 7e78 3b33
0000006

@p5pRT
Copy link
Author

p5pRT commented Jan 6, 2015

From @geeknik

7bytecrash.gz

@p5pRT
Copy link
Author

p5pRT commented Jan 6, 2015

From @geeknik

core.gz

@p5pRT
Copy link
Author

p5pRT commented Jan 6, 2015

From @cpansprout

On Mon Jan 05 20​:24​:11 2015, brian.carpenter@​gmail.com wrote​:

I'm still fuzzing a Perl binary that I built from git source on 01/02/2015
using the afl-gcc (http​://lcamtuf.coredump.cx/afl/) 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 a 7-byte test case which causes a
segfault (and possible stack overflow).

Nice bug!

$ perl5.12 -e '33x3'
Out of memory!
$ perl5.14.4 -e '33x
3'
panic​: memory wrap at -e line 1.
$ perl5.18.3 -e '33x3'
Out of memory!
panic​: fold_constants JMPENV_PUSH returned 2 at -e line 1.
$ perl5.20.1 -e '33x
3'
Segmentation fault​: 11

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jan 6, 2015

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

@p5pRT
Copy link
Author

p5pRT commented Jan 6, 2015

From @tonycoz

On Mon Jan 05 20​:24​:11 2015, brian.carpenter@​gmail.com wrote​:

I'm still fuzzing a Perl binary that I built from git source on 01/02/2015
using the afl-gcc (http​://lcamtuf.coredump.cx/afl/) compiler​:

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

This doesn't need afl-gcc to reproduce​:

  $ ./perl -e '33x~3'
  Segmentation fault

This is caused by pp_repeat passing ((size_t)~0) to SvGROW() and then Perl_sv_grow() bumps that up by 1 (per cbcb2a1) to allocate a byte for a COW count. Unfortunately ((size_t)~0)+1 is 0, so Perl_sv_grow() does nothing, and the string is repeated into the original buffer.

The following prevents the segfault and produces the expected panic instead​:

Inline Patch
diff --git a/sv.c b/sv.c
index fe092c4..1a28368 100644
--- a/sv.c
+++ b/sv.c
@@ -1596,7 +1596,8 @@ Perl_sv_grow(pTHX_ SV *const sv, STRLEN newlen)
      * caller wanted a nice 2^N sized block and will be annoyed at getting
      * 2^N+1 */
     if (newlen & 0xff)
-        newlen++;
+        if (!++newlen)
+            --newlen;
 #endif
 
 #if defined(PERL_USE_MALLOC_SIZE) && defined(Perl_safesysmalloc_size)

Tony

@p5pRT
Copy link
Author

p5pRT commented Jan 6, 2015

From @cpansprout

On Mon Jan 05 21​:58​:35 2015, tonyc wrote​:

On Mon Jan 05 20​:24​:11 2015, brian.carpenter@​gmail.com wrote​:

I'm still fuzzing a Perl binary that I built from git source on
01/02/2015
using the afl-gcc (http​://lcamtuf.coredump.cx/afl/) compiler​:

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

This doesn't need afl-gcc to reproduce​:

$ ./perl -e '33x~3'
Segmentation fault

This is caused by pp_repeat passing ((size_t)~0) to SvGROW() and then
Perl_sv_grow() bumps that up by 1 (per cbcb2a1) to allocate a byte for
a COW count. Unfortunately ((size_t)~0)+1 is 0, so Perl_sv_grow()
does nothing, and the string is repeated into the original buffer.

The following prevents the segfault and produces the expected panic
instead​:

Is a panic really expected? 5.12 just died with ‘Out of memory!’

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jan 6, 2015

From @ppisar

On 2015-01-06, Tony Cook via RT <perlbug-followup@​perl.org> wrote​:

This is caused by pp_repeat passing ((size_t)~0) to SvGROW() and then
Perl_sv_grow() bumps that up by 1 (per cbcb2a1) to allocate a byte for
a COW count. Unfortunately ((size_t)~0)+1 is 0, so Perl_sv_grow()
does nothing, and the string is repeated into the original buffer.

The following prevents the segfault and produces the expected panic
instead​:

diff --git a/sv.c b/sv.c
index fe092c4..1a28368 100644
--- a/sv.c
+++ b/sv.c
@​@​ -1596,7 +1596,8 @​@​ Perl_sv_grow(pTHX_ SV *const sv, STRLEN newlen)
* caller wanted a nice 2^N sized block and will be annoyed at getting
* 2^N+1 */
if (newlen & 0xff)
- newlen++;
+ if (!++newlen)
+ --newlen;
#endif

#if defined(PERL_USE_MALLOC_SIZE) && defined(Perl_safesysmalloc_size)

newlen's type is STRLEN. STRLEN is defined as MEM_SIZE and MEM_SIZE is
defines as Size_t. My config.h says​:

/* Size_t​:
* This symbol holds the type used to declare length parameters
* for string functions. It is usually size_t, but may be
* unsigned long, int, etc. It may be necessary to include
* <sys/types.h> to get any typedef'ed information.
*/

So it can be a signed integer. And overflow of signed variables is
undefined in C language. Therefore instead of the undefined behavior,
(!++newlen), you should compare against maximal value (MEM_SIZE_MAX).

-- Petr

@p5pRT
Copy link
Author

p5pRT commented Jan 6, 2015

From @tonycoz

On Tue, Jan 06, 2015 at 06​:39​:02AM +0000, Petr Pisar wrote​:

On 2015-01-06, Tony Cook via RT <perlbug-followup@​perl.org> wrote​:

This is caused by pp_repeat passing ((size_t)~0) to SvGROW() and then
Perl_sv_grow() bumps that up by 1 (per cbcb2a1) to allocate a byte for
a COW count. Unfortunately ((size_t)~0)+1 is 0, so Perl_sv_grow()
does nothing, and the string is repeated into the original buffer.

The following prevents the segfault and produces the expected panic
instead​:

diff --git a/sv.c b/sv.c
index fe092c4..1a28368 100644
--- a/sv.c
+++ b/sv.c
@​@​ -1596,7 +1596,8 @​@​ Perl_sv_grow(pTHX_ SV *const sv, STRLEN newlen)
* caller wanted a nice 2^N sized block and will be annoyed at getting
* 2^N+1 */
if (newlen & 0xff)
- newlen++;
+ if (!++newlen)
+ --newlen;
#endif

#if defined(PERL_USE_MALLOC_SIZE) && defined(Perl_safesysmalloc_size)

newlen's type is STRLEN. STRLEN is defined as MEM_SIZE and MEM_SIZE is
defines as Size_t. My config.h says​:

/* Size_t​:
* This symbol holds the type used to declare length parameters
* for string functions. It is usually size_t, but may be
* unsigned long, int, etc. It may be necessary to include
* <sys/types.h> to get any typedef'ed information.
*/

So it can be a signed integer. And overflow of signed variables is
undefined in C language. Therefore instead of the undefined behavior,
(!++newlen), you should compare against maximal value (MEM_SIZE_MAX).

If available, Size_t is ANSI C89 size_t which is required to be
unsigned.

You may be reading the (unlikely) alternatives incorrectly, they are
unsigned long, unsigned int, etc.

MEM_SIZE_MAX is defined as ((MEM_SIZE)~0) (aka ((Size_t)~0) and
doesn't attempt to account for a signed Size_t.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jan 6, 2015

From @tonycoz

On Mon, Jan 05, 2015 at 10​:32​:34PM -0800, Father Chrysostomos via RT wrote​:

On Mon Jan 05 21​:58​:35 2015, tonyc wrote​:

On Mon Jan 05 20​:24​:11 2015, brian.carpenter@​gmail.com wrote​:

I'm still fuzzing a Perl binary that I built from git source on
01/02/2015
using the afl-gcc (http​://lcamtuf.coredump.cx/afl/) compiler​:

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

This doesn't need afl-gcc to reproduce​:

$ ./perl -e '33x~3'
Segmentation fault

This is caused by pp_repeat passing ((size_t)~0) to SvGROW() and then
Perl_sv_grow() bumps that up by 1 (per cbcb2a1) to allocate a byte for
a COW count. Unfortunately ((size_t)~0)+1 is 0, so Perl_sv_grow()
does nothing, and the string is repeated into the original buffer.

The following prevents the segfault and produces the expected panic
instead​:

Is a panic really expected? 5.12 just died with ‘Out of memory!’

5.14 does the panic​:

  $ perl -v | grep subversion
  This is perl 5, version 14, subversion 2 (v5.14.2) built for x86_64-linux-gnu-thread-multi
  $ perl -e '33x~3'
  panic​: memory wrap at -e line 1.

While it says it's a panic, it's a croak, so it can be captured by
eval.

The "Out of memory!" message is simple write() to stderr and a hard
exit(1), so can't be captured.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jan 7, 2015

From @tonycoz

On Mon Jan 05 21​:58​:35 2015, tonyc wrote​:

On Mon Jan 05 20​:24​:11 2015, brian.carpenter@​gmail.com wrote​:

I'm still fuzzing a Perl binary that I built from git source on
01/02/2015
using the afl-gcc (http​://lcamtuf.coredump.cx/afl/) compiler​:

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

This doesn't need afl-gcc to reproduce​:

$ ./perl -e '33x~3'
Segmentation fault

This is caused by pp_repeat passing ((size_t)~0) to SvGROW() and then
Perl_sv_grow() bumps that up by 1 (per cbcb2a1) to allocate a byte for
a COW count. Unfortunately ((size_t)~0)+1 is 0, so Perl_sv_grow()
does nothing, and the string is repeated into the original buffer.

The following prevents the segfault and produces the expected panic
instead...

I've attached a format-patch patch instead, which directly checks against MEM_SIZE_MAX instead, rather than checking for the overflow.

I considered making the comparison C<< newlen < MEM_SIZE_MAX >> instead, which produced the same code, in case (somehow!) MEM_SIZE/STRLEN/Size_t ended up signed, but since that would break MEM_SIZE_MAX anyway I though it would be slightly more confusing.

As to the test, since we're allocating (address_space_size-1) bytes, the result creation should fail before any memory is allocated, so this isn't going to cause smokers (or other perl test runs) to attempt to allocate stupidly large amounts of space.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jan 7, 2015

From @tonycoz

0001-perl-123554-avoid-a-crash-from-SvGROW-MEM_SIZE_MAX.patch
From 9a747d06187928e4f40916f7ecf1328aef95f84c Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Wed, 7 Jan 2015 11:09:15 +1100
Subject: [PATCH] [perl #123554] avoid a crash from SvGROW(MEM_SIZE_MAX)

---
 sv.c          |    7 +++++--
 t/op/repeat.t |    6 +++++-
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/sv.c b/sv.c
index fe092c4..11f8499 100644
--- a/sv.c
+++ b/sv.c
@@ -1594,8 +1594,11 @@ Perl_sv_grow(pTHX_ SV *const sv, STRLEN newlen)
      * make more strings COW-able.
      * If the new size is a big power of two, don't bother: we assume the
      * caller wanted a nice 2^N sized block and will be annoyed at getting
-     * 2^N+1 */
-    if (newlen & 0xff)
+     * 2^N+1.
+     * Only increment if the allocation isn't MEM_SIZE_MAX,
+     * otherwise it will wrap to 0.
+     */
+    if (newlen & 0xff && newlen != MEM_SIZE_MAX)
         newlen++;
 #endif
 
diff --git a/t/op/repeat.t b/t/op/repeat.t
index 8df5241..421b705 100644
--- a/t/op/repeat.t
+++ b/t/op/repeat.t
@@ -6,7 +6,7 @@ BEGIN {
 }
 
 require './test.pl';
-plan(tests => 47);
+plan(tests => 49);
 
 # compile time
 
@@ -173,3 +173,7 @@ for(($#that_array)x2) {
     $_ *= 2;
 }
 is($#that_array, 28, 'list repetition propagates lvalue cx to its lhs');
+
+# see [perl #123554]
+ok(!eval '33x~3', "eval 33x~3 should panic, not crash perl");
+like($@, qr/^panic: memory wrap/, "check it's a panic");
-- 
1.7.10.4

@p5pRT
Copy link
Author

p5pRT commented Jan 7, 2015

From @cpansprout

On Mon Jan 05 10​:23​:49 2015, brian.carpenter@​gmail.com wrote​:

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 particular test case​:

3333333333333333333333333333333333333;33x~3333333333epl`t(/&/"oˇˇer web encodˇˇÄ

@p5pRT
Copy link
Author

p5pRT commented Jan 7, 2015

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

@p5pRT
Copy link
Author

p5pRT commented Jan 7, 2015

From @cpansprout

On Wed Jan 07 03​:50​:46 2015, sprout wrote​:

On Mon Jan 05 10​:23​:49 2015, brian.carpenter@​gmail.com wrote​:

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 particular test case​:

3333333333333333333333333333333333333;33x~3333333333epl`t(/&/"oˇˇer
web encodˇˇÄ

Something didn’t like the nulls that I unwittingly copied and pasted into the browser. So the message got cut off.

This particular test case fails for the same reason as #123554. The syntax error makes no difference, because the 33x~3333333... is folded at compile time.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jan 19, 2015

From @tonycoz

On Tue Jan 06 16​:23​:36 2015, tonyc wrote​:

On Mon Jan 05 21​:58​:35 2015, tonyc wrote​:

On Mon Jan 05 20​:24​:11 2015, brian.carpenter@​gmail.com wrote​:

I'm still fuzzing a Perl binary that I built from git source on
01/02/2015
using the afl-gcc (http​://lcamtuf.coredump.cx/afl/) compiler​:

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

This doesn't need afl-gcc to reproduce​:

$ ./perl -e '33x~3'
Segmentation fault

This is caused by pp_repeat passing ((size_t)~0) to SvGROW() and then
Perl_sv_grow() bumps that up by 1 (per cbcb2a1) to allocate a byte
for
a COW count. Unfortunately ((size_t)~0)+1 is 0, so Perl_sv_grow()
does nothing, and the string is repeated into the original buffer.

The following prevents the segfault and produces the expected panic
instead...

I've attached a format-patch patch instead, which directly checks
against MEM_SIZE_MAX instead, rather than checking for the overflow.

I considered making the comparison C<< newlen < MEM_SIZE_MAX >>
instead, which produced the same code, in case (somehow!)
MEM_SIZE/STRLEN/Size_t ended up signed, but since that would break
MEM_SIZE_MAX anyway I though it would be slightly more confusing.

As to the test, since we're allocating (address_space_size-1) bytes,
the result creation should fail before any memory is allocated, so
this isn't going to cause smokers (or other perl test runs) to attempt
to allocate stupidly large amounts of space.

Applied as fa8f4f8.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jan 19, 2015

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

@p5pRT p5pRT closed this as completed Jan 19, 2015
@p5pRT
Copy link
Author

p5pRT commented Feb 2, 2015

From @geeknik

I'm still attacking Perl5 with american fuzzy lop (
http​://lcamtuf.coredump.cx/afl/).

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

This is perl 5, version 21, subversion 9 (v5.21.9 (v5.21.8-79-g4932eec))
built for x86_64-linux

Perl was compiled using all defaults (except adding -g to the CFLAGS).

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX​: 0x0
RBX​: 0x2
RCX​: 0x1
RDX​: 0x2
RSI​: 0x12
RDI​: 0x0
RBP​: 0x2
RSP​: 0x7fffffffdcb0 --> 0x100
RIP​: 0x6e5a1c (<Perl_repeatcpy+2180>​: movzx edx,BYTE PTR [r9])
R8 : 0x0
R9 : 0x0
R10​: 0x2
R11​: 0x0
R12​: 0x2
R13​: 0x101
R14​: 0x0
R15​: 0x4
EFLAGS​: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction
overflow)
[-------------------------------------code-------------------------------------]
  0x6e5a0b <Perl_repeatcpy+2163>​: mov rax,QWORD PTR [rsp+0x10]
  0x6e5a10 <Perl_repeatcpy+2168>​: lea rsp,[rsp+0x98]
  0x6e5a18 <Perl_repeatcpy+2176>​: lea rcx,[rbp-0x1]
=> 0x6e5a1c <Perl_repeatcpy+2180>​: movzx edx,BYTE PTR [r9]
  0x6e5a20 <Perl_repeatcpy+2184>​: lea rax,[r9+0x1]
  0x6e5a24 <Perl_repeatcpy+2188>​: mov rsi,rcx
  0x6e5a27 <Perl_repeatcpy+2191>​: and esi,0x7
  0x6e5a2a <Perl_repeatcpy+2194>​: test rcx,rcx
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdcb0 --> 0x100
0008| 0x7fffffffdcb8 --> 0x7ffffffffffffffe
0016| 0x7fffffffdcc0 --> 0x0
0024| 0x7fffffffdcc8 --> 0x2
0032| 0x7fffffffdcd0 --> 0x10
0040| 0x7fffffffdcd8 --> 0x2
0048| 0x7fffffffdce0 --> 0xe4cfe8 --> 0xe4cfd8 --> 0x440300000001
0056| 0x7fffffffdce8 --> 0x603d63bf155a1200
[------------------------------------------------------------------------------]
Legend​: code, data, rodata, value
Stopped reason​: SIGSEGV
0x00000000006e5a1c in Perl_repeatcpy (to=0x2 <Address 0x2 out of bounds>,
from=0x0, len=0x2, count=0x7ffffffffffffffe) at util.c​:3086
3086 *p++ = *q++;

gdb-peda$ bt
#0 0x00000000006e5a1c in Perl_repeatcpy (to=0x2 <Address 0x2 out of
bounds>, from=0x0, len=0x2, count=0x7ffffffffffffffe) at util.c​:3086
#1 0x0000000000854eac in Perl_pp_repeat () at pp.c​:1768
#2 0x0000000000782f7b in Perl_runops_standard () at run.c​:41
#3 0x000000000046012e in S_fold_constants (o=0xe58420) at op.c​:4332
#4 0x00000000005c94f9 in Perl_yyparse (gramtype=<optimized out>) at
perly.y​:797
#5 0x00000000004f2615 in S_parse_body (xsinit=0x42a850 <xs_init>, env=0x0)
at perl.c​:2273
#6 perl_parse (my_perl=<optimized out>, xsinit=0x42a850 <xs_init>,
argc=<optimized out>, argv=<optimized out>, env=0x0) at perl.c​:1607
#7 0x000000000042a45c in main (argc=0x2, argv=0x7fffffffe398,
env=0x7fffffffe3b0) at perlmain.c​:114
#8 0x00007ffff6f97ead 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=0x7fffffffe388)
at libc-start.c​:244
#9 0x000000000042a775 in _start ()

gdb-peda$ exploit
Description​: Access violation near NULL on source operand
Short description​: SourceAvNearNull (16/22)
Hash​: 000c219cf66df9b6d330542118bb3e1e.8e1055cedb39ef6cf4cbc49a4c29dd29
Exploitability Classification​: PROBABLY_NOT_EXPLOITABLE
Explanation​: The target crashed on an access violation at an address
matching the source operand of the current instruction. This likely
indicates a read access violation, which may mean the application crashed
on a simple NULL dereference to data structure that has no immediate effect
on control of the processor.
Other tags​: AccessViolation (21/22)

I noticed that this same test case crashes Perl 5.21.7 as well
(v5.21.6-602-ge9d2bd8) but with a little different backtrace​:

#0 __memcpy_ssse3_back () at
../sysdeps/x86_64/multiarch/memcpy-ssse3-back.S​:1664
#1 0x00000000006d8d0b in memcpy (__len=0x20000, __src=0xe46432,
__dest=<optimized out>) at /usr/include/x86_64-linux-gnu/bits/string3.h​:52
#2 Perl_repeatcpy (to=0xe46432 '6' <repeats 200 times>..., from=0xe46430
'6' <repeats 200 times>..., len=0x2, count=0x7ffffffffffffffe) at
util.c​:3092
#3 0x000000000084742c in Perl_pp_repeat () at pp.c​:1749
#4 0x0000000000775a6b in Perl_runops_standard () at run.c​:41
#5 0x000000000045a3ee in S_fold_constants (o=0xe46320) at op.c​:4337
#6 0x00000000005c7321 in Perl_yyparse (gramtype=<optimized out>) at
perly.y​:769
#7 0x00000000004f0875 in S_parse_body (xsinit=0x42ac70 <xs_init>, env=0x0)
at perl.c​:2271
#8 perl_parse (my_perl=<optimized out>, xsinit=0x42ac70 <xs_init>,
argc=<optimized out>, argv=<optimized out>, env=0x0) at perl.c​:1605
#9 0x000000000042a87c in main (argc=0x2, argv=0x7fffffffe398,
env=0x7fffffffe3b0) at perlmain.c​:114
#10 0x00007ffff6f97ead 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=0x7fffffffe388)
at libc-start.c​:244
#11 0x000000000042ab95 in _start ()

The test case is a bit similar to the one in #123551, but the gdb output is
a bit different.

@p5pRT
Copy link
Author

p5pRT commented Feb 2, 2015

From @geeknik

perl5-crash.gz

@p5pRT
Copy link
Author

p5pRT commented Feb 2, 2015

From @tonycoz

On Mon Feb 02 08​:25​:53 2015, brian.carpenter@​gmail.com wrote​:

I'm still attacking Perl5 with american fuzzy lop (
http​://lcamtuf.coredump.cx/afl/).

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

I can't reproduce this in blead @​ v5.21.8-186-g533686c (using afl-gcc)​:

./Configure -des -Dusedevel -DDEBUGGING -Dcc=afl-gcc -Doptimize=-O2\ -g && AFL_HARDEN=1 make -j6 test-prep

$ AFL_HARDEN=1 valgrind -q ./perl ../123717.pl
Number found where operator expected at ../123717.pl line 1, near "--031"
  (Missing operator before 031?)
Can't modify constant item in postdecrement (--) at ../123717.pl line 1, near " Z6xx--"
syntax error at ../123717.pl line 1, near "--031"
Unrecognized character \xB1; marked by <-- HERE after Z6xx--031<-- HERE near column 18 at ../123717.pl line 1.

Tony

@p5pRT
Copy link
Author

p5pRT commented Feb 2, 2015

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

@p5pRT
Copy link
Author

p5pRT commented Feb 3, 2015

From @geeknik

Well that is what I get for using an outdated github repo. I've got this box pointed at the right repo now. We can probably close this if nobody can reproduce it.

@p5pRT
Copy link
Author

p5pRT commented Feb 8, 2015

From @wolfsage

On Mon Feb 02 16​:13​:02 2015, brian.carpenter@​gmail.com wrote​:

Well that is what I get for using an outdated github repo. I've got
this box pointed at the right repo now. We can probably close this if
nobody can reproduce it.

This appears to have been fixed in passing by​:

  commit fa8f4f8
  Author​: Tony Cook <tony@​develop-help.com>
  Date​: Mon Jan 19 13​:31​:26 2015 +1100

  [perl #123554] avoid a crash from SvGROW(MEM_SIZE_MAX)

(Perhaps these tickets should be linked?)

This appears to have been broken only recently - in perl-5.19.1, from​:

  commit cbcb2a1
  Author​: David Mitchell <davem@​iabyn.com>
  Date​: Sat Jun 8 18​:24​:51 2013 +0100

  add 1 to SvGROW under COW (and fix svleak.t)
  [...]

-- Matthew Horsfall (alh)

@p5pRT
Copy link
Author

p5pRT commented Feb 9, 2015

From @tonycoz

On Sun Jan 18 20​:48​:57 2015, tonyc wrote​:

On Tue Jan 06 16​:23​:36 2015, tonyc wrote​:

On Mon Jan 05 21​:58​:35 2015, tonyc wrote​:

On Mon Jan 05 20​:24​:11 2015, brian.carpenter@​gmail.com wrote​:

I'm still fuzzing a Perl binary that I built from git source on
01/02/2015
using the afl-gcc (http​://lcamtuf.coredump.cx/afl/) compiler​:

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

This doesn't need afl-gcc to reproduce​:

$ ./perl -e '33x~3'
Segmentation fault

This is caused by pp_repeat passing ((size_t)~0) to SvGROW() and then
Perl_sv_grow() bumps that up by 1 (per cbcb2a1) to allocate a byte
for
a COW count. Unfortunately ((size_t)~0)+1 is 0, so Perl_sv_grow()
does nothing, and the string is repeated into the original buffer.

The following prevents the segfault and produces the expected panic
instead...

I've attached a format-patch patch instead, which directly checks
against MEM_SIZE_MAX instead, rather than checking for the overflow.

I considered making the comparison C<< newlen < MEM_SIZE_MAX >>
instead, which produced the same code, in case (somehow!)
MEM_SIZE/STRLEN/Size_t ended up signed, but since that would break
MEM_SIZE_MAX anyway I though it would be slightly more confusing.

As to the test, since we're allocating (address_space_size-1) bytes,
the result creation should fail before any memory is allocated, so
this isn't going to cause smokers (or other perl test runs) to attempt
to allocate stupidly large amounts of space.

Applied as fa8f4f8.

With jhi's help, fixed a couple of other size overflows in 9efda33.

Unfortunately, which perl isn't segfaulting, in some builds this falls back to the out of memory handler, which can't be caught by eval, so remove the test.

Tony

@p5pRT
Copy link
Author

p5pRT commented Feb 14, 2015

From @hvds

Merge into [perl #123554], it's the same issue.

@p5pRT
Copy link
Author

p5pRT commented Feb 14, 2015

From @hvds

I think this is identical to [perl #123554], since the test case starts with '66x~6'. I'll merge.

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