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

heap-use-after-free in S_regmatch #15811

Open
p5pRT opened this issue Jan 17, 2017 · 8 comments
Open

heap-use-after-free in S_regmatch #15811

p5pRT opened this issue Jan 17, 2017 · 8 comments

Comments

@p5pRT
Copy link

p5pRT commented Jan 17, 2017

Migrated from rt.perl.org#130569 (status was 'open')

Searchable as RT130569$

@p5pRT
Copy link
Author

p5pRT commented Jan 17, 2017

From @dur-randir

Created by @dur-randir

While fuzzing perl v5.25.8-216-gfbceb79751 built with afl and run
under libdislocator, I found the following program

/0|$}(?{s!!!})(0@​{s!!{s!})/

to perform an access outside of an allocated memory slot. ASAN diagnostics are​:

=================================================================
==22491==ERROR​: AddressSanitizer​: heap-use-after-free on address
0x60200000db71 at pc 0x000000c44d9e bp 0x7ffe8cb11710 sp
0x7ffe8cb11708
READ of size 1 at 0x60200000db71 thread T0
  #0 0xc44d9d in S_regmatch /home/afl/afl-asan/regexec.c​:5459​:9
  #1 0xc0927d in S_regtry /home/afl/afl-asan/regexec.c​:3645​:14
  #2 0xbdaeb7 in Perl_regexec_flags /home/afl/afl-asan/regexec.c​:3502​:7
  #3 0x923dcd in Perl_pp_match /home/afl/afl-asan/pp_hot.c​:2050​:10
  #4 0x847fe1 in Perl_runops_debug /home/afl/afl-asan/dump.c​:2260​:23
  #5 0x5f03f5 in S_run_body /home/afl/afl-asan/perl.c​:2528​:2
  #6 0x5f03f5 in perl_run /home/afl/afl-asan/perl.c​:2451
  #7 0x522402 in main /home/afl/afl-asan/perlmain.c​:123​:9
  #8 0x7f01f33d52b0 in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x202b0)
  #9 0x43ace9 in _start (/home/afl/afl-asan/perl+0x43ace9)

0x60200000db71 is located 1 bytes inside of 10-byte region
[0x60200000db70,0x60200000db7a)
freed by thread T0 here​:
  #0 0x4ea440 in __interceptor_cfree.localalias.1
(/home/afl/afl-asan/perl+0x4ea440)
  #1 0x84d317 in Perl_safesysfree /home/afl/afl-asan/util.c​:388​:2

previously allocated by thread T0 here​:
  #0 0x4ea5f8 in malloc (/home/afl/afl-asan/perl+0x4ea5f8)
  #1 0x84c51b in Perl_safesysmalloc /home/afl/afl-asan/util.c​:153​:21

GDB reports the following program state​:
#0 0x00007f694d950a85 in S_regmatch (reginfo=0x7ffddd44d2b0,
startpos=0x7f694bd32ff7 "s", prog=0x7f694bd20fc8) at regexec.c​:5459
5459 SET_nextchr;
(gdb) bt
#0 0x00007f694d950a85 in S_regmatch (reginfo=0x7ffddd44d2b0,
startpos=0x7f694bd32ff7 "s", prog=0x7f694bd20fc8) at regexec.c​:5459
#1 0x00007f694d94a2ea in S_regtry (reginfo=0x7ffddd44d2b0,
startposp=0x7ffddd44d078) at regexec.c​:3645
#2 0x00007f694d949cc6 in Perl_regexec_flags (rx=0x7f694c0756d0,
stringarg=0x7f694bd32ff6 "{s", strend=0x7f694bd32ff8 "",
strbeg=0x7f694bd32ff6 "{s",
  minend=0, sv=0x7f694dc8e490, data=0x0, flags=97) at regexec.c​:3502
#3 0x00007f694d81299e in Perl_pp_match () at pp_hot.c​:2050
#4 0x00007f694d7b9bb0 in Perl_runops_debug () at dump.c​:2260
#5 0x00007f694d6b4156 in S_run_body (oldscope=1) at perl.c​:2528
#6 0x00007f694d6b36d4 in perl_run (my_perl=0x7f694dc9afff) at perl.c​:2451
#7 0x00007f694d66ed3e in main (argc=2, argv=0x7ffddd44d778,
env=0x7ffddd44d790) at perlmain.c​:123
(gdb) p nextchr=0
Cannot access memory at address 0x7ffddd44c8e0

