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

null ptr deref -> Perl_find_lexical_cv () at op.c:11235 #14596

Closed
p5pRT opened this issue Mar 17, 2015 · 13 comments
Closed

null ptr deref -> Perl_find_lexical_cv () at op.c:11235 #14596

p5pRT opened this issue Mar 17, 2015 · 13 comments

Comments

@p5pRT
Copy link

p5pRT commented Mar 17, 2015

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

Searchable as RT124099$

@p5pRT
Copy link
Author

p5pRT commented Mar 17, 2015

From @geeknik

Built v5.21.10 (v5.21.9-259-g88d9f32) with the following command line​:

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

Bug found with AFL (http​://lcamtuf.coredump.cx/afl)

Valgrind​:
Array found where operator expected at test271-min line 1, at end of line
  (Missing operator before ?)
==3428== Invalid read of size 8
==3428== at 0x455678​: Perl_find_lexical_cv (op.c​:11238)
==3428== by 0x64B706​: Perl_yylex (toke.c​:6503)
==3428== by 0x65ACF4​: Perl_yyparse (perly.c​:322)
==3428== by 0x534490​: perl_parse (perl.c​:2289)
==3428== by 0x42AED7​: main (perlmain.c​:114)
==3428== Address 0x5edfea0 is 0 bytes after a block of size 16 alloc'd
==3428== at 0x4C28CCE​: realloc (vg_replace_malloc.c​:632)
==3428== by 0x7E0A18​: Perl_safesysrealloc (util.c​:270)
==3428== by 0x8A500E​: Perl_av_extend_guts (av.c​:159)
==3428== by 0x67EEC4​: S_pad_alloc_name (pad.c​:2684)
==3428== by 0x684644​: S_pad_findlex (pad.c​:1331)
==3428== by 0x684499​: S_pad_findlex (pad.c​:1308)
==3428== by 0x68696A​: Perl_pad_findmy_pvn (pad.c​:962)
==3428== by 0x5F7A3C​: Perl_yylex (toke.c​:6481)
==3428== by 0x65ACF4​: Perl_yyparse (perly.c​:322)
==3428== by 0x534490​: perl_parse (perl.c​:2289)
==3428== by 0x42AED7​: main (perlmain.c​:114)
==3428==
==3428== Invalid read of size 1
==3428== at 0x455684​: Perl_find_lexical_cv (op.c​:11235)
==3428== by 0x64B706​: Perl_yylex (toke.c​:6503)
==3428== by 0x65ACF4​: Perl_yyparse (perly.c​:322)
==3428== by 0x534490​: perl_parse (perl.c​:2289)
==3428== by 0x42AED7​: main (perlmain.c​:114)
==3428== Address 0x29 is not stack'd, malloc'd or (recently) free'd
==3428==
==3428==
==3428== Process terminating with default action of signal 11 (SIGSEGV)​: dumping core
==3428== Access not within mapped region at address 0x29
==3428== at 0x455684​: Perl_find_lexical_cv (op.c​:11235)
==3428== by 0x64B706​: Perl_yylex (toke.c​:6503)
==3428== by 0x65ACF4​: Perl_yyparse (perly.c​:322)
==3428== by 0x534490​: perl_parse (perl.c​:2289)
==3428== by 0x42AED7​: main (perlmain.c​:114)
==3428== If you believe this happened as a result of a stack
==3428== overflow in your program's main thread (unlikely but
==3428== possible), you can try to increase the size of the
==3428== main thread stack using the --main-stacksize= flag.
==3428== The main thread stack size used in this run was 8388608.
Segmentation fault

GDB​:
gdb-peda$ file ~/perl/perl
gdb-peda$ set args test271-min
gdb-peda$ r
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Array found where operator expected at test271-min line 1, at end of line
  (Missing operator before ?)

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX​: 0x0
RBX​: 0x11edc49 --> 0x0
RCX​: 0x10
RDX​: 0x1
RSI​: 0x11f0160 --> 0x11c9f60 --> 0x0
RDI​: 0x11e20b8 --> 0x11e0660 --> 0x0
RBP​: 0x11d2590 --> 0x11edf5a --> 0x6826 ('&h')
RSP​: 0x7fffffffd960 --> 0x0
RIP​: 0x455684 (<Perl_find_lexical_cv+484>​: movzx edx,BYTE PTR [rax+0x29])
R8 : 0x2
R9 : 0x11f00e0 --> 0x1
R10​: 0x11f0180 --> 0x11f0130 --> 0x1
R11​: 0x11f0130 --> 0x1
R12​: 0x0
R13​: 0x0
R14​: 0x11d27a0 (0x00000000011d27a0)
R15​: 0x1
EFLAGS​: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
  0x455670 <Perl_find_lexical_cv+464>​: lea rsp,[rsp+0x98]
  0x455678 <Perl_find_lexical_cv+472>​: mov rax,QWORD PTR [rsi+r8*8]
  0x45567c <Perl_find_lexical_cv+476>​: lea rcx,[r8*8+0x0]
