9

What I have done.

Test1

  1 #include <stdio.h>                                                              
  2                                                                                 
  3 int test[16];                                                                   
  4                                                                                 
  5 int main()                                                                      
  6 {                                                                               
  7     test[17] = -1;                                                              
  8 } 

/tmp $ gcc ./main.c -o main -fsanitize=address
/tmp $ ./main 
/tmp $

Test2

  1 #include <stdio.h>                                                              
  2                                                                                 
  3 int test[16] = {1};                                                             
  4                                                                                 
  5 int main()                                                                      
  6 {                                                                               
  7     test[17] = -1;                                                              
  8 }

 /tmp $ gcc ./main.c -o main -fsanitize=address
 /tmp $ ./main 

=================================================================
==19776==ERROR: AddressSanitizer: global-buffer-overflow on address 
...

Looks like global buffer overflow detection is not working for global variables which are placed in bss (is it so?). What are the reasons behind this?

Update:

The code which does store is not optimized out. System information:

$ gcc --version
gcc (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Alex Hoppus
  • 3,821
  • 4
  • 28
  • 47
  • have you tried with `clang` ? – Jean-François Fabre Apr 19 '18 at 16:22
  • I am not sure that assignment is even generating any code. – Eugene Sh. Apr 19 '18 at 16:22
  • @EugeneSh. it would be ok to generate no code (as it's UB anyways, and even if not, there's no observable behavior without a `volatile`), but I'd be surprised when this depends on whether the variable is initialized or not ... –  Apr 19 '18 at 16:31
  • @Jean-François Fabre I haven't tried clang, I'am interested only in gcc now. – Alex Hoppus Apr 19 '18 at 17:33
  • [godbolt of the program seems to show a call to __asan_report_store4](https://godbolt.org/g/3v8Wdt) for both gcc and clang ... hmmm – Shafik Yaghmour Apr 19 '18 at 17:57
  • Unless the checking gcc is doing is incorrect, which is not obvious from looking at the check being generated. – Shafik Yaghmour Apr 19 '18 at 18:08
  • The __asan_report_store4 is not the only thing asan shouold do. Actually, it should poison redzones around global variables in __asan_register_global hook in libasan (this hooks are places in ctors section and called on init). I'am not sure right now, but looks like this hooks are not called for global variables which are placed in bss. Also i have checked kernel address sanitizer (from linux-kernel) and looks like it detects bss global buffer overflow. – Alex Hoppus Apr 19 '18 at 18:10

2 Answers2

6

This is in FAQ:

Q: Why didn't ASan report an obviously invalid memory access in my code?

A1: If your errors is too obvious, compiler might have already optimized it out by the time Asan runs.

A2: Another, C-only option is accesses to global common symbols which are not protected by Asan (you can use -fno-common to disable generation of common symbols and hopefully detect more bugs).

Your case is probly covered by A2 so adding -fno-common should help.

The issue with common symbols (which are generated for zero-initialized global variables by default) is that, due to their weird legacy semantics, Asan can not insert redzones for them (see GCC #55739 for gory details). By supplying -fno-common you disable generation of commons and instead ask GCC to generate normal global symbols in all cases (this has a small chance of breaking ill-written programs that rely on common symbols behavior but usually it's not an issue).

yugr
  • 19,769
  • 3
  • 51
  • 96
  • Adding -fno-common flag helps here. Also, if you want, you can give a more broad explanation about this flag and how it affects asan behavior concretely. It would be helpful for other people, which would refer this question in future. Thank you. – Alex Hoppus Apr 19 '18 at 18:20
  • @AlexHoppus I tried to add some more details, let me know if it can be improved. – yugr Apr 19 '18 at 18:27
-2

Other tools, including our (Semantic Designs) CheckPointer tool, do this. (Output edited to remove some irrelevant text):

For test1.c as OP defined it:

c:\DMS\Domains\C\GCC4\Tools\CheckPointer\Example\Source>DMSCheckPointer C~GCC4 test1.c
C~GCC4 CheckPointer Version 1.2.1001
Copyright (C) 2011-2016 Semantic Designs, Inc; All Rights Reserved; SD Confidential

c:\DMS\Domains\C\GCC4\Tools\CheckPointer\Example\Source>gcc.exe -I"c:\DMS\Domains\C\GCC4\Tools\CheckPointer" -I.\Target -otest1.exe Target\test1.c <snip>

test1
*** Error: CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer
       Dereference of pointer is out of bounds.
in function: main, line: 7, file c:\DMS\Domains\C\GCC4\Tools\CheckPointer\Example\Source\test1.c

For test2.c:

c:\DMS\Domains\C\GCC4\Tools\CheckPointer\Example\Source>DMSCheckPointer C~GCC4 test2.c
C~GCC4 CheckPointer Version 1.2.1001
Copyright (C) 2011-2016 Semantic Designs, Inc; All Rights Reserved; SD Confidential

c:\DMS\Domains\C\GCC4\Tools\CheckPointer\Example\Source>gcc.exe -I"c:\DMS\Domains\C\GCC4\Tools\CheckPointer" -I.\Target -otest2.exe Target\test2.c <snip>

test2
*** Error: CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer
       Dereference of pointer is out of bounds.
in function: main, line: 7, file c:\DMS\Domains\C\GCC4\Tools\CheckPointer\Example\Source\test2.c

CheckPointer doesn't need "redzones" around data; it checks accesses against the language semantics. That means it will, for example, detect accesses off the end of a char array anywhere in a struct, whether the struct is a local (stack) variable, in the heap, in thread local storage, or embedded in some other structure.

The "odd phrasing" related to "CWE-119" isn't our choice of words, it is defined by the standard for Common Weakness Enumeration. CheckPointer reports errors using the CWE definitions, classifications and descriptions.

Ira Baxter
  • 93,541
  • 22
  • 172
  • 341