Quoted from page 7 of the book;
The following overrun is a little more interesting:
bool CopyStructs(InputFile* pInFile, unsigned long count)
unsigned long i;
m_pStructs = new Structs[count];
for(i = 0; i < count; i++)
How can this fail? Consider that when you call the C++ new operator, it is similar to the following code:
ptr = malloc(sizeof(type) * count);
If the user supplies the count, it isn't hard to specify a value that overflows the multiplication operation internally. You'll then allocate a buffer much smaller than you need, and the attacker is able to write over your buffer. The upcoming C++ compiler in Microsoft Visual Studio 2005 contains an internal check to prevent this problem.
Is it because the count value that will be used to calculate the buffer's size can be too long? Will the size of the actual buffer will be truncated to something smaller while count remains the same?
So I wrote something to test a few theories.
const unsigned long COUNT = 18446744073709551615; // Biggest possible unsigned long on my system.
char* buf = new char[COUNT];
printf("Count: %u\n", COUNT);
printf("Strlen: %i\n", strlen(buf));
unsigned long i;
for(i = 0; i < COUNT; i++)
buf[i] = 'A';
Debugging this gives me the following error;
"error C2148: total size of array must not exceed 0x7fffffff". The hex value of 0x7fffffffequals 2147483647 in decimal, which is the biggest possible value of a signed int.
When I change the count from 18446744073709551615 to 99999999999999999 I get the following output;
What, no errors? So obviously the new operator doesn't like to get unsigned long values And does indeed create a smaller buffer, but ALSO adjust the value of count, so that overflows don't occur in the for loop. Even when count was declared as constant. Is this because of the internal check the compiler performed? Will it just throw the C2148 error? Is this what the author was talking about?
Maybe I'm making things too complicated for myself :-X
Edit: Ugh, so I found out the Visual C++ compiler treats unsigned longs as 4 bytes. So they're like unsigned ints. I can imagine the risk when you think you're dealing with 8 bytes instead of 4.