The following example can be found in many places on the internet:
The following code excerpt from OpenSSH 3.3 demonstrates a classic case of integer overflow: (bad code) Example Language: C
nresp = packet_get_int();
if (nresp > 0) {
response = xmalloc(nresp*sizeof(char*));
for (i = 0; i < nresp; i++) response[i] = packet_get_string(NULL);
}
If nresp has the value 1073741824 and sizeof(char*) has its typical value of 4, then the result of the operation
nresp*sizeof(char*)overflows, and the argument to xmalloc() will be 0. Most malloc() implementations will happily allocate a 0-byte buffer, causing the subsequent loop iterations to overflow the heap buffer response.
If nresp is an int and sizeof() returns a size_t, which in x86_64 is essentially unsigned long, the result should be unsigned long. Is the problem with the above that the argument for xmalloc is an int? Or does the example assume IA32? If not, what's the problem?
True, yet the product can overflow when
INT_MAX > ULONG_MAX/sizeof(char*). (e.g.intandunsigned long,size_tboth 32-bit.)Even when
nresp > 0andsizeof(char*)is a smallish value, computations likenresp*sizeof(char*)risk overflow given it is anint * size_t.C does not specify
size_tto be wider thanint, althoughsize_tis some unsigned type.size_tmay only have 1 more bit thanintand overflow can occurs whensizeof(char*)is greater than 2.(On select machine,
SIZE_MAX <= INT_MAXis possible.)Robust code prevents/detects potential overflow without making undue assumptions about the width of
size_tandint.Simple to add a range test
On machines where
SIZE_MAX/sizeof(char*) > UINT_MAX, I'd expectresponse = (unsigned) nresp > SIZE_MAX/sizeof(char*) ? NULL : xmalloc(nresp*sizeof(char*));to optimize toresponse = xmalloc(nresp*sizeof(char*));IMO, better as
response = (unsigned) nresp > SIZE_MAX/sizeof(char*) ? NULL : xmalloc(sizeof response[0] * (unsigned) nresp);