=> 0x455684 <Perl_find_lexical_cv+484>​: movzx edx,BYTE PTR [rax+0x29]
  0x455688 <Perl_find_lexical_cv+488>​: test dl,0x1
  0x45568b <Perl_find_lexical_cv+491>​: jne 0x4555f8 <Perl_find_lexical_cv+344>
  0x455691 <Perl_find_lexical_cv+497>​: nop DWORD PTR [rax]
  0x455694 <Perl_find_lexical_cv+500>​: lea rsp,[rsp-0x98]
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffd960 --> 0x0
0008| 0x7fffffffd968 --> 0xe1075289aa3ceb00
0016| 0x7fffffffd970 --> 0x0
0024| 0x7fffffffd978 --> 0x64b707 (<Perl_yylex+487543>​: mov BYTE PTR [rsp+0x40],0x1)
0032| 0x7fffffffd980 --> 0x7ffff7dea1e0 (push rbx)
0040| 0x7fffffffd988 --> 0x11ea1f8 --> 0x620068 (<Perl_yylex+309720>​: and al,0x10)
0048| 0x7fffffffd990 --> 0x7fffffffe100 --> 0x3877552a ('*Uw8')
0056| 0x7fffffffd998 --> 0x1
[------------------------------------------------------------------------------]
Legend​: code, data, rodata, value
Stopped reason​: SIGSEGV
Perl_find_lexical_cv () at op.c​:11235
11235 while (PadnameOUTER(name)) {
gdb-peda$ bt
#0 Perl_find_lexical_cv () at op.c​:11235
#1 0x000000000064b707 in Perl_yylex () at toke.c​:6503
#2 0x000000000065acf5 in Perl_yyparse ()
#3 0x0000000000534491 in perl_parse ()
#4 0x000000000042aed8 in main () at perlmain.c​:114
#5 0x00007ffff6d7cead 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
#6 0x000000000042b1dd in _start ()
gdb-peda$ i r
rax 0x0 0x0
rbx 0x11edc49 0x11edc49
rcx 0x10 0x10
rdx 0x1 0x1
rsi 0x11f0160 0x11f0160
rdi 0x11e20b8 0x11e20b8
rbp 0x11d2590 0x11d2590
rsp 0x7fffffffd960 0x7fffffffd960
r8 0x2 0x2
r9 0x11f00e0 0x11f00e0
r10 0x11f0180 0x11f0180
r11 0x11f0130 0x11f0130
r12 0x0 0x0
r13 0x0 0x0
r14 0x11d27a0 0x11d27a0
r15 0x1 0x1
rip 0x455684 0x455684 <Perl_find_lexical_cv+484>
eflags 0x10202 [ IF RF ]
cs 0x33 0x33
ss 0x2b 0x2b
ds 0x0 0x0
es 0x0 0x0
fs 0x0 0x0
gs 0x0 0x0
gdb-peda$ exploitable
Description​: Access violation near NULL on source operand
Short description​: SourceAvNearNull (16/22)
Hash​: 2cd9775ce7faae9f56a2d26643b1d670.2cd9775ce7faae9f56a2d26643b1d670
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)

Hexdump of the 25-byte test case​:
0000000 7b30 796d 6d40 757b 2663 4068 3b30 3b30
0000010 7573 7b62 7573 7b62 0068
0000019

System Info​: Debian 7, Kernel 3.2.65-1+deb7u1 x86_64, GCC 4.9.2, libc 2.13-38+deb7u8

@p5pRT
Copy link
Author

p5pRT commented Mar 17, 2015

From @geeknik

test271-min

@p5pRT
Copy link
Author

p5pRT commented Mar 21, 2015

From @hvds

I think the pad-related debug may be significant​:

% ./miniperl -DXv -ce '0{my@​m{uc&h@​0;0;sub{sub{h'
Pad 0x1c762f8[0x1c84d40] new​: compcv=0x1c762e0 name=0x1c84d70 flags=0x0
Pad findlex cv=0x1c762e0 searching "&my" seq=-50
Pad 0x1c762f8[0x1c84d40] alloc​: 1 for padsv
Pad addname​: 1 "%m" new lex=0x1c97288
Pad findlex cv=0x1c762e0 searching "&uc" seq=-50
Pad 0x1c762f8[0x1c84d40] alloc​: 2 for padsv
Pad addname​: 2 "&h" new lex=0x1c972d0
Array found where operator expected at -e line 1, at end of line
  (Missing operator before ?)
Pad findlex cv=0x1c762e0 searching "@​0" seq=-50
Pad intromy​: 1 "%m", (4294967246,4294967295)
Pad intromy​: 2 "&h", (4294967246,4294967295)
Pad intromy​: seq -> 4294967247
Pad findlex cv=0x1c762e0 searching "&sub" seq=-49
Pad 0x1c973d8[0x1c98860] new​: compcv=0x1c973c0 name=0x1c98910 flags=0x6
Pad findlex cv=0x1c973c0 searching "&sub" seq=-48
Pad findlex cv=0x1c762e0 searching "&sub" seq=-49
Pad 0x1c97420[0x1c98ab0] new​: compcv=0x1c97408 name=0x1c98ae0 flags=0x6
Pad findlex cv=0x1c97408 searching "&h" seq=-47
Pad findlex cv=0x1c973c0 searching "&h" seq=-48
Pad findlex cv=0x1c762e0 searching "&h" seq=-49
Pad findlex cv=0x1c762e0 matched​: offset=2 (4294967246,4294967295)
Pad 0x1c973d8[0x1c98860] alloc​: 1 for padsv
Pad addname​: 1 "&h" FAKE
Pad 0x1c97420[0x1c98ab0] alloc​: 1 for padsv
Pad addname​: 1 "&h" FAKE
Segmentation fault (core dumped)
%

I'm not sure what any of that means, but it seems odd that we addname "&h" at line 7 of the output, and odder that we haven't attempted a findlex first; this appears to be because PL_in_my remains true when we reach S_pending_ident(PL_tokenbuf="&h") inside the braces of '0{my@​m{&h' whereas it is false at the same point without the leading '0'.