This is sort-of regression in blead since v5.24.0. Before the
following commit, this program just crashes due to a stack overflow​:

794826f is the first bad commit
commit 794826f
Author​: Yves Orton <demerphq@​gmail.com>
Date​: Tue Oct 18 13​:11​:49 2016 +0200

  regexec.c​: fix #129903​: forbid empty pattern in regex code block

  PL_curpm provides access to the data needed to implement
  the regex magic vars like $1 and $&amp;. These vars are defined
  to reference the last successfully matched pattern, or when
  in regex code blocks (?{ ... }) and (??{ ... }), they
  should refer to the currently executing pattern.

  Unfortunately this collides with its use to implement the
  empty pattern special behavior, which requires /just/
  "the last successfully matched pattern" everwhere.

  This meant that a pattern match like /(?{ s!!! })/ will
  infinitely recurse. Fixing this would be difficult, on
  the other hand detecting it is not, so we can convert
  the infinite recursion/stack overflow into a normal
  exception.

Perl Info

Flags:
    category=core
    severity=medium

Site configuration information for perl 5.25.9:

Configured by root at Sat Jan 14 02:25:05 MSK 2017.

Summary of my perl5 (revision 5 version 25 subversion 9) configuration:
  Commit id: cbe2fc5001aa59cdc73e04cc35e097a2ecfbeec0
  Platform:
    osname=linux
    osvers=3.16.0-4-amd64
    archname=x86_64-linux
    uname='linux dorothy 3.16.0-4-amd64 #1 smp debian 3.16.36-1+deb8u2
(2016-10-19) x86_64 gnulinux '
    config_args='-des -Dusedevel -DDEBUGGING -Dcc=afl-clang-fast
-Doptimize=-O0 -g -ggdb3'
    hint=recommended
    useposix=true
    d_sigaction=define
    useithreads=undef
    usemultiplicity=undef
    use64bitint=define
    use64bitall=define
    uselongdouble=undef
    usemymalloc=n
    bincompat5005=undef
  Compiler:
    cc='afl-clang-fast'
    ccflags ='-DDEBUGGING -fno-strict-aliasing -pipe
-fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE
-D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2'
    optimize='-O0 -g -ggdb3'
    cppflags='-DDEBUGGING -fno-strict-aliasing -pipe
-fstack-protector-strong -I/usr/local/include'
    ccversion=''
    gccversion='4.2.1 Compatible Clang 3.9.1 (tags/RELEASE_391/rc2)'
    gccosandvers=''
    intsize=4
    longsize=8
    ptrsize=8
    doublesize=8
    byteorder=12345678
    doublekind=3
    d_longlong=define
    longlongsize=8
    d_longdbl=define
    longdblsize=16
    longdblkind=3
    ivtype='long'
    ivsize=8
    nvtype='double'
    nvsize=8
    Off_t='off_t'
    lseeksize=8
    alignbytes=8
    prototype=define
  Linker and Libraries:
    ld='afl-clang-fast'
    ldflags =' -fstack-protector-strong -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib/llvm-3.9/bin/../lib/clang/3.9.1/lib
/usr/include/x86_64-linux-gnu /usr/lib /lib/x86_64-linux-gnu
/lib/../lib /usr/lib/x86_64-linux-gnu /usr/lib/../lib /lib
    libs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
    perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
    libc=libc-2.24.so
    so=so
    useshrplib=false
    libperl=libperl.a
    gnulibc_version='2.24'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs
    dlext=so
    d_dlsymun=undef
    ccdlflags='-Wl,-E'
    cccdlflags='-fPIC'
    lddlflags='-shared -O0 -g -ggdb3 -L/usr/local/lib -fstack-protector-strong'



@INC for perl 5.25.9:
    lib
    /usr/local/lib/perl5/site_perl/5.25.9/x86_64-linux
    /usr/local/lib/perl5/site_perl/5.25.9
    /usr/local/lib/perl5/5.25.9/x86_64-linux
    /usr/local/lib/perl5/5.25.9


Environment for perl 5.25.9:
    HOME=/home/afl
    LANG=en_US.UTF-8
    LANGUAGE=en_US:en
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/afl/perlbrew/bin:/home/afl/perlbrew/perls/perl-5.22.1/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
    PERLBREW_BASHRC_VERSION=0.78
    PERLBREW_HOME=/home/afl/.perlbrew
    PERLBREW_MANPATH=/home/afl/perlbrew/perls/perl-5.22.1/man
    PERLBREW_PATH=/home/afl/perlbrew/bin:/home/afl/perlbrew/perls/perl-5.22.1/bin
    PERLBREW_PERL=perl-5.22.1
    PERLBREW_ROOT=/home/afl/perlbrew
    PERLBREW_VERSION=0.78
    PERL_BADLANG (unset)
    SHELL=/usr/bin/zsh

@p5pRT
Copy link
Author

p5pRT commented Jan 22, 2017

From @tonycoz

On Tue, 17 Jan 2017 02​:10​:05 -0800, randir wrote​:

While fuzzing perl v5.25.8-216-gfbceb79751 built with afl and run
under libdislocator, I found the following program

/0|$}(?{s!!!})(0@​{s!!{s!})/

to perform an access outside of an allocated memory slot. ASAN
diagnostics are​:

=================================================================
==22491==ERROR​: AddressSanitizer​: heap-use-after-free on address
0x60200000db71 at pc 0x000000c44d9e bp 0x7ffe8cb11710 sp
0x7ffe8cb11708
READ of size 1 at 0x60200000db71 thread T0
#0 0xc44d9d in S_regmatch /home/afl/afl-asan/regexec.c​:5459​:9
#1 0xc0927d in S_regtry /home/afl/afl-asan/regexec.c​:3645​:14
#2 0xbdaeb7 in Perl_regexec_flags /home/afl/afl-
asan/regexec.c​:3502​:7
#3 0x923dcd in Perl_pp_match /home/afl/afl-asan/pp_hot.c​:2050​:10
#4 0x847fe1 in Perl_runops_debug /home/afl/afl-asan/dump.c​:2260​:23
#5 0x5f03f5 in S_run_body /home/afl/afl-asan/perl.c​:2528​:2
#6 0x5f03f5 in perl_run /home/afl/afl-asan/perl.c​:2451
#7 0x522402 in main /home/afl/afl-asan/perlmain.c​:123​:9
#8 0x7f01f33d52b0 in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x202b0)
#9 0x43ace9 in _start (/home/afl/afl-asan/perl+0x43ace9)

0x60200000db71 is located 1 bytes inside of 10-byte region
[0x60200000db70,0x60200000db7a)
freed by thread T0 here​:
#0 0x4ea440 in __interceptor_cfree.localalias.1
(/home/afl/afl-asan/perl+0x4ea440)
#1 0x84d317 in Perl_safesysfree /home/afl/afl-asan/util.c​:388​:2

A better freed by backtrace​:

0x60200000dad1 is located 1 bytes inside of 10-byte region [0x60200000dad0,0x60200000dada)
freed by thread T0 here​:
  #0 0x7f038d9b2527 in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x54527)
  #1 0x74ba3f in Perl_safesysfree /home/tony/dev/perl/git/perl/util.c​:388
  #2 0x8a930e in Perl_sv_setsv_cow /home/tony/dev/perl/git/perl/sv.c​:4891
  #3 0xafbc54 in S_reg_set_capture_string /home/tony/dev/perl/git/perl/regexec.c​:2770
  #4 0xb04f6e in Perl_regexec_flags /home/tony/dev/perl/git/perl/regexec.c​:3546
  #5 0x835281 in Perl_pp_subst /home/tony/dev/perl/git/perl/pp_hot.c​:3225
  #6 0x74745c in Perl_runops_debug /home/tony/dev/perl/git/perl/dump.c​:2406
  #7 0xb25bcd in S_regmatch /home/tony/dev/perl/git/perl/regexec.c​:6918
  #8 0xb05b83 in S_regtry /home/tony/dev/perl/git/perl/regexec.c​:3645
  #9 0xb04c31 in Perl_regexec_flags /home/tony/dev/perl/git/perl/regexec.c​:3502
  #10 0x81ffe3 in Perl_pp_match /home/tony/dev/perl/git/perl/pp_hot.c​:2050
  #11 0x74745c in Perl_runops_debug /home/tony/dev/perl/git/perl/dump.c​:2406
  #12 0x4bef56 in S_run_body /home/tony/dev/perl/git/perl/perl.c​:2528
  #13 0x4bd2e1 in perl_run /home/tony/dev/perl/git/perl/perl.c​:2451
  #14 0x41fc3b in main /home/tony/dev/perl/git/perl/perlmain.c​:123
  #15 0x7f038c860b44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b44)

previously allocated by thread T0 here​:
#0 0x4ea5f8 in malloc (/home/afl/afl-asan/perl+0x4ea5f8)
#1 0x84c51b in Perl_safesysmalloc /home/afl/afl-asan/util.c​:153​:21

and previously allocated​:

previously allocated by thread T0 here​:
  #0 0x7f038d9b273f in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x5473f)
  #1 0x74b382 in Perl_safesysmalloc /home/tony/dev/perl/git/perl/util.c​:153
  #2 0x8596a2 in Perl_sv_grow /home/tony/dev/perl/git/perl/sv.c​:1601
  #3 0x8abf05 in Perl_sv_setpvn /home/tony/dev/perl/git/perl/sv.c​:5001
  #4 0x8f0089 in Perl_newSVpvn_flags /home/tony/dev/perl/git/perl/sv.c​:9273
  #5 0x8382c5 in Perl_pp_subst /home/tony/dev/perl/git/perl/pp_hot.c​:3380
  #6 0x74745c in Perl_runops_debug /home/tony/dev/perl/git/perl/dump.c​:2406
  #7 0x4bef56 in S_run_body /home/tony/dev/perl/git/perl/perl.c​:2528
  #8 0x4bd2e1 in perl_run /home/tony/dev/perl/git/perl/perl.c​:2451
  #9 0x41fc3b in main /home/tony/dev/perl/git/perl/perlmain.c​:123
  #10 0x7f038c860b44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b44)

I suspect the (?{s!!!}) is moving $_ out from under the calling regexp matching.

I don't think this is a security issue.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jan 22, 2017

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

@p5pRT
Copy link
Author

p5pRT commented Jan 24, 2017

From @khwilliamson

On 01/22/2017 04​:29 PM, Tony Cook via RT wrote​:

On Tue, 17 Jan 2017 02​:10​:05 -0800, randir wrote​:

While fuzzing perl v5.25.8-216-gfbceb79751 built with afl and run
under libdislocator, I found the following program

/0|$}(?{s!!!})(0@​{s!!{s!})/

to perform an access outside of an allocated memory slot. ASAN
diagnostics are​:

=================================================================
==22491==ERROR​: AddressSanitizer​: heap-use-after-free on address
0x60200000db71 at pc 0x000000c44d9e bp 0x7ffe8cb11710 sp
0x7ffe8cb11708
READ of size 1 at 0x60200000db71 thread T0
#0 0xc44d9d in S_regmatch /home/afl/afl-asan/regexec.c​:5459​:9
#1 0xc0927d in S_regtry /home/afl/afl-asan/regexec.c​:3645​:14
#2 0xbdaeb7 in Perl_regexec_flags /home/afl/afl-
asan/regexec.c​:3502​:7
#3 0x923dcd in Perl_pp_match /home/afl/afl-asan/pp_hot.c​:2050​:10
#4 0x847fe1 in Perl_runops_debug /home/afl/afl-asan/dump.c​:2260​:23
#5 0x5f03f5 in S_run_body /home/afl/afl-asan/perl.c​:2528​:2
#6 0x5f03f5 in perl_run /home/afl/afl-asan/perl.c​:2451
#7 0x522402 in main /home/afl/afl-asan/perlmain.c​:123​:9
#8 0x7f01f33d52b0 in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x202b0)
#9 0x43ace9 in _start (/home/afl/afl-asan/perl+0x43ace9)

0x60200000db71 is located 1 bytes inside of 10-byte region
[0x60200000db70,0x60200000db7a)
freed by thread T0 here​:
#0 0x4ea440 in __interceptor_cfree.localalias.1
(/home/afl/afl-asan/perl+0x4ea440)
#1 0x84d317 in Perl_safesysfree /home/afl/afl-asan/util.c​:388​:2

A better freed by backtrace​:

0x60200000dad1 is located 1 bytes inside of 10-byte region [0x60200000dad0,0x60200000dada)
freed by thread T0 here​:
#0 0x7f038d9b2527 in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x54527)
#1 0x74ba3f in Perl_safesysfree /home/tony/dev/perl/git/perl/util.c​:388
#2 0x8a930e in Perl_sv_setsv_cow /home/tony/dev/perl/git/perl/sv.c​:4891
#3 0xafbc54 in S_reg_set_capture_string /home/tony/dev/perl/git/perl/regexec.c​:2770
#4 0xb04f6e in Perl_regexec_flags /home/tony/dev/perl/git/perl/regexec.c​:3546
#5 0x835281 in Perl_pp_subst /home/tony/dev/perl/git/perl/pp_hot.c​:3225
#6 0x74745c in Perl_runops_debug /home/tony/dev/perl/git/perl/dump.c​:2406
#7 0xb25bcd in S_regmatch /home/tony/dev/perl/git/perl/regexec.c​:6918
#8 0xb05b83 in S_regtry /home/tony/dev/perl/git/perl/regexec.c​:3645
#9 0xb04c31 in Perl_regexec_flags /home/tony/dev/perl/git/perl/regexec.c​:3502
#10 0x81ffe3 in Perl_pp_match /home/tony/dev/perl/git/perl/pp_hot.c​:2050
#11 0x74745c in Perl_runops_debug /home/tony/dev/perl/git/perl/dump.c​:2406
#12 0x4bef56 in S_run_body /home/tony/dev/perl/git/perl/perl.c​:2528
#13 0x4bd2e1 in perl_run /home/tony/dev/perl/git/perl/perl.c​:2451
#14 0x41fc3b in main /home/tony/dev/perl/git/perl/perlmain.c​:123
#15 0x7f038c860b44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b44)

previously allocated by thread T0 here​:
#0 0x4ea5f8 in malloc (/home/afl/afl-asan/perl+0x4ea5f8)
#1 0x84c51b in Perl_safesysmalloc /home/afl/afl-asan/util.c​:153​:21

and previously allocated​:

previously allocated by thread T0 here​:
#0 0x7f038d9b273f in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x5473f)
#1 0x74b382 in Perl_safesysmalloc /home/tony/dev/perl/git/perl/util.c​:153
#2 0x8596a2 in Perl_sv_grow /home/tony/dev/perl/git/perl/sv.c​:1601
#3 0x8abf05 in Perl_sv_setpvn /home/tony/dev/perl/git/perl/sv.c​:5001
#4 0x8f0089 in Perl_newSVpvn_flags /home/tony/dev/perl/git/perl/sv.c​:9273
#5 0x8382c5 in Perl_pp_subst /home/tony/dev/perl/git/perl/pp_hot.c​:3380
#6 0x74745c in Perl_runops_debug /home/tony/dev/perl/git/perl/dump.c​:2406
#7 0x4bef56 in S_run_body /home/tony/dev/perl/git/perl/perl.c​:2528
#8 0x4bd2e1 in perl_run /home/tony/dev/perl/git/perl/perl.c​:2451
#9 0x41fc3b in main /home/tony/dev/perl/git/perl/perlmain.c​:123
#10 0x7f038c860b44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b44)

I suspect the (?{s!!!}) is moving $_ out from under the calling regexp matching.

I don't think this is a security issue.

Tony

I looked at this enough to realize that there are others more familiar
with this code than me that could more easily find the bug. Attached is
an output of valgrind with a few extra debug statements added

The first failure is at a call to
  SET_nextchr;

This expands to

  nextchr = ((locinput < reginfo->strend) ? UCHARAT(locinput) :
NEXTCHR_EOS)

which looks quite safe. But in adding in DEBUG statements, the locinfo
and reginfo->strend have been changed from previous loop iterations at
the first valgrind failure. It looks related to the EVAL or some submatch.

@p5pRT
Copy link
Author

p5pRT commented Jan 24, 2017

From @khwilliamson

valgrind.log

@p5pRT
Copy link
Author

p5pRT commented Jan 25, 2017

From @hvds

On Tue, 17 Jan 2017 02​:10​:05 -0800, randir wrote​:

This is sort-of regression in blead since v5.24.0. Before the
following commit, this program just crashes due to a stack overflow​:

794826f is the first bad commit
commit 794826f
Author​: Yves Orton <demerphq@​gmail.com>
Date​: Tue Oct 18 13​:11​:49 2016 +0200

regexec.c​: fix #129903​: forbid empty pattern in regex code block

That's a red herring really, this alternate version avoiding the empty pattern (with some other expansions to try and make clearer what's going on) acts the same before and after that commit​:

