-
Notifications
You must be signed in to change notification settings - Fork 560
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
Use-After-Free in Parser #15009
Comments
From hectohertz@gmail.comHi All, I've been doing some fuzzing of perl with afl, and I've found a use-after All fuzzing was done against a recent Perl was built with the following: These test-cases produce UAFs in toke.c, here's a trace using address root@vagrant-ubuntu-trusty-64:~/perl-debug/perl# ================================================================= ==7139==ERROR: AddressSanitizer: heap-use-after-free on address READ of size 1 at 0x60200000e170 thread T0 #0 0x6182e2 in Perl_yyerror_pvn #1 0x60cdd9 in Perl_yyerror_pv #2 0x60cdd9 in S_yywarn /home/vagrant/perl-debug/perl/toke.c:10921 #3 0x60cdd9 in S_no_op /home/vagrant/perl-debug/perl/toke.c:523 #4 0x5cc1e3 in Perl_yylex /home/vagrant/perl-debug/perl/toke.c:6472:6 #5 0x6203a8 in Perl_yyparse /home/vagrant/perl-debug/perl/perly.c:322:19 #6 0x56ca07 in S_parse_body /home/vagrant/perl-debug/perl/perl.c:2307:9 #7 0x567c97 in perl_parse /home/vagrant/perl-debug/perl/perl.c:1634:2 #8 0x4f8b88 in main /home/vagrant/perl-debug/perl/perlmain.c:114:18 #9 0x7f8ed4161ec4 in __libc_start_main #10 0x452626 in _start (/home/vagrant/perl-debug/perl/perl+0x452626) 0x60200000e170 is located 0 bytes inside of 10-byte region freed by thread T0 here: #0 0x4d9302 in __interceptor_free #1 0x7c01f3 in Perl_sv_clear /home/vagrant/perl-debug/perl/sv.c:6610:7 #2 0x7c3806 in Perl_sv_free2 /home/vagrant/perl-debug/perl/sv.c:6885:9 #3 0x5dc849 in S_SvREFCNT_dec #4 0x5dc849 in S_scan_heredoc /home/vagrant/perl-debug/perl/toke.c:9672 #5 0x5dc849 in Perl_yylex /home/vagrant/perl-debug/perl/toke.c:6123 #6 0x6203a8 in Perl_yyparse /home/vagrant/perl-debug/perl/perly.c:322:19 #7 0x56ca07 in S_parse_body /home/vagrant/perl-debug/perl/perl.c:2307:9 #8 0x567c97 in perl_parse /home/vagrant/perl-debug/perl/perl.c:1634:2 #9 0x4f8b88 in main /home/vagrant/perl-debug/perl/perlmain.c:114:18 #10 0x7f8ed4161ec4 in __libc_start_main previously allocated by thread T0 here: #0 0x4d95e2 in malloc (/home/vagrant/perl-debug/perl/perl+0x4d95e2) #1 0x6efdd7 in Perl_safesysmalloc #2 0x7898eb in Perl_sv_grow /home/vagrant/perl-debug/perl/sv.c:1628:17 #3 0x79a084 in Perl_sv_setpvn /home/vagrant/perl-debug/perl/sv.c:4853:12 #4 0x7c8083 in Perl_newSVpvn /home/vagrant/perl-debug/perl/sv.c:9175:5 #5 0x5da50f in S_scan_heredoc #6 0x5da50f in Perl_yylex /home/vagrant/perl-debug/perl/toke.c:6123 #7 0x6203a8 in Perl_yyparse /home/vagrant/perl-debug/perl/perly.c:322:19 #8 0x56ca07 in S_parse_body /home/vagrant/perl-debug/perl/perl.c:2307:9 #9 0x567c97 in perl_parse /home/vagrant/perl-debug/perl/perl.c:1634:2 #10 0x4f8b88 in main /home/vagrant/perl-debug/perl/perlmain.c:114:18 #11 0x7f8ed4161ec4 in __libc_start_main SUMMARY: AddressSanitizer: heap-use-after-free Shadow bytes around the buggy address: 0x0c047fff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff9bf0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff9c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff9c10: fa fa fa fa fa fa fa fa fa fa 00 02 fa fa fd fd =>0x0c047fff9c20: fa fa 00 02 fa fa fd fd fa fa fd fa fa fa[fd]fd 0x0c047fff9c30: fa fa 00 00 fa fa 00 02 fa fa fd fd fa fa 00 04 0x0c047fff9c40: fa fa 02 fa fa fa 00 02 fa fa 00 02 fa fa 00 01 0x0c047fff9c50: fa fa 00 02 fa fa 00 01 fa fa 00 01 fa fa 00 05 0x0c047fff9c60: fa fa 00 fa fa fa 00 02 fa fa 05 fa fa fa 00 07 0x0c047fff9c70: fa fa 00 05 fa fa 00 03 fa fa 06 fa fa fa 00 02 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 Left alloca redzone: ca Right alloca redzone: cb ==7139==ABORTING I realize similar bugs have been reported in perl before, and this team may Best, -jh |
From @tonycozOn Fri Oct 23 23:51:28 2015, hectohertz@gmail.com wrote:
The attached seems to fix all three test cases: tony@mars:.../git/perl$ valgrind -q ./perl ../126443a.pl
I think in general we consider such issues as not a security concern, after all, if an attacker can provide code to the parser, you're already vulnerable. The failure here is reading freed memory, and possibly sending its contents to stderr, while that will end up reading non-text occasionally, it doesn't *write* to that memory, so it won't corrupt that memory. So I think this isn't a security issue. Tony |
From @tonycoz0001-perl-126443-make-sure-PL_oldbufptr-is-preserved-in-s.patchFrom 36cd3a65d9abec33cbac02c1bc11dbeccec56b80 Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Tue, 27 Oct 2015 11:22:19 +1100
Subject: [perl #126443] make sure PL_oldbufptr is preserved in scan_heredoc()
This is later used to update PL_oldoldbufptr, if the token following
the <<FOO is unexpected this caused S_no_op() to access an invalid
*PL_oldoldbufptr.
WIP, needs tests, I suspect it should save/restore more of the parser
buffer pointers.
---
toke.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/toke.c b/toke.c
index b1bdfad..4ba7c0e 100644
--- a/toke.c
+++ b/toke.c
@@ -9617,12 +9617,14 @@ S_scan_heredoc(pTHX_ char *s)
else
{
SV *linestr_save;
+ char *oldbufptr_save;
streaming:
sv_setpvs(tmpstr,""); /* avoid "uninitialized" warning */
term = PL_tokenbuf[1];
len--;
linestr_save = PL_linestr; /* must restore this afterwards */
d = s; /* and this */
+ oldbufptr_save = PL_oldbufptr;
PL_linestr = newSVpvs("");
PL_bufend = SvPVX(PL_linestr);
while (1) {
@@ -9639,6 +9641,7 @@ S_scan_heredoc(pTHX_ char *s)
restore PL_linestr. */
SvREFCNT_dec_NN(PL_linestr);
PL_linestr = linestr_save;
+ PL_oldbufptr = oldbufptr_save;
goto interminable;
}
CopLINE_set(PL_curcop, origline);
@@ -9673,6 +9676,7 @@ S_scan_heredoc(pTHX_ char *s)
PL_linestr = linestr_save;
PL_linestart = SvPVX(linestr_save);
PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
+ PL_oldbufptr = oldbufptr_save;
s = d;
break;
}
--
2.1.4
|
The RT System itself - Status changed from 'new' to 'open' |
From hectohertz@gmail.comI figured as much, well regardless, glad to help catch a bug. If I find On Mon, Oct 26, 2015 at 8:30 PM, Tony Cook via RT <
|
From @tonycozOn Sat Oct 31 09:04:58 2015, hectohertz@gmail.com wrote:
To the general bug tracker I think. I'll move this ticket to the general bug tracker in a couple of days, unless someone objects. Tony |
From @tonycozOn Mon Oct 26 17:30:38 2015, tonyc wrote:
Now with a test. The test may only fail under ASAN/valgrind. Tony |
From @tonycoz0001-perl-126443-make-sure-PL_oldbufptr-is-preserved-in-s.patchFrom c8fa4f7fcdb0936482dc3b0196ef55918993a5cc Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Thu, 19 Nov 2015 11:44:48 +1100
Subject: [perl #126443] make sure PL_oldbufptr is preserved in scan_heredoc()
This is later used to update PL_oldoldbufptr, if the token following
the <<FOO is unexpected this caused S_no_op() to access an invalid
*PL_oldoldbufptr.
---
t/op/heredoc.t | 11 ++++++++++-
toke.c | 4 ++++
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/t/op/heredoc.t b/t/op/heredoc.t
index a239e92..dadf105 100644
--- a/t/op/heredoc.t
+++ b/t/op/heredoc.t
@@ -7,7 +7,7 @@ BEGIN {
}
use strict;
-plan(tests => 39);
+plan(tests => 40);
# heredoc without newline (#65838)
@@ -89,4 +89,13 @@ HEREDOC
{},
"long terminator fails correctly"
);
+
+ # this would read freed memory
+ fresh_perl_like(
+ qq(0<<<<""0\n\n),
+ # valgrind and asan reports an error between these two lines
+ qr/^Number found where operator expected at - line 1, near "<<""0"\s+\(Missing operator/,
+ {},
+ "don't use an invalid oldoldbufptr"
+ );
}
diff --git a/toke.c b/toke.c
index 2c0a3c9..37fe35d 100644
--- a/toke.c
+++ b/toke.c
@@ -9617,12 +9617,14 @@ S_scan_heredoc(pTHX_ char *s)
else
{
SV *linestr_save;
+ char *oldbufptr_save;
streaming:
sv_setpvs(tmpstr,""); /* avoid "uninitialized" warning */
term = PL_tokenbuf[1];
len--;
linestr_save = PL_linestr; /* must restore this afterwards */
d = s; /* and this */
+ oldbufptr_save = PL_oldbufptr;
PL_linestr = newSVpvs("");
PL_bufend = SvPVX(PL_linestr);
while (1) {
@@ -9639,6 +9641,7 @@ S_scan_heredoc(pTHX_ char *s)
restore PL_linestr. */
SvREFCNT_dec_NN(PL_linestr);
PL_linestr = linestr_save;
+ PL_oldbufptr = oldbufptr_save;
goto interminable;
}
CopLINE_set(PL_curcop, origline);
@@ -9673,6 +9676,7 @@ S_scan_heredoc(pTHX_ char *s)
PL_linestr = linestr_save;
PL_linestart = SvPVX(linestr_save);
PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
+ PL_oldbufptr = oldbufptr_save;
s = d;
break;
}
--
2.1.4
|
@tonycoz - Status changed from 'open' to 'pending release' |
From @khwilliamsonThank you for submitting this report. You have helped make Perl better. Perl 5.24.0 may be downloaded via https://metacpan.org/release/RJBS/perl-5.24.0 |
@khwilliamson - Status changed from 'pending release' to 'resolved' |
Migrated from rt.perl.org#126443 (status was 'resolved')
Searchable as RT126443$
The text was updated successfully, but these errors were encountered: