develooper Front page | perl.perl5.porters | Postings from August 2016

[perl #129058] Perl_do_vop: resulting string isn't alwaysnull-terminated

Thread Previous
From:
Dan Collins
Date:
August 23, 2016 16:58
Subject:
[perl #129058] Perl_do_vop: resulting string isn't alwaysnull-terminated
Message ID:
rt-4.0.24-16741-1471971481-120.129058-75-0@perl.org
# New Ticket Created by  Dan Collins 
# Please include the string:  [perl #129058]
# in the subject line of all future correspondence about this issue. 
# <URL: https://rt.perl.org/Ticket/Display.html?id=129058 >


Hello!

While fuzzing the a quadmath build of the perl interpreter, I encountered the following testcase:

perl -e '0|v1000&E'

This appears to be creating a string with a codepoint over 255. The output:

$ ../bin/perl -e '0|v1000&E'
Operator or semicolon missing before &E at -e line 1.
Ambiguous use of & resolved as operator & at -e line 1.
Use of strings with code points over 0xFF as arguments to bitwise and (&) operator is deprecated at -e line 1.
$ echo $?
0

Under Valgrind, with --track-origins=yes:

Operator or semicolon missing before &E at -e line 1.
Ambiguous use of & resolved as operator & at -e line 1.
Use of strings with code points over 0xFF as arguments to bitwise and (&) operator is deprecated at -e line 1.
==45631== Conditional jump or move depends on uninitialised value(s)
==45631==    at 0x4C2BBD8: strlen (vg_replace_strmem.c:454)
==45631==    by 0xDF4F77: Perl_my_atof2 (numeric.c:1349)
==45631==    by 0xDF4F77: Perl_my_atof (numeric.c:1210)
==45631==    by 0x93B64B: S_sv_setnv (sv.c:2113)
==45631==    by 0x9D1321: S_sv_2iuv_common (sv.c:2298)
==45631==    by 0x9D880F: Perl_sv_2uv_flags (sv.c:2574)
==45631==    by 0xA80A65: Perl_pp_bit_or (pp.c:2464)
==45631==    by 0x7E0833: Perl_runops_debug (dump.c:2234)
==45631==    by 0x53A0D8: S_run_body (perl.c:2525)
==45631==    by 0x53A0D8: perl_run (perl.c:2448)
==45631==    by 0x429A47: main (perlmain.c:123)
==45631==  Uninitialised value was created by a heap allocation
==45631==    at 0x4C28C0F: malloc (vg_replace_malloc.c:299)
==45631==    by 0x7EF59C: Perl_safesysmalloc (util.c:153)
==45631==    by 0x99646F: Perl_sv_grow (sv.c:1605)
==45631==    by 0x9CB173: Perl_sv_setpvn (sv.c:4898)
==45631==    by 0xC324AE: Perl_do_vop (doop.c:1011)
==45631==    by 0xA7E15E: Perl_pp_bit_and (pp.c:2407)
==45631==    by 0x7E0833: Perl_runops_debug (dump.c:2234)
==45631==    by 0x45DB75: S_fold_constants (op.c:4512)
==45631==    by 0x665A10: Perl_yyparse (perly.y:970)
==45631==    by 0x530344: S_parse_body (perl.c:2373)
==45631==    by 0x537586: perl_parse (perl.c:1689)
==45631==    by 0x4297B7: main (perlmain.c:121)
==45631==
==45631==
==45631== HEAP SUMMARY:
==45631==     in use at exit: 104,090 bytes in 517 blocks
==45631==   total heap usage: 700 allocs, 183 frees, 148,350 bytes allocated
==45631==
==45631== LEAK SUMMARY:
==45631==    definitely lost: 0 bytes in 0 blocks
==45631==    indirectly lost: 0 bytes in 0 blocks
==45631==      possibly lost: 0 bytes in 0 blocks
==45631==    still reachable: 104,090 bytes in 517 blocks
==45631==         suppressed: 0 bytes in 0 blocks
==45631== Rerun with --leak-check=full to see details of leaked memory
==45631==
==45631== For counts of detected and suppressed errors, rerun with: -v
==45631== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

And under GDB, using AFL's libdislocator to turn the invalid access into a SEGV:

(gdb) run
Starting program: /usr/local/perl-afl/bin/perl -e 0\|v1000\&E
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Operator or semicolon missing before &E at -e line 1.
Ambiguous use of & resolved as operator & at -e line 1.
Use of strings with code points over 0xFF as arguments to bitwise and (&) operator is deprecated at -e line 1.

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff6b452b0 in strlen () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) bt
#0  0x00007ffff6b452b0 in strlen () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x0000000000df4f78 in Perl_my_atof2 (value=<synthetic pointer>, orig=0x7ffff637fff6 "@AAAAAAAAA") at numeric.c:1349
#2  Perl_my_atof (s=0x7ffff637fff6 "@AAAAAAAAA") at numeric.c:1210
#3  0x000000000093b64c in S_sv_setnv (sv=sv@entry=0x7ffff660ae98, numtype=numtype@entry=0) at sv.c:2113
#4  0x00000000009d1322 in S_sv_2iuv_common (sv=sv@entry=0x7ffff660ae98) at sv.c:2298
#5  0x00000000009d8810 in Perl_sv_2uv_flags (sv=sv@entry=0x7ffff660ae98, flags=flags@entry=0) at sv.c:2574
#6  0x0000000000a80a66 in Perl_pp_bit_or () at pp.c:2464
#7  0x00000000007e0834 in Perl_runops_debug () at dump.c:2234
#8  0x000000000053a0d9 in S_run_body (oldscope=1) at perl.c:2525
#9  perl_run (my_perl=<optimized out>) at perl.c:2448
#10 0x0000000000429a48 in main (argc=<optimized out>, argv=<optimized out>, env=<optimized out>) at perlmain.c:123
(gdb) f 1
#1  0x0000000000df4f78 in Perl_my_atof2 (value=<synthetic pointer>, orig=0x7ffff637fff6 "@AAAAAAAAA") at numeric.c:1349
1349        const char* send = s + strlen(orig); /* one past the last */
(gdb) l
1344    Perl_my_atof2(pTHX_ const char* orig, NV* value)
1345    {
1346        const char* s = orig;
1347        NV result[3] = {0.0, 0.0, 0.0};
1348    #if defined(USE_PERL_ATOF) || defined(USE_QUADMATH)
1349        const char* send = s + strlen(orig); /* one past the last */
1350        bool negative = 0;
1351    #endif
1352    #if defined(USE_PERL_ATOF) && !defined(USE_QUADMATH)
1353        UV accumulator[2] = {0,0};  /* before/after dp */
(gdb) info locals
s = 0x7ffff637fff6 "@AAAAAAAAA"
send = <optimized out>
negative = <optimized out>
(gdb) p s[10]
$1 = 0 '\000'

So fold_constants is trying to reduce this, something is disappointed because the v-string uses codepoints over 255. Because this is a quadmath build, we take this branch:

1209    #ifdef USE_QUADMATH
1210        Perl_my_atof2(aTHX_ s, &x);
1211        return x;
1212    #else

Now, that string /should/ just read "@". Breaking on Perl_my_atof2 without libdislocator loaded yields the following:

Breakpoint 1, Perl_my_atof (s=0x122a200 "@") at numeric.c:1210
1210        Perl_my_atof2(aTHX_ s, &x);
(gdb) p s[1]
$1 = 0 '\000'
(gdb) l
1205    NV
1206    Perl_my_atof(pTHX_ const char* s)
1207    {
1208        NV x = 0.0;
1209    #ifdef USE_QUADMATH
1210        Perl_my_atof2(aTHX_ s, &x);
1211        return x;
1212    #else
1213    #  ifdef USE_LOCALE_NUMERIC
1214        PERL_ARGS_ASSERT_MY_ATOF;
(gdb) s
Perl_my_atof2 (value=<synthetic pointer>, orig=0x122a200 "@") at numeric.c:1349
1349        const char* send = s + strlen(orig); /* one past the last */
(gdb) s
1369        while (isSPACE(*s))
(gdb) p send
$2 = 0x122a201 ""

The "AAAAA" is an uninitialized poison pattern. The root cause *seems* to be that this string is not being null-terminated when it is created, presumably for the same reason as the deprecation warning. This is happening in Perl_do_vop. The case OP_BIT_AND around line 1077 does not append a null. There are three cases here: AND, OR, and XOR. OR falls through to mop_up_utf, which appends a NUL. XOR jumps to it. AND breaks from the case structure, skipping mop_up_utf. The patch which I am currently testing corrects this issue, eliminating the valgrind noise and the SEGV under libdislocator. I'm only waiting for a clean test run.

A test is difficult to add since the only outwardly visible symptoms require that the memory allocated to the constant-folded SV be non-zeroed, or that valgrind be used.

-- 
Respectfully,
Dan Collins


Thread Previous


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About