Skip to content

Commit a1325b902d ("try" support) can read uninitialized memory #18540

Closed
@hvds

Description

@hvds

As initially reported by George Greer to p5p, building with sanitize=address shows that this commit causes reads of uninitialized memory, for example when a sort block exits with an explicit return:

==3168==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61c000000018 at pc 0x560bb1fe782a bp 0x7ffcd34f9a10 sp 0x7ffcd34f9a00
READ of size 1 at 0x61c000000018 thread T0
    #0 0x560bb1fe7829 in Perl_pp_return /src/perl/git/pp_ctl.c:2575
    #1 0x560bb1ee2642 in Perl_runops_standard /src/perl/git/run.c:41
    #2 0x560bb211eb85 in S_sortcv /src/perl/git/pp_sort.c:1066
    #3 0x560bb2145825 in dynprep /src/perl/git/pp_sort.c:188
    #4 0x560bb2145825 in S_sortsv_flags_impl /src/perl/git/pp_sort.c:358
    #5 0x560bb2145825 in Perl_sortsv_flags /src/perl/git/pp_sort.c:556
    #6 0x560bb2147f6b in Perl_pp_sort /src/perl/git/pp_sort.c:909
    #7 0x560bb1ee2642 in Perl_runops_standard /src/perl/git/run.c:41
    #8 0x560bb1cdd700 in S_run_body /src/perl/git/perl.c:2738
    #9 0x560bb1cdd700 in perl_run /src/perl/git/perl.c:2666
    #10 0x560bb1c57636 in main /src/perl/git/miniperlmain.c:116
    #11 0x7f6ef677abf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
    #12 0x560bb1c576d9 in _start (/src/perl/git/miniperl+0xe06d9)

0x61c000000018 is located 104 bytes to the left of 1872-byte region [0x61c000000080,0x61c0000007d0)
allocated by thread T0 here:
    #0 0x7f6ef741db40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40)
    #1 0x560bb1e66c82 in Perl_safesysmalloc /src/perl/git/util.c:161

SUMMARY: AddressSanitizer: heap-buffer-overflow /src/perl/git/pp_ctl.c:2575 in Perl_pp_return
Shadow bytes around the buggy address:
  0x0c387fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c387fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c387fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c387fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c387fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c387fff8000: fa fa fa[fa]fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c387fff8010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c387fff8020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c387fff8030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c387fff8040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c387fff8050: 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
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  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
==3168==ABORTING

This occurs at least when the cxix found at the start of pp_return() is negative, and during a normal build causes lib/unicore/mktables to fail.

The diff below is sufficient to get make minitest to pass, but it isn't clear if it fully solves the problem: for example, other code in pp_return() also checks for cxix < cxstack_ix. It seems likely to me that the whole CxTRY test should probably be moved later in the function.

@leonerd suggests we apply this diff; @tonycoz or @iabyn could you check it over?

Hugo

diff --git a/pp_ctl.c b/pp_ctl.c
index 9e440dcd9b..6ef2ba17bb 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -2487,11 +2487,13 @@ PP(pp_return)
     I32 cxix = dopopto_cursub();
 
 again:
-    cx = &cxstack[cxix];
-    if(CxTRY(cx)) {
-        /* This was a try {}. keep going */
-        cxix = dopoptosub_at(cxstack, cxix - 1);
-        goto again;
+    if (cxix >= 0) {
+        cx = &cxstack[cxix];
+        if (CxTRY(cx)) {
+            /* This was a try {}. keep going */
+            cxix = dopoptosub_at(cxstack, cxix - 1);
+            goto again;
+        }
     }
 
     assert(cxstack_ix >= 0);

Metadata

Metadata

Assignees

No one assigned

    Labels

    smokeReport derived from smoke-testingtype-core

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions