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

PERL-5.26.1 heap_use_after_free WRITE of size 8 #16313

Closed
p5pRT opened this issue Dec 18, 2017 · 9 comments
Closed

PERL-5.26.1 heap_use_after_free WRITE of size 8 #16313

p5pRT opened this issue Dec 18, 2017 · 9 comments

Comments

@p5pRT
Copy link

p5pRT commented Dec 18, 2017

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

Searchable as RT132602$

@p5pRT
Copy link
Author

p5pRT commented Dec 18, 2017

From sraums2498@gmail.com

=================================================================
==105657==ERROR​: AddressSanitizer​: heap-use-after-free on address
0x619000009a70 at pc 0x0000021ceb5c bp 0x7fff8d34c340 sp 0x7fff8d34c330
WRITE of size 8 at 0x619000009a70 thread T0
  #0 0x21ceb5b in Perl_pp_list
/home/asan_perl/Documents/perl-5.26.1/pp.c​:5193
  #1 0x1b1bc2e in Perl_runops_standard
/home/asan_perl/Documents/perl-5.26.1/run.c​:41
  #2 0x9218a5 in S_run_body
/home/asan_perl/Documents/perl-5.26.1/perl.c​:2519
  #3 0x9218a5 in perl_run
/home/asan_perl/Documents/perl-5.26.1/perl.c​:2447
  #4 0x46b6a7 in main /home/asan_perl/Documents/perl-5.26.1/perlmain.c​:123
  #5 0x7f0cf33a282f in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
  #6 0x46c888 in _start
(/home/asan_perl/Documents/perl-5.26.1/perl+0x46c888)

0x619000009a70 is located 1008 bytes inside of 1024-byte region
[0x619000009680,0x619000009a80)
freed by thread T0 here​:
  #0 0x7f0cf4146961 in realloc
(/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98961)
  #1 0x1681118 in Perl_safesysrealloc
/home/asan_perl/Documents/perl-5.26.1/util.c​:274
  #2 0x1addeda in Perl_av_extend_guts
/home/asan_perl/Documents/perl-5.26.1/av.c​:163
  #3 0x22727fb in Perl_stack_grow
/home/asan_perl/Documents/perl-5.26.1/scope.c​:57
  #4 0x21ce97f in Perl_pp_list
/home/asan_perl/Documents/perl-5.26.1/pp.c​:5191
  #5 0x1b1bc2e in Perl_runops_standard
/home/asan_perl/Documents/perl-5.26.1/run.c​:41
  #6 0x9218a5 in S_run_body
/home/asan_perl/Documents/perl-5.26.1/perl.c​:2519
  #7 0x9218a5 in perl_run
/home/asan_perl/Documents/perl-5.26.1/perl.c​:2447
  #8 0x46b6a7 in main /home/asan_perl/Documents/perl-5.26.1/perlmain.c​:123
  #9 0x7f0cf33a282f in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

previously allocated by thread T0 here​:
  #0 0x7f0cf4146602 in malloc
(/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
  #1 0x167dd81 in Perl_safesysmalloc
/home/asan_perl/Documents/perl-5.26.1/util.c​:153
  #2 0x1adf2d0 in Perl_av_extend_guts
/home/asan_perl/Documents/perl-5.26.1/av.c​:186
  #3 0x2272eb6 in Perl_new_stackinfo
/home/asan_perl/Documents/perl-5.26.1/scope.c​:74
  #4 0x8ab011 in Perl_init_stacks
/home/asan_perl/Documents/perl-5.26.1/perl.c​:4137
  #5 0x8af2e0 in perl_construct
/home/asan_perl/Documents/perl-5.26.1/perl.c​:274
  #6 0x46b033 in main /home/asan_perl/Documents/perl-5.26.1/perlmain.c​:117
  #7 0x7f0cf33a282f in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

SUMMARY​: AddressSanitizer​: heap-use-after-free
/home/asan_perl/Documents/perl-5.26.1/pp.c​:5193 Perl_pp_list
Shadow bytes around the buggy address​:
  0x0c327fff92f0​: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c327fff9300​: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c327fff9310​: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c327fff9320​: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c327fff9330​: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x0c327fff9340​: fd fd fd fd fd fd fd fd fd fd fd fd fd fd[fd]fd
  0x0c327fff9350​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c327fff9360​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c327fff9370​: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c327fff9380​: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c327fff9390​: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes)​:
  Addressable​: 00
  Partially addressable​: 01 02 03 04 05 06 07
  Heap left redzone​: fa
  Heap right redzone​: fb
  Freed heap region​: fd
  Stack left redzone​: f1
  Stack mid redzone​: f2
  Stack right redzone​: f3
  Stack partial redzone​: f4
  Stack after return​: f5
  Stack use after scope​: f8
  Global redzone​: f9
  Global init order​: f6
  Poisoned by user​: f7
  Container overflow​: fc
  Array cookie​: ac
  Intra object redzone​: bb
  ASan internal​: fe
