steleman / address-sanitizer

Automatically exported from code.google.com/p/address-sanitizer
0 stars 0 forks source link

unknown-crash with annotate_contiguous_container #377

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Not sure if this is a bug, or just expected behaviour:

With the following C program I get an unknown-crash. The problem appears to be 
a stray shadow value of 4 being left behind by a call to 
__sanitizer_annotate_contiguous_container on a buffer with a size that isn't 8 
aligned that isn't cleared afterwards. I was under the impression this was 
supposed to work as long as the unaligned size is the size of the actual buffer.

#include <stdio.h>                                                              

#include <stdint.h>                                                             

// Not 8 aligned                                                                

#define SIZ 132                                                                 

struct foo {                                                                    

  uint32_t a;                                                                                                                                                             
  char buf[SIZ] __attribute ((aligned(8)));                                                                                                                               
};                                                                              

void setup_stack() {                                                            

  struct foo blah1;                                                                                                                                                       
  struct foo blah2;                                                                                                                                                       
  struct foo blah3;                                                                                                                                                       
  printf("%p %p %p\n", blah1, blah2, blah3);                                                                                                                              
  char *lol = &(blah2.buf);                                                                                                                                               
  printf("lol = %p\n", lol);                                                                                                                                              

  __sanitizer_annotate_contiguous_container(lol, lol+SIZ, lol+SIZ, lol+0);                                                                                                
  __sanitizer_annotate_contiguous_container(lol, lol+SIZ, lol+0, lol+SIZ);                                                                                                
  printf("setup_stack done\n");                                                                                                                                           
}                                                                               

void crash() {                                                                  

  volatile char buf[1024];                                                                                                                                                
  printf("buf = %p\n", buf);                                                                                                                                              
  int i;                                                                                                                                                                  
  for (i = 0; i < 1024; i++) {                                                                                                                                            
    printf("%d\n", buf[i]);                                                                                                                                               
  }                                                                                                                                                                       
}                                                                               

int main(int argc, char *argv[]) {                                              

  setup_stack();                                                                                                                                                          
  crash();                                                                                                                                                                
  return 0;                                                                                                                                                               
}    

Compiling with clang (r223108) on 64-bit Linux and running:

$ clang -fsanitize=address asan_crash.c
$ ./a.out

SUMMARY: AddressSanitizer: unknown-crash ??:0 ??
Shadow bytes around the buggy address:
  0x100073e28540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100073e28550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100073e28560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100073e28570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100073e28580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100073e28590: 00 00 00[04]00 00 00 00 00 00 00 00 00 00 00 00
  0x100073e285a0: 00 00 00 00 00 00 00 00 f2 f2 f2 f2 f2 f2 f2 f2
  0x100073e285b0: f2 f2 f2 f2 f2 f2 f2 f2 04 f3 f3 f3 00 00 00 00
  0x100073e285c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100073e285d0: 00 00 00 00 f1 f1 f1 f1 04 f2 04 f2 00 f3 f3 f3
  0x100073e285e0: 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
  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
==9248==ABORTING

Original issue reported on code.google.com by och...@chromium.org on 22 Feb 2015 at 8:48

GoogleCodeExporter commented 9 years ago
Small mistake in the provided code, doesn't affect the result.

#include <stdio.h>                                                              

#include <stdint.h>                                                             

// Not 8-aligned                                                                

#define SIZ 132                                                                 

struct foo {                                                                    

  uint32_t a;                                                                                                                                                             
  char buf[SIZ] __attribute ((aligned(8)));                                                                                                                               
};                                                                              

void setup_stack() {                                                            

  struct foo blah1;                                                                                                                                                       
  struct foo blah2;                                                                                                                                                       
  struct foo blah3;                                                                                                                                                       
  printf("%p %p %p\n", &blah1, &blah2, &blah3);                                                                                                                           
  char *lol = &(blah2.buf);                                                                                                                                               
  printf("lol = %p\n", lol);                                                                                                                                              

  __sanitizer_annotate_contiguous_container(lol, lol+SIZ, lol+SIZ, lol+0);                                                                                                
  __sanitizer_annotate_contiguous_container(lol, lol+SIZ, lol+0, lol+SIZ);                                                                                                
  printf("setup_stack done\n");                                                                                                                                           
}                                                                               

void crash() {                                                                  

  volatile char buf[1024];                                                                                                                                                
  printf("buf = %p\n", buf);                                                                                                                                              
  int i;                                                                                                                                                                  
  for (i = 0; i < 1024; i++) {                                                                                                                                            
    printf("%d\n", buf[i]);                                                                                                                                               
  }                                                                                                                                                                       
}                                                                               

int main(int argc, char *argv[]) {                                              

  setup_stack();                                                                                                                                                          
  crash();                                                                                                                                                                
  return 0;                                                                                                                                                               
}  

Original comment by och...@chromium.org on 22 Feb 2015 at 8:53

GoogleCodeExporter commented 9 years ago
The first argument must be aligned. 
We actually submitted a CHECK for that yesterday (it got reverted, but will get 
committed again soon). 

http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_report.cc?r1
=227559&r2=230019&pathrev=230019

Original comment by konstant...@gmail.com on 24 Feb 2015 at 2:02

GoogleCodeExporter commented 9 years ago
Kostya,
Looking at comment #0, I don't think this is the issue with the alignment of 
the first argument of __sanitizer_annotate_contiguous_container.  The issue 
seems to be that for some reason we get an "unknown crash" report.

Original comment by timurrrr@google.com on 24 Feb 2015 at 12:23

GoogleCodeExporter commented 9 years ago
Yep the first argument is aligned. The problems seems to be that in some cases 
having a misaligned buffer size and properly calling 
__sanitizer_annotate_contiguous_container to reset the buffer to the unpoisoned 
state could leave behind trailing shadow values that will cause errors in 
another frame (the "crash" function in this case).

Original comment by och...@chromium.org on 24 Feb 2015 at 5:26

GoogleCodeExporter commented 9 years ago
I can provide a compiled binary for you guys to look at. Just from the source 
code, assuming that the buffer is 8-aligned, is a crash expected?

Original comment by och...@chromium.org on 24 Feb 2015 at 5:31

GoogleCodeExporter commented 9 years ago

Original comment by infe...@chromium.org on 24 Feb 2015 at 8:29

GoogleCodeExporter commented 9 years ago
isn't this the case described in the comments in 
include/sanitizer/common_interface_defs.h:

  // For AddressSanitizer, 'beg' should be 8-aligned and 'end' should
  // be either 8-aligned or it should point to the end of a separate heap-,
  // stack-, or global- allocated buffer.

Note the the struct foo is 8-aligned due to the first field, and thus the end 
of 
buf is not the end of the foo object -- there is an extra 4-byte padding. 
This is that padding that is not get unpoisoned and you end up with poisoned 
region on stack. 

This is an unfortunate limitation of asan caused by it's alignment 
requirements. 

Original comment by konstant...@gmail.com on 24 Feb 2015 at 8:53

GoogleCodeExporter commented 9 years ago
Thanks for the clarification. Out of curiosity, why would this not crash when 
there are only 1 or 2 of those foo structs on the stack?

Original comment by och...@chromium.org on 24 Feb 2015 at 10:23

GoogleCodeExporter commented 9 years ago
no idea off the top of my head.
something else comes into play and unpoisons the shadow...

Original comment by konstant...@gmail.com on 24 Feb 2015 at 10:36