valgrind ./miniperl -Dr -we '$_ = ""; @​x = (1); m{ 0 | (?{ s/^// }) 0 @​{ foo() } }x; sub foo { s/^/{s/; "x" }'

With the -Dr output we see an additional pair of bad reads in pv_escape(), which help to make clear that it's the reallocation of the PV after the second EVAL leaving stale pointers.

Around the CALLRUNOPS at regexec.c​:6918 we don't appear to make any effort to allow for the possibility our string may move under us, and I'm not sure what it'd make sense to do halfway through a pattern match in any case.

For simple-enough cases I think we could maybe leverage the COW framework for this - use COW to make a cheap mirror of the target string, and continue matching against the unaltered original even if someone changes the sv while we're working.

Note that that'd be a change of behaviour, which'd probably have at least some fallout. My gut feel is that it'd be relatively minor, and mostly in japh-like code, but I dunno.

I also don't know what we can sanely do in the more complex cases where COW can't be used, and it'd be a shame if the choices we make here take us further away from being able to deliver stream-matching in the future.

Hugo

@p5pRT
Copy link
Author

p5pRT commented Feb 20, 2017

From @iabyn

On Wed, Jan 25, 2017 at 04​:17​:07AM -0800, Hugo van der Sanden via RT wrote​:

On Tue, 17 Jan 2017 02​:10​:05 -0800, randir wrote​:

