public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* sanitizer not detecting buffer overrun
@ 2023-11-12  0:01 Navin P
  2023-11-12  2:34 ` Sam James
  2023-11-12  9:37 ` Jonathan Wakely
  0 siblings, 2 replies; 5+ messages in thread
From: Navin P @ 2023-11-12  0:01 UTC (permalink / raw)
  To: gcc-help

[-- Attachment #1: Type: text/plain, Size: 1370 bytes --]

Hi,

Why doesn't sanitizer catch this ? The value ptr is a valid address but it
did a buffer overflow into another object a3 and then it is a valid
address. This is from production code where a ptr whose base was different
array address overflows into another array and becomes a valid address.
This is not caught by address sanitizer.

   - How do you detect this and fix this ? Are there any alternative
   datastructures in C or C++ that prevent these kind of overruns
   Please don't increase the cookie or red zone size between arrays. Again
   sizes more than the cookie or redzone between arrays or objects can be
   overrun



navin@Navin-acer-5740:~/cpp$ gcc -fsanitize=address sanitizer.c
navin@Navin-acer-5740:~/cpp$ ./a.out
a1=(0x614000000040-0x6140000001d0) a2=(0x614000000240-0x6140000003d0)
a3=(0x614000000440-0x6140000005d0)
value=0, ptr=0x614000000498
ptr lies in the array a3
navin@Navin-acer-5740:~/cpp$ cat sanitizer.c
#include<stdlib.h>
#include<stdio.h>
int main(){
int *a1=calloc(100,sizeof(int));
int *a2=calloc(100,sizeof(int));
int *a3=calloc(100,sizeof(int));

printf("a1=(%p-%p) a2=(%p-%p) a3=(%p-%p)\n",a1,a1+100,a2,a2+100,a3,a3+100);
int *ptr=a2;
ptr+=150;
printf("value=%d, ptr=%p\n",*ptr,ptr);
if(a3<=ptr && ptr<=a3+100) printf("ptr lies in the array a3\n");

free(a1);
free(a2);
free(a3);
}
navin@Navin-acer-5740:~/cpp$


Regards,
Navin

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: sanitizer not detecting buffer overrun
  2023-11-12  0:01 sanitizer not detecting buffer overrun Navin P
@ 2023-11-12  2:34 ` Sam James
  2023-11-12  5:14   ` Navin P
  2023-11-12  9:37 ` Jonathan Wakely
  1 sibling, 1 reply; 5+ messages in thread
From: Sam James @ 2023-11-12  2:34 UTC (permalink / raw)
  To: Navin P; +Cc: gcc-help


Navin P via Gcc-help <gcc-help@gcc.gnu.org> writes:

> Hi,
>
> Why doesn't sanitizer catch this ? The value ptr is a valid address but it
> did a buffer overflow into another object a3 and then it is a valid
> address. This is from production code where a ptr whose base was different
> array address overflows into another array and becomes a valid address.
> This is not caught by address sanitizer.
>
>    - How do you detect this and fix this ? Are there any alternative
>    datastructures in C or C++ that prevent these kind of overruns
>    Please don't increase the cookie or red zone size between arrays. Again
>    sizes more than the cookie or redzone between arrays or objects can be
>    overrun

You appear to have answered your own question unless I'm
misunderstanding you?

ASAN does not claim to capture every possible overflow. It has to strike
a balance, for one, between performance and catching errors (it has some
other trade-offs too).

Are you interested in a broad technical discussion about alternatives
to redzones and other mitigations like SSP (which is unrelated here...)
or are you wondering specifically just about how ASAN works and why it
missed something?

To me, the intent of your email seems mixed.

>
>
>
> navin@Navin-acer-5740:~/cpp$ gcc -fsanitize=address sanitizer.c
> navin@Navin-acer-5740:~/cpp$ ./a.out
> a1=(0x614000000040-0x6140000001d0) a2=(0x614000000240-0x6140000003d0)
> a3=(0x614000000440-0x6140000005d0)
> value=0, ptr=0x614000000498
> ptr lies in the array a3
> navin@Navin-acer-5740:~/cpp$ cat sanitizer.c
> #include<stdlib.h>
> #include<stdio.h>
> int main(){
> int *a1=calloc(100,sizeof(int));
> int *a2=calloc(100,sizeof(int));
> int *a3=calloc(100,sizeof(int));
>
> printf("a1=(%p-%p) a2=(%p-%p) a3=(%p-%p)\n",a1,a1+100,a2,a2+100,a3,a3+100);
> int *ptr=a2;
> ptr+=150;
> printf("value=%d, ptr=%p\n",*ptr,ptr);
> if(a3<=ptr && ptr<=a3+100) printf("ptr lies in the array a3\n");
>
> free(a1);
> free(a2);
> free(a3);
> }
> navin@Navin-acer-5740:~/cpp$
>
>
> Regards,
> Navin


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: sanitizer not detecting buffer overrun
  2023-11-12  2:34 ` Sam James
@ 2023-11-12  5:14   ` Navin P
  2023-11-12 10:02     ` Xi Ruoyao
  0 siblings, 1 reply; 5+ messages in thread
From: Navin P @ 2023-11-12  5:14 UTC (permalink / raw)
  To: Sam James; +Cc: gcc-help

Hi,

On Sun, Nov 12, 2023 at 8:06 AM Sam James <sam@gentoo.org> wrote:
>
>
> Navin P via Gcc-help <gcc-help@gcc.gnu.org> writes:
>
> > Hi,
> >
> > Why doesn't sanitizer catch this ? The value ptr is a valid address but it
> > did a buffer overflow into another object a3 and then it is a valid
> > address. This is from production code where a ptr whose base was different
> > array address overflows into another array and becomes a valid address.
> > This is not caught by address sanitizer.
> >
> >    - How do you detect this and fix this ? Are there any alternative
> >    datastructures in C or C++ that prevent these kind of overruns
> >    Please don't increase the cookie or red zone size between arrays. Again
> >    sizes more than the cookie or redzone between arrays or objects can be
> >    overrun
>
> You appear to have answered your own question unless I'm
> misunderstanding you?
>
> ASAN does not claim to capture every possible overflow. It has to strike
> a balance, for one, between performance and catching errors (it has some
> other trade-offs too).
>
> Are you interested in a broad technical discussion about alternatives
> to redzones and other mitigations like SSP (which is unrelated here...)
> or are you wondering specifically just about how ASAN works and why it
> missed something?
>
I was asking if there exists any way to catch such errors ?
Assuming right now there doesn't exist any such implementation i was
thinking of an approach as to how it should be.
All pointers are null by default. Every pointer has a [start,end) . pointer
arithmetic even though it is not dereferenced cannot go beyond the end.
The start,end can be stored in a hash table for each pointer and it should
always stay within the bounds. Assignment of pointers copies the [start,end]
range to the lvalue from the rvalue.

ptr=ptr+x if x is greater than array size +1 is undefined
ptr=ptr+x-y where x=array size+10 and y=11 is defined

Do you think this is right and covers all cases ? Are there better ways ?
What does it take to implement this ? Maybe I can try or is it too complicated ?

> To me, the intent of your email seems mixed.
>
> >
> >
> >
> > navin@Navin-acer-5740:~/cpp$ gcc -fsanitize=address sanitizer.c
> > navin@Navin-acer-5740:~/cpp$ ./a.out
> > a1=(0x614000000040-0x6140000001d0) a2=(0x614000000240-0x6140000003d0)
> > a3=(0x614000000440-0x6140000005d0)
> > value=0, ptr=0x614000000498
> > ptr lies in the array a3
> > navin@Navin-acer-5740:~/cpp$ cat sanitizer.c
> > #include<stdlib.h>
> > #include<stdio.h>
> > int main(){
> > int *a1=calloc(100,sizeof(int));
> > int *a2=calloc(100,sizeof(int));
> > int *a3=calloc(100,sizeof(int));
> >
> > printf("a1=(%p-%p) a2=(%p-%p) a3=(%p-%p)\n",a1,a1+100,a2,a2+100,a3,a3+100);
> > int *ptr=a2;
> > ptr+=150;
> > printf("value=%d, ptr=%p\n",*ptr,ptr);
> > if(a3<=ptr && ptr<=a3+100) printf("ptr lies in the array a3\n");
> >
> > free(a1);
> > free(a2);
> > free(a3);
> > }
> > navin@Navin-acer-5740:~/cpp$
> >
> >
> > Regards,
> > Navin
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: sanitizer not detecting buffer overrun
  2023-11-12  0:01 sanitizer not detecting buffer overrun Navin P
  2023-11-12  2:34 ` Sam James
@ 2023-11-12  9:37 ` Jonathan Wakely
  1 sibling, 0 replies; 5+ messages in thread
From: Jonathan Wakely @ 2023-11-12  9:37 UTC (permalink / raw)
  To: Navin P; +Cc: gcc-help

[-- Attachment #1: Type: text/plain, Size: 1899 bytes --]

On Sun, 12 Nov 2023, 00:02 Navin P via Gcc-help, <gcc-help@gcc.gnu.org>
wrote:

> Hi,
>
> Why doesn't sanitizer catch this ? The value ptr is a valid address but it
> did a buffer overflow into another object a3 and then it is a valid
> address. This is from production code where a ptr whose base was different
> array address overflows into another array and becomes a valid address.
> This is not caught by address sanitizer.
>
>    - How do you detect this and fix this ? Are there any alternative
>    datastructures in C or C++ that prevent these kind of overruns
>

Use std::vector instead of allocating arrays using calloc. Or allocate
arrays yourself and then use std::span to access into them. Performing
pointer arithmetic and indexing via pointers is simply not going to be
safe, either get it right, or stop doing it.

Both vector and span have checks that can be enabled to diagnose when you
overflow. Raw pointers don't.


   Please don't increase the cookie or red zone size between arrays. Again
>    sizes more than the cookie or redzone between arrays or objects can be
>    overrun
>
>
>
> navin@Navin-acer-5740:~/cpp$ gcc -fsanitize=address sanitizer.c
> navin@Navin-acer-5740:~/cpp$ ./a.out
> a1=(0x614000000040-0x6140000001d0) a2=(0x614000000240-0x6140000003d0)
> a3=(0x614000000440-0x6140000005d0)
> value=0, ptr=0x614000000498
> ptr lies in the array a3
> navin@Navin-acer-5740:~/cpp$ cat sanitizer.c
> #include<stdlib.h>
> #include<stdio.h>
> int main(){
> int *a1=calloc(100,sizeof(int));
> int *a2=calloc(100,sizeof(int));
> int *a3=calloc(100,sizeof(int));
>
> printf("a1=(%p-%p) a2=(%p-%p) a3=(%p-%p)\n",a1,a1+100,a2,a2+100,a3,a3+100);
> int *ptr=a2;
> ptr+=150;
> printf("value=%d, ptr=%p\n",*ptr,ptr);
> if(a3<=ptr && ptr<=a3+100) printf("ptr lies in the array a3\n");
>
> free(a1);
> free(a2);
> free(a3);
> }
> navin@Navin-acer-5740:~/cpp$
>
>
> Regards,
> Navin
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: sanitizer not detecting buffer overrun
  2023-11-12  5:14   ` Navin P
@ 2023-11-12 10:02     ` Xi Ruoyao
  0 siblings, 0 replies; 5+ messages in thread
From: Xi Ruoyao @ 2023-11-12 10:02 UTC (permalink / raw)
  To: Navin P, Sam James; +Cc: gcc-help

On Sun, 2023-11-12 at 10:44 +0530, Navin P via Gcc-help wrote:
> I was asking if there exists any way to catch such errors ?
> Assuming right now there doesn't exist any such implementation i was
> thinking of an approach as to how it should be.
> All pointers are null by default. Every pointer has a [start,end) . pointer
> arithmetic even though it is not dereferenced cannot go beyond the end.
> The start,end can be stored in a hash table for each pointer and it should
> always stay within the bounds. Assignment of pointers copies the [start,end]
> range to the lvalue from the rvalue.
> 
> ptr=ptr+x if x is greater than array size +1 is undefined
> ptr=ptr+x-y where x=array size+10 and y=11 is defined
> 
> Do you think this is right and covers all cases ? Are there better ways ?
> What does it take to implement this ? Maybe I can try or is it too complicated ?

MPX was implemented like this, but it was too problematic to be
maintained or used in practice so it was removed in GCC 9.  Intel also
removed MPX in recent CPU models.

Read the wiki page for more info (including its undoings):
https://gcc.gnu.org/wiki/Intel%20MPX%20support%20in%20the%20GCC%20compiler

Hardware-assisted address sanitizer (hwasan) is a modern replacement of
MPX-like approaches, but currently it's only implemented on AArch64. 
(The GCC support for hwasan on x86_64 is already added, but Intel has
not shipped any CPUs supporting it as at now.)

On an AArch64 hwasan correctly detects this overrun:

==50998==ERROR: HWAddressSanitizer: tag-mismatch on address 0xefeaffff03f8 at pc 0xffff8666086c
READ of size 4 at 0xefeaffff03f8 tags: cd/ff (ptr/mem) in thread T0
    #0 0xffff8666086c in SigTrap<2> ../../../../libsanitizer/hwasan/hwasan_checks.h:28
    #1 0xffff8666086c in CheckAddress<(__hwasan::ErrorAction)0, (__hwasan::AccessType)0, 2> ../../../../libsanitizer/hwasan/hwasan_checks.h:108
    #2 0xffff8666086c in __hwasan_load4 ../../../../libsanitizer/hwasan/hwasan.cpp:455
    #3 0xaaaadada0b90 in main /home/xry111/t.c:11
    #4 0xffff8644b510 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #5 0xffff8644b5f4 in __libc_start_main_impl ../csu/libc-start.c:360
    #6 0xaaaadada092c in _start ../sysdeps/aarch64/start.S:98

[0xefeaffff0340,0xefeaffff04e0) is a small allocated heap chunk; size: 416 offset: 184

Cause: heap-buffer-overflow
0xefeaffff03f8 is located 200 bytes after a 400-byte region [0xefeaffff01a0,0xefeaffff0330)
allocated here:
    #0 0xffff8665a690 in __sanitizer_calloc ../../../../libsanitizer/hwasan/hwasan_allocation_functions.cpp:116
    #1 0xaaaadada0adc in main /home/xry111/t.c:5
    #2 0xffff8644b510 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #3 0xffff8644b5f4 in __libc_start_main_impl ../csu/libc-start.c:360
    #4 0xaaaadada092c in _start ../sysdeps/aarch64/start.S:98


-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2023-11-12 10:02 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-12  0:01 sanitizer not detecting buffer overrun Navin P
2023-11-12  2:34 ` Sam James
2023-11-12  5:14   ` Navin P
2023-11-12 10:02     ` Xi Ruoyao
2023-11-12  9:37 ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).