US-CERT Vulnerability Note VU#162289
Robert C. Seacord
rcs@cert.org
Thu Apr 10 13:26:00 GMT 2008
Gerald,
Here is another version of the program (same compiler version/flags).
#include <stdio.h>
void test_signed(char *buf) {
signed int len;
len = 1<<30;
printf("buf = %p; buf+len = %p; buf+len < buf = %d %d",
buf, buf+len, buf+len < buf, (uintptr_t)buf+len < (uintptr_t)buf);
if((buf+len < buf) != ((uintptr_t)buf+len < (uintptr_t)buf))
printf(" BUG!");
printf("\n");
}
void test_unsigned(char *buf) {
unsigned int len;
len = 1<<30;
printf("buf = %p; buf+len = %p; buf+len < buf = %d %d",
buf, buf+len, buf+len < buf, (uintptr_t)buf+len < (uintptr_t)buf);
if((buf+len < buf) != ((uintptr_t)buf+len < (uintptr_t)buf))
printf(" BUG!");
printf("\n");
}
int main(void) {
test_signed(0);
test_signed((char*)0x70000000);
test_signed((char*)0xf0000000);
test_unsigned(0);
test_unsigned((char*)0x70000000);
test_unsigned((char*)0xf0000000);
return 0;
}
output:
buf = 00000000; buf+len = 40000000; buf+len < buf = 0 0
buf = 70000000; buf+len = B0000000; buf+len < buf = 0 0
buf = F0000000; buf+len = 30000000; buf+len < buf = 1 1
buf = 00000000; buf+len = 40000000; buf+len < buf = 0 0
buf = 70000000; buf+len = B0000000; buf+len < buf = 0 0
buf = F0000000; buf+len = 30000000; buf+len < buf = 1 1
The unsigned test was one we performed on the gcc versions. I added the
signed test, but it didn't make a difference on Visual Studio. My
understanding is that it shouldn't, because the real issue here is
pointer arithmetic and the resulting type should always be a pointer.
rCs
> Robert C. Seacord wrote:
>
>> void f(char *buf) {
>> unsigned int len = len = 0xFFFFFF00;
>>
>> if (buf+len < buf) puts("true");
>>
>> }
>>
>
> You need to be more precise. That is not the same example
> that you quoted for GCC.
>
> In fact, if you vary the criteria too much, you will find
> situations where GCC already behaved that way. The test in
> the following example is optimized out by old versions of
> GCC (certainly my version 3.4.5 compiler does it, with no
> warnings even when using -Wall):
>
> int f(char *buf, int i)
> {
> i = 1<<30;
>
> if ((int)buf + i < (int)buf)
> return 0;
>
> return 1;
> }
>
> That's quite a bit less changed than your example, which
> brings unsigned-ness into the picture. [This is exactly
> the problem--signed overflow and pointer overflow aren't
> defined, unlike unsigned overflow.]
>
> Given that current Microsoft compilers reportedly exhibit
> this behavior, it sounds like the advisory is going to at
> least need some significant rewriting. :-)
>
> -Jerry
>
More information about the Gcc
mailing list