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 S_gv_fetchmeth_internal (gv.c:782) #15772

Open
p5pRT opened this issue Dec 14, 2016 · 8 comments
Open

heap-use-after-free S_gv_fetchmeth_internal (gv.c:782) #15772

p5pRT opened this issue Dec 14, 2016 · 8 comments

Comments

@p5pRT
Copy link

p5pRT commented Dec 14, 2016

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

Searchable as RT130344$

@p5pRT
Copy link
Author

p5pRT commented Dec 14, 2016

From @geeknik

Triggered with Perl v5.25.7-98-gdf13534 while fuzzing with AFL.

od -tx1 test775
0000000 6d 44 7b 32 5e 57 20 3e 3e 2d 21 2b 2d 2d 24 7c
0000020 2c 25 bd 3d 66 2e 2e 50 2b 2d 2d 24 7c 2c 25 bd
0000040 3d 66 2e 2e 50 4b 2c 6d 41 35 48 6d 6c 75 6c 2e
0000060 35 2e 35 2e 39 33 37 35 2c 6d 41 35 33 37 35 2c
0000100 6d 41 35 48 55 6c 56 7d 2e 35 2e 35 2e 44 39 37
0000120 35 39 1a 25 a3 a3 a3 a3 a3 69 6e 6f 6f 64 65 20
0000140 44 59 54 01 2c 20 22 3a 7b 74 66 50 bc 6f 64 65
0000160 20 53 6d 44 37 55 ea ff 70 23 39 0a 5f 5f 44 41
0000200 61 00 00 00 ff 28 65 6c 6c 6f 77 84 ff 77 77 77
0000220 00 64 32 41 33 41 7d 21 5c 6e 22 df 10 24 75 73
0000240 74 84 69 8f 6a 32 26 64 20 3c 3c 3c ff 7f 0a
0000257

Can't locate object method "mD" via package "2" (perhaps you forgot to load
"2"?) at test775 line 1.

==22687==ERROR​: AddressSanitizer​: heap-use-after-free on address
0x60300000e9b8 at pc 0x0000005bed2d bp 0x7ffca4724570 sp 0x7ffca4724568
READ of size 8 at 0x60300000e9b8 thread T0
  #0 0x5bed2c in S_gv_fetchmeth_internal /root/perl/gv.c​:782​:9
  #1 0x5bdcb9 in S_gv_fetchmeth_internal /root/perl/gv.c​:832​:21
  #2 0x95599f in S_curse /root/perl/sv.c​:6902​:21
  #3 0x951224 in Perl_sv_clear /root/perl/sv.c​:6559​:8
  #4 0x957ec2 in Perl_sv_free2 /root/perl/sv.c​:7056​:9
  #5 0x8f02a1 in S_SvREFCNT_dec_NN /root/perl/./inline.h​:200​:2
  #6 0x8f02a1 in do_clean_named_io_objs /root/perl/sv.c​:600
  #7 0x8eebf6 in S_visit /root/perl/sv.c​:476​:3
  #8 0x8eebf6 in Perl_sv_clean_objs /root/perl/sv.c​:632
  #9 0x585fc5 in perl_destruct /root/perl/perl.c​:855​:5
  #10 0x4de86a in main /root/perl/perlmain.c​:134​:18
  #11 0x7fa63e484b44 in __libc_start_main
/build/glibc-daoqzt/glibc-2.19/csu/libc-start.c​:287
  #12 0x4de34c in _start (/root/perl/perl+0x4de34c)

0x60300000e9b8 is located 8 bytes inside of 32-byte region
[0x60300000e9b0,0x60300000e9d0)
freed by thread T0 here​:
  #0 0x4c0a4b in __interceptor_free (/root/perl/perl+0x4c0a4b)
  #1 0x7fce59 in Perl_safesysfree /root/perl/util.c​:388​:2
  #2 0x957ec2 in Perl_sv_free2 /root/perl/sv.c​:7056​:9

previously allocated by thread T0 here​:
  #0 0x4c0ccb in malloc (/root/perl/perl+0x4c0ccb)
  #1 0x7fc067 in Perl_safesysmalloc /root/perl/util.c​:153​:21

SUMMARY​: AddressSanitizer​: heap-use-after-free /root/perl/gv.c​:782
S_gv_fetchmeth_internal
Shadow bytes around the buggy address​:
  0x0c067fff9ce0​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9cf0​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9d00​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9d10​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff9d20​: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c067fff9d30​: fd fd fd fd fa fa fd[fd]fd fd fa fa fd fd fd fa
  0x0c067fff9d40​: fa fa 00 00 00 04 fa fa 00 00 00 fa fa fa 00 00
  0x0c067fff9d50​: 05 fa fa fa 00 00 00 06 fa fa 00 00 00 00 fa fa
  0x0c067fff9d60​: 00 00 00 00 fa fa 00 00 00 00 fa fa fd fd fd fd
  0x0c067fff9d70​: fa fa 00 00 00 00 fa fa fd fd fd fd fa fa 00 00
  0x0c067fff9d80​: 00 00 fa fa fd fd fd fd fa fa 00 00 00 00 fa fa
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
  ASan internal​: fe
==22687==ABORTING

@p5pRT
Copy link
Author

p5pRT commented Dec 14, 2016

From @geeknik

test775.gz

@p5pRT
Copy link
Author

p5pRT commented Dec 14, 2016

From @tonycoz

On Tue, 13 Dec 2016 17​:20​:50 -0800, brian.carpenter@​gmail.com wrote​:

Triggered with Perl v5.25.7-98-gdf13534 while fuzzing with AFL.

od -tx1 test775
0000000 6d 44 7b 32 5e 57 20 3e 3e 2d 21 2b 2d 2d 24 7c
0000020 2c 25 bd 3d 66 2e 2e 50 2b 2d 2d 24 7c 2c 25 bd
0000040 3d 66 2e 2e 50 4b 2c 6d 41 35 48 6d 6c 75 6c 2e
0000060 35 2e 35 2e 39 33 37 35 2c 6d 41 35 33 37 35 2c
0000100 6d 41 35 48 55 6c 56 7d 2e 35 2e 35 2e 44 39 37
0000120 35 39 1a 25 a3 a3 a3 a3 a3 69 6e 6f 6f 64 65 20
0000140 44 59 54 01 2c 20 22 3a 7b 74 66 50 bc 6f 64 65
0000160 20 53 6d 44 37 55 ea ff 70 23 39 0a 5f 5f 44 41
0000200 61 00 00 00 ff 28 65 6c 6c 6f 77 84 ff 77 77 77
0000220 00 64 32 41 33 41 7d 21 5c 6e 22 df 10 24 75 73
0000240 74 84 69 8f 6a 32 26 64 20 3c 3c 3c ff 7f 0a
0000257

Can't locate object method "mD" via package "2" (perhaps you forgot to load

Simplifies to​:

  mD{--$|,%x=f..k+--$|,%x=f..k}"abc"