==105657==ABORTING

--
Regards,
SRAUMS

@p5pRT
Copy link
Author

p5pRT commented Dec 18, 2017

From sraums2498@gmail.com

168

@p5pRT
Copy link
Author

p5pRT commented Dec 20, 2017

From @iabyn

On Mon, Dec 18, 2017 at 03​:38​:23AM -0800, SRAUMS JN wrote​:

WRITE of size 8 at 0x619000009a70 thread T0
#0 0x21ceb5b in Perl_pp_list

This is a regression that was introduced into blead with
v5.27.1-248-gb54564c and backported to 5.26.1 with v5.26.0-16-g6a20648,
thus it only appears in a single production release.

The fault is in pp_list using EXTEND() rather than MEXTEND(), so if the
stack gets reallocated, mark still points to the old stack.

I think it would be hard to find code in the wild which could exploit
this​:

1) pp_list() would have to be called in scalar context, which doesn't
happen very often (I added an assert(0) in the scalar branch of pp_list,
and 97% of the test suite files passed);

2) pp_list has to be called with the stack filled exactly to the brim,
in order to trigger a stack grow.

Once triggered, the effects are

1) pp_list will randomly return (...)[-1] or &PL_sv_undef - normally
which of these is chosen depends on whether the list is empty;

2) On return, PL_stack_sp will point to the old freed stack, so any
further stack activity will be writing SV addresses to, or beyond, the
freed stack.

I have a fix for this, and also a fix for a similar issue in pp_warn,
found by looking for pp functions which contain both MARK and EXTEND
(rather than MEXTEND).

Here's a test I added which triggers the behaviour​:

  fresh_perl_is(<<'EOF', "OK\n", {stderr => 1}, "RT #132602");
  sub f { 3701, 15844 }
  my (@​a, @​b);
  for my $i (1..300) {
  push @​a, $i;
  @​b = (@​a, scalar f());
  die unless $b[-1] == 15844;
  }
  # mess with the stack some more for ASan's benefit
  for my $i (1..100) {
  push @​a, $i;
  @​b = @​a;
  }
  print "OK\n";
  EOF

The OP_LIST is in the f sub, which doesn't know until runtime whether to
return a list or the last element.

Once the pp_list fix is pushed, it needs backporting to maint-5.26 too.

My feeling is that since this is hard enough to exploit, and has been in
only one production release, we should just treat it as a normal fix.

--
A major Starfleet emergency breaks out near the Enterprise, but
fortunately some other ships in the area are able to deal with it to
everyone's satisfaction.
  -- Things That Never Happen in "Star Trek" #13

@p5pRT
Copy link
Author

p5pRT commented Dec 20, 2017

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

@p5pRT
Copy link
Author

p5pRT commented Jan 31, 2018

From @tonycoz

On Wed, 20 Dec 2017 06​:46​:41 -0800, davem wrote​:

On Mon, Dec 18, 2017 at 03​:38​:23AM -0800, SRAUMS JN wrote​:

WRITE of size 8 at 0x619000009a70 thread T0
#0 0x21ceb5b in Perl_pp_list

This is a regression that was introduced into blead with
v5.27.1-248-gb54564c and backported to 5.26.1 with v5.26.0-16-g6a20648,
thus it only appears in a single production release.

The fault is in pp_list using EXTEND() rather than MEXTEND(), so if the
stack gets reallocated, mark still points to the old stack.

I think it would be hard to find code in the wild which could exploit
this​:

1) pp_list() would have to be called in scalar context, which doesn't
happen very often (I added an assert(0) in the scalar branch of pp_list,
and 97% of the test suite files passed);

2) pp_list has to be called with the stack filled exactly to the brim,
in order to trigger a stack grow.

Once triggered, the effects are

1) pp_list will randomly return (...)[-1] or &PL_sv_undef - normally
which of these is chosen depends on whether the list is empty;

2) On return, PL_stack_sp will point to the old freed stack, so any
further stack activity will be writing SV addresses to, or beyond, the
freed stack.

I have a fix for this, and also a fix for a similar issue in pp_warn,
found by looking for pp functions which contain both MARK and EXTEND
(rather than MEXTEND).

Here's a test I added which triggers the behaviour​:

fresh\_perl\_is\(\<\<'EOF'\, "OK\\n"\, \{stderr => 1\}\, "RT \#132602"\);
sub f \{ 3701\, 15844 \}
my \(@&#8203;a\, @&#8203;b\);
for my $i \(1\.\.300\) \{
    push @&#8203;a\, $i;
    @&#8203;b = \(@&#8203;a\, scalar f\(\)\);
    die unless $b\[\-1\] == 15844;
\}
\# mess with the stack some more for ASan's benefit
for my $i \(1\.\.100\) \{
    push @&#8203;a\, $i;
    @&#8203;b = @&#8203;a;
\}
print "OK\\n";
EOF

The OP_LIST is in the f sub, which doesn't know until runtime whether to
return a list or the last element.

Once the pp_list fix is pushed, it needs backporting to maint-5.26 too.

My feeling is that since this is hard enough to exploit, and has been in
only one production release, we should just treat it as a normal fix.

It's potentially a denial of service in that a write to the freed block might crash perl (the memory may no longer be mapped), or corrupt the arena, leading to a crash later on.

But as you say, it's unlikely for pp_list to be used in scalar context, and it's very unlikely the stack will be filled to the brim, so I agree this isn't a useful denial of service, and the lack of control over the value written (it's a pointer) means I don't think this can be used for any sort of code execution attack.

If the new block allocated when the stack was reallocated contained SV pointers (such as the AvARRAY() from an AV) it may be possible to use this for some sort of information disclosure, since the next SV popped from he stack will be the previous SV pointer[1], but with the unlikelyhood of the pre-conditions I don't think this is realistically exploitable.

So I agree this isn't a security issue.

Tony

[1] AvREAL() arrays have the new entries cleared, but the stack isn't

@p5pRT
Copy link
Author

p5pRT commented Jan 31, 2018

From @tonycoz

On Tue, 30 Jan 2018 16​:53​:24 -0800, tonyc wrote​:

So I agree this isn't a security issue.

Moved to the public queue.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jan 31, 2018

From @tonycoz

On Wed, 20 Dec 2017 06​:46​:41 -0800, davem wrote​:

I have a fix for this, and also a fix for a similar issue in pp_warn,
found by looking for pp functions which contain both MARK and EXTEND
(rather than MEXTEND).

I think the original issue here was fixed in 57bd660 (perl #131954), but
not the pp_warn issue you found.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jan 31, 2018

From @iabyn

On Tue, Jan 30, 2018 at 04​:59​:24PM -0800, Tony Cook via RT wrote​:

On Wed, 20 Dec 2017 06​:46​:41 -0800, davem wrote​:

I have a fix for this, and also a fix for a similar issue in pp_warn,
found by looking for pp functions which contain both MARK and EXTEND
(rather than MEXTEND).

I think the original issue here was fixed in 57bd660 (perl #131954), but
not the pp_warn issue you found.

Ah yes, I forgot to push it. Pushed now as v5.27.8-140-g8d629a7.

--
A walk of a thousand miles begins with a single step...
then continues for another 1,999,999 or so.

@p5pRT
Copy link
Author

p5pRT commented Feb 7, 2018

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

@p5pRT p5pRT closed this as completed Feb 7, 2018
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