This is sort-of regression in blead since v5.24.0. Before the
following commit, this program just crashes due to a stack overflow​:

794826f is the first bad commit
commit 794826f
Author​: Yves Orton <demerphq@​gmail.com>
Date​: Tue Oct 18 13​:11​:49 2016 +0200

regexec.c​: fix #129903​: forbid empty pattern in regex code block

That's a red herring really, this alternate version avoiding the empty
pattern (with some other expansions to try and make clearer what's going
on) acts the same before and after that commit​:

valgrind ./miniperl -Dr -we '$_ = ""; @​x = (1); m{ 0 | (?{ s/^// }) 0 @​{ foo() } }x; sub foo { s/^/{s/; "x" }'

With the -Dr output we see an additional pair of bad reads in
pv_escape(), which help to make clear that it's the reallocation of the
PV after the second EVAL leaving stale pointers.

Around the CALLRUNOPS at regexec.c​:6918 we don't appear to make any
effort to allow for the possibility our string may move under us, and
I'm not sure what it'd make sense to do halfway through a pattern match
in any case.

For simple-enough cases I think we could maybe leverage the COW
framework for this - use COW to make a cheap mirror of the target
string, and continue matching against the unaltered original even if
someone changes the sv while we're working.

Note that that'd be a change of behaviour, which'd probably have at
least some fallout. My gut feel is that it'd be relatively minor, and
mostly in japh-like code, but I dunno.

I also don't know what we can sanely do in the more complex cases where
COW can't be used, and it'd be a shame if the choices we make here take
us further away from being able to deliver stream-matching in the
future.

It can be reduced further to the following (using $s rather than $_ to
demonstrate that there's nothing special about $_)​:

  $s = "a";
  $s .= "b"; # ensure not COW
  $s =~ /(?{$s = "xxxxxxxx"; $s .= ""})a/

and it shows clearly that it's the PVX buffer of $s being freed within
the (one) execution of the code block that causes the problem when the
regex op following the code block is executed.

I think some sort of COWing does seem to be the way forward.

But in any case, I don't think this is a security issue, as the attacker
would have to craft code-blocks that modify the match string, and if they
can craft code blocks, you've already lost. And the chances of finding an
existing code block which does this is slim - the code would already likely
crash. And hence why we've only seen this issue via fuzzing.

So I propose we move this to the public queue.

--
My get-up-and-go just got up and went.

@p5pRT
Copy link
Author

p5pRT commented Feb 27, 2017

From @iabyn

On Mon, Feb 20, 2017 at 05​:10​:48PM +0000, Dave Mitchell wrote​:

It can be reduced further to the following (using $s rather than $_ to
demonstrate that there's nothing special about $_)​:

$s = "a";
$s \.= "b"; \# ensure not COW
$s =~ /\(?\{$s = "xxxxxxxx"; $s \.= ""\}\)a/

and it shows clearly that it's the PVX buffer of $s being freed within
the (one) execution of the code block that causes the problem when the
regex op following the code block is executed.

I think some sort of COWing does seem to be the way forward.

But in any case, I don't think this is a security issue, as the attacker
would have to craft code-blocks that modify the match string, and if they
can craft code blocks, you've already lost. And the chances of finding an
existing code block which does this is slim - the code would already likely
crash. And hence why we've only seen this issue via fuzzing.

So I propose we move this to the public queue.

which I am now doing.

--
My Dad used to say 'always fight fire with fire', which is probably why
he got thrown out of the fire brigade.

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