which needs to be in a file (perl -e ... doesn't reproduce it).

The following​:

  mD{--$|,%x=f..k,%x=f..k}"abc"

again in a file, produces​:

tony@​mars​:.../git/perl$ ./perl ../130344b.pl
Can't locate object method "mD" via package "1" (perhaps you forgot to load "1"?) at ../130344b.pl line 1.
Attempt to free unreferenced scalar​: SV 0x62100001bf18.
perl​: gv.c​:1498​: S_gv_stashsvpvn_cached​: Assertion `PL_valid_types_IVX[((svtype)((_svivx)->sv_flags & 0xff)) & 0xf]' failed.
Aborted

The original and its simplified version are crashing while looking
for DESTROY for an IO​::File object, falling back to UNIVERSAL​:

$ ./perl -Do ../130344b.pl
(../130344b.pl​:0) sv_upgrade clearing PL_stashcache
(../130344b.pl​:0) sv_upgrade clearing PL_stashcache
(../130344b.pl​:0) sv_upgrade clearing PL_stashcache
(../130344b.pl​:0) sv_upgrade clearing PL_stashcache

EXECUTING...

(../130344b.pl​:1) Looking for method mD in package UNIVERSAL
(../130344b.pl​:1) Looking for method mD in package UNIVERSAL
(../130344b.pl​:1) Looking for method AUTOLOAD in package UNIVERSAL
(../130344b.pl​:1) Looking for method AUTOLOAD in package UNIVERSAL
Can't locate object method "mD" via package "0" (perhaps you forgot to load "0"?) at ../130344b.pl line 1.
(../130344b.pl​:0) Looking for DESTROY method for IO​::File
(../130344b.pl​:0) Looking for method DESTROY in package IO​::File
(../130344b.pl​:0) Looking for method DESTROY in package UNIVERSAL

Tony

@p5pRT
Copy link
Author

p5pRT commented Dec 14, 2016

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

@p5pRT
Copy link
Author

p5pRT commented Jan 8, 2017

From @arc

On Wed, 14 Dec 2016 15​:45​:53 -0800, tonyc wrote​:

Simplifies to​:

mD{--$|,%x=f..k+--$|,%x=f..k}"abc"

Further reduction​: f { $s=1, %x=j..k+($s=0), %x=() } 9

So I suspect at least part of this is stack-not-refcounted.

which needs to be in a file (perl -e ... doesn't reproduce it).

I think that's because using -e causes IO​::File to have a 0 cached for its DESTROY method before execution starts.

I get the same heap-use-after-free under miniperl, fwiw.

The following​:

mD{--$|,%x=f..k,%x=f..k}"abc"

again in a file, produces​:

tony@​mars​:.../git/perl$ ./perl ../130344b.pl
Can't locate object method "mD" via package "1" (perhaps you forgot to
load "1"?) at ../130344b.pl line 1.
Attempt to free unreferenced scalar​: SV 0x62100001bf18.
perl​: gv.c​:1498​: S_gv_stashsvpvn_cached​: Assertion
`PL_valid_types_IVX[((svtype)((_svivx)->sv_flags & 0xff)) & 0xf]'
failed.
Aborted

With this further reduction, rt130344c.pl​:

f { $s=1, @​x=2, @​x=() } 9

I get the same assertion failure as with rt130344b.pl. But that doesn't seem to be the whole of the same bug, in that this fixes it​:

Inline Patch
diff --git a/gv.c b/gv.c
index 2570cf0657..6f513ca1e2 100644
--- a/gv.c
+++ b/gv.c
@@ -1495,7 +1495,10 @@ S_gv_stashsvpvn_cached(pTHX_ SV *namesv, const char *name, U32 namelen, I32 flag
         (flags & SVf_UTF8) ? HVhek_UTF8 : 0, 0, NULL, 0
     );

-    if (he) return INT2PTR(HV*,SvIVX(HeVAL(he)));
+    if (he) {
+        SV *sv = HeVAL(he);
+        return SvIOK(sv) ? INT2PTR(HV*, SvIVX(sv)) : NULL;
+    }
     else if (flags & GV_CACHE_ONLY) return NULL;

     if (namesv) {

but doesn't affect Tony's rt130344.pl or rt130344b.pl.

That change isn't good enough, because running rt130344c.pl with -e still yields "Attempt to free unreferenced scalar". But I think it's probably needed anyway, and I'm wondering whether it should be applied to blead directly. That is, I suspect fixing it wouldn't disclose an unfixed security issue.

--
Aaron Crane ** http​://aaroncrane.co.uk/

@p5pRT
Copy link
Author

p5pRT commented Feb 1, 2017

From @tonycoz

On Sun, 08 Jan 2017 06​:14​:29 -0800, arc wrote​:

With this further reduction, rt130344c.pl​:

f { $s=1, @​x=2, @​x=() } 9

I get the same assertion failure as with rt130344b.pl. But that
doesn't seem to be the whole of the same bug, in that this fixes it​:

diff --git a/gv.c b/gv.c
index 2570cf0657..6f513ca1e2 100644
--- a/gv.c
+++ b/gv.c
@​@​ -1495,7 +1495,10 @​@​ S_gv_stashsvpvn_cached(pTHX_ SV *namesv, const
char *name, U32 namelen, I32 flag
(flags & SVf_UTF8) ? HVhek_UTF8 : 0, 0, NULL, 0
);

- if (he) return INT2PTR(HV*,SvIVX(HeVAL(he)));
+ if (he) {
+ SV *sv = HeVAL(he);
+ return SvIOK(sv) ? INT2PTR(HV*, SvIVX(sv)) : NULL;
+ }
else if (flags & GV_CACHE_ONLY) return NULL;

if (namesv) {

but doesn't affect Tony's rt130344.pl or rt130344b.pl.

That change isn't good enough, because running rt130344c.pl with -e
still yields "Attempt to free unreferenced scalar". But I think it's
probably needed anyway, and I'm wondering whether it should be applied
to blead directly. That is, I suspect fixing it wouldn't disclose an
unfixed security issue.

The problem I see with this patch is it's more a workaround for the stack-not-refcounted bug rather than a fix for the issue.

In the general case that bug can result in re-use of SV pool entries, so while in this particular case it might detect the problem, in the more general that SV could have been re-used and gv_stashsvpvn_cached() will be returning some random SV instead.

It really needs an assertion, something like​:

  /* make sure it's a HV, though it might still be the wrong HV */
  assert(SvIOK(sv) && SvTYPE(INT2PTR(HV*, SvIVX(sv))) == SVt_HV);

which I expect would currently only fail due to the stack-not-refcounted bug.

Tony

@p5pRT
Copy link
Author

p5pRT commented Feb 20, 2017

From @iabyn

On Tue, Jan 31, 2017 at 04​:22​:49PM -0800, Tony Cook via RT wrote​:

On Sun, 08 Jan 2017 06​:14​:29 -0800, arc wrote​:

With this further reduction, rt130344c.pl​:

f { $s=1, @​x=2, @​x=() } 9

I get the same assertion failure as with rt130344b.pl. But that
doesn't seem to be the whole of the same bug, in that this fixes it​:

diff --git a/gv.c b/gv.c
index 2570cf0657..6f513ca1e2 100644
--- a/gv.c
+++ b/gv.c
@​@​ -1495,7 +1495,10 @​@​ S_gv_stashsvpvn_cached(pTHX_ SV *namesv, const
char *name, U32 namelen, I32 flag
(flags & SVf_UTF8) ? HVhek_UTF8 : 0, 0, NULL, 0
);

- if (he) return INT2PTR(HV*,SvIVX(HeVAL(he)));
+ if (he) {
+ SV *sv = HeVAL(he);
+ return SvIOK(sv) ? INT2PTR(HV*, SvIVX(sv)) : NULL;
+ }
else if (flags & GV_CACHE_ONLY) return NULL;

if (namesv) {

but doesn't affect Tony's rt130344.pl or rt130344b.pl.

That change isn't good enough, because running rt130344c.pl with -e
still yields "Attempt to free unreferenced scalar". But I think it's
probably needed anyway, and I'm wondering whether it should be applied
to blead directly. That is, I suspect fixing it wouldn't disclose an
unfixed security issue.

The problem I see with this patch is it's more a workaround for the stack-not-refcounted bug rather than a fix for the issue.

In the general case that bug can result in re-use of SV pool entries, so while in this particular case it might detect the problem, in the more general that SV could have been re-used and gv_stashsvpvn_cached() will be returning some random SV instead.

It really needs an assertion, something like​:

/* make sure it's a HV, though it might still be the wrong HV */
assert(SvIOK(sv) && SvTYPE(INT2PTR(HV*, SvIVX(sv))) == SVt_HV);

which I expect would currently only fail due to the stack-not-refcounted bug.

I agree with Tony in that I think the assertion should be applied rather
than Aaron's 'handle possibly corrupt caceh entry' patch.

Then the ticket should be moved to the public queue, added to the 'stack
not ref counted' meta ticket, then ignored until such time as we fix that
wider issue.

--
You're only as old as you look.

@p5pRT
Copy link
Author

p5pRT commented Feb 27, 2017

From @iabyn

On Mon, Feb 20, 2017 at 03​:25​:34PM +0000, Dave Mitchell wrote​:

On Tue, Jan 31, 2017 at 04​:22​:49PM -0800, Tony Cook via RT wrote​:

On Sun, 08 Jan 2017 06​:14​:29 -0800, arc wrote​:

With this further reduction, rt130344c.pl​:

f { $s=1, @​x=2, @​x=() } 9

I get the same assertion failure as with rt130344b.pl. But that
doesn't seem to be the whole of the same bug, in that this fixes it​:

diff --git a/gv.c b/gv.c
index 2570cf0657..6f513ca1e2 100644
--- a/gv.c
+++ b/gv.c
@​@​ -1495,7 +1495,10 @​@​ S_gv_stashsvpvn_cached(pTHX_ SV *namesv, const
char *name, U32 namelen, I32 flag
(flags & SVf_UTF8) ? HVhek_UTF8 : 0, 0, NULL, 0
);

- if (he) return INT2PTR(HV*,SvIVX(HeVAL(he)));
+ if (he) {
+ SV *sv = HeVAL(he);
+ return SvIOK(sv) ? INT2PTR(HV*, SvIVX(sv)) : NULL;
+ }
else if (flags & GV_CACHE_ONLY) return NULL;

if (namesv) {

but doesn't affect Tony's rt130344.pl or rt130344b.pl.

That change isn't good enough, because running rt130344c.pl with -e
still yields "Attempt to free unreferenced scalar". But I think it's
probably needed anyway, and I'm wondering whether it should be applied
to blead directly. That is, I suspect fixing it wouldn't disclose an
unfixed security issue.

The problem I see with this patch is it's more a workaround for the stack-not-refcounted bug rather than a fix for the issue.

In the general case that bug can result in re-use of SV pool entries, so while in this particular case it might detect the problem, in the more general that SV could have been re-used and gv_stashsvpvn_cached() will be returning some random SV instead.

It really needs an assertion, something like​:

/* make sure it's a HV, though it might still be the wrong HV */
assert(SvIOK(sv) && SvTYPE(INT2PTR(HV*, SvIVX(sv))) == SVt_HV);

which I expect would currently only fail due to the stack-not-refcounted bug.

I agree with Tony in that I think the assertion should be applied rather
than Aaron's 'handle possibly corrupt caceh entry' patch.

Then the ticket should be moved to the public queue, added to the 'stack
not ref counted' meta ticket, then ignored until such time as we fix that
wider issue.

I've now pushed the assert as v5.25.10-42-g78e4f28 and am doing the moving
and linking.

--
"Emacs isn't a bad OS once you get used to it.
It just lacks a decent editor."

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