(We also seem rather inconsistent about size and sign of seq in the debug output, not sure if there's any good reason for that.)

Bisect points to​:

commit f815dc1
Author​: Father Chrysostomos <sprout@​cpan.org>
Date​: Sun Jun 30 00​:20​:33 2013 -0700

  Inline list constants
 
  These are inlined the same way as 1..5. We have two ops​:
 
  rv2av
  |
  `-- const
 
  The const op returns an AV, which is stored in the op tree, and then
  rv2av flattens it.

.. which is maybe somehow interacting with the lexical sub support.

Hugo

@p5pRT
Copy link
Author

p5pRT commented Mar 21, 2015

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

@p5pRT
Copy link
Author

p5pRT commented Mar 26, 2015

From @cpansprout

On Sat Mar 21 04​:35​:54 2015, hv wrote​:

I'm not sure what any of that means, but it seems odd that we addname
"&h" at line 7 of the output,

my &h will cause &h to be added to the pad, but it also generates a syntax error. When there are syntax errors, the lexer sometimes gets confused as to what a ‘my’ is meant to apply to.

Extra pad entries like an empty &h shouldn’t cause any problems, but it seems the pads are getting corrupted somehow.

and odder that we haven't attempted a
findlex first; this appears to be because PL_in_my remains true when
we reach S_pending_ident(PL_tokenbuf="&h") inside the braces of
'0{my@​m{&h' whereas it is false at the same point without the leading
'0'.

That’s what I was referring to about lexer confusion above. As long as it works correctly in the absence of syntax errors, that should suffice.

(We also seem rather inconsistent about size and sign of seq in the
debug output, not sure if there's any good reason for that.)

Bisect points to​:

commit f815dc1
Author​: Father Chrysostomos <sprout@​cpan.org>
Date​: Sun Jun 30 00​:20​:33 2013 -0700

Inline list constants

These are inlined the same way as 1..5. We have two ops​:

rv2av
|
`-- const

The const op returns an AV, which is stored in the op tree, and then
rv2av flattens it.

.. which is maybe somehow interacting with the lexical sub support.

I think that’s a red herring.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Mar 27, 2015

From @geeknik

perl -e 'm0{0\my}sub H;0;sub{sub{H' points to a slightly different line in op.c​:

Perl_find_lexical_cv () at op.c​:11239
11239 while (PadnameOUTER(name)) {
gdb-peda$ list
11234 CV *
11235 Perl_find_lexical_cv(pTHX_ PADOFFSET off)
11236 {
11237 PADNAME *name = PAD_COMPNAME(off);
11238 CV *compcv = PL_compcv;
11239 while (PadnameOUTER(name)) {
11240 assert(PARENT_PAD_INDEX(name));
11241 compcv = CvOUTSIDE(PL_compcv);
11242 name = PadlistNAMESARRAY(CvPADLIST(compcv))
11243

@p5pRT
Copy link
Author

p5pRT commented Mar 27, 2015

From [Unknown Contact. See original ticket]

perl -e 'm0{0\my}sub H;0;sub{sub{H' points to a slightly different line in op.c​:

Perl_find_lexical_cv () at op.c​:11239
11239 while (PadnameOUTER(name)) {
gdb-peda$ list
11234 CV *
11235 Perl_find_lexical_cv(pTHX_ PADOFFSET off)
11236 {
11237 PADNAME *name = PAD_COMPNAME(off);
11238 CV *compcv = PL_compcv;
11239 while (PadnameOUTER(name)) {
11240 assert(PARENT_PAD_INDEX(name));
11241 compcv = CvOUTSIDE(PL_compcv);
11242 name = PadlistNAMESARRAY(CvPADLIST(compcv))
11243

@p5pRT
Copy link
Author

p5pRT commented Mar 27, 2015

From @geeknik

~/perl/miniperl -DXv -ce 'm0{0\my}sub H;0;sub{sub{H'
Pad 0x1a162f8[0x1a25f10] new​: compcv=0x1a162e0 name=0x1a25f40 flags=0x0
Pad findlex cv=0x1a162e0 searching "&m0" seq=-50
Backslash found where operator expected at -e line 1, near "0\"
  (Missing operator before \?)
Pad findlex cv=0x1a162e0 searching "&my" seq=-49
Pad leavemy​: seq = 4294967248
Pad findlex cv=0x1a162e0 searching "&sub" seq=-48
Pad findlex cv=0x1a162e0 searching "&H" seq=-48
Pad 0x1a162f8[0x1a25f10] alloc​: 1 for entersub
Pad 0x1a162f8[0x1a25f10] free​: 1
Pad 0x1a162f8[0x1a25f10] alloc​: 2 for padsv
Pad addname​: 2 "&H" new lex=0x1a2d020
Pad intromy​: 2 "&H", (4294967248,4294967295)
Pad intromy​: seq -> 4294967249
Pad findlex cv=0x1a162e0 searching "&sub" seq=-47
Pad 0x1a2d128[0x1a36ef0] new​: compcv=0x1a2d110 name=0x1a36f20 flags=0x6
Pad findlex cv=0x1a2d110 searching "&sub" seq=-46
Pad findlex cv=0x1a162e0 searching "&sub" seq=-47
Pad 0x1a2d170[0x1a370c0] new​: compcv=0x1a2d158 name=0x1a370f0 flags=0x6
Pad findlex cv=0x1a2d158 searching "&H" seq=-45
Pad findlex cv=0x1a2d110 searching "&H" seq=-46
Pad findlex cv=0x1a162e0 searching "&H" seq=-47
Pad findlex cv=0x1a162e0 matched​: offset=2 (4294967248,4294967295)
Pad 0x1a2d128[0x1a36ef0] alloc​: 1 for padsv
Pad addname​: 1 "&H" FAKE
Pad 0x1a2d170[0x1a370c0] alloc​: 1 for padsv
Pad addname​: 1 "&H" FAKE
Segmentation fault

@p5pRT
Copy link
Author

p5pRT commented Mar 27, 2015

From @cpansprout

This variation loops​:

./miniperl -e '0{my&h@​0;0;sub{sub{h'

I think this line in find_lexical_cv is wrong​:

  compcv = CvOUTSIDE(PL_compcv);

It should be CvOUTSIDE(compcv).

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Mar 27, 2015

From @cpansprout

On Fri Mar 27 09​:35​:52 2015, sprout wrote​:

This variation loops​:

./miniperl -e '0{my&h@​0;0;sub{sub{h'

I think this line in find_lexical_cv is wrong​:

compcv = CvOUTSIDE\(PL\_compcv\);

It should be CvOUTSIDE(compcv).

It has nothing to do with syntax errors. This example demonstrates the problem more clearly (to me, at least)​:

$ ./perl -Ilib -Mfeature=​:all -e 'my sub h; sub{my $x; sub{h}}'
The lexical_subs feature is experimental at -e line 1.
Assertion failed​: (SvTYPE(cv) == SVt_PVCV || SvTYPE(cv) == SVt_PVFM), function Perl_cv_const_sv_or_av, file op.c, line 7933.
Abort trap​: 6

I have now fixed it in d655d9a.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Mar 27, 2015

@cpansprout - Status changed from 'open' to 'pending release'

@p5pRT
Copy link
Author

p5pRT commented Jun 2, 2015

From @khwilliamson

Thank you for submitting this ticket.

The issue should now be resolved with the release today of Perl v5.22, which is available at http​://www.perl.org/get.html
--
Karl Williamson for the Perl 5 team

@p5pRT
Copy link
Author

p5pRT commented Jun 2, 2015

@khwilliamson - Status changed from 'pending release' to 'resolved'

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