When I originally wrote this response, it appears I glossed over some misunderstandings that you hold. These misunderstandings would likely prevent you from understanding my answer. To be clear, I'm going to make this text large to draw emphasis, not to be disrespectful:
Many of the terms you use don't mean what you seem to think they mean.
- "the third member of
memcpy" is non-existent because
memcpy is a function, not a
- "I can’t perform a buffer overflow, since there is
len" and I can't run out of petrol, since there is petrol. Am I begging the question? It seems like a fitting analogy to me, especially since theoretically speaking, your code could invoke a buffer overflow.
- "All I can do is to set
len to a value larger than the one allocated to
string.st.data. This is a buffer underflow..." No, that is not the definition of a buffer underflow. A buffer underflow occurs when you access out-of-bounds an array using a negative index, or an index that would cause pointer arithmetic wrapping to occur. The latter may be possible for some configurations (even on "64-bit systems", whatever that means), but I doubt this is what you meant when you were writing these words, because you then followed them up with:
- "... enabling me to read unallocated memory." I think perhaps you meant "uninitialised memory". To be clear, I think you meant to state that you've allocated an excess and left the excess uninitialised, and perhaps you want to do something about that (see
Let us consider
char *fubar = NULL; for a moment... this kind of pointer generally has a zero value. Dereferencing it is considered a null pointer dereference, but if we write something like
0["hello"] we get the same as
"hello" (that is
'h'). Thus, a null pointer dereference can be used in attacks when the attacker controls the expression between the square braces (as they do in your situation).
Coming back to the
fubar thing; let's say we
memset(&fubar, UCHAR_MAX, sizeof fubar);, now
fubar is all 1-bits, meaning it might be an address that is the largest address our system could (theoretically) accommodate. What if we access
fubar? How can you access the element after the largest address? Does the address then wrap back around? Technically, all of this is undefined behaviour, but if I were to name that on common architecture, it would be:
- Arithmetic overflow of a pointer, leading into...
- Null pointer dereference, and/or potentially a buffer underflow.
does a buffer underflow on
memcpy allow remote code execution ?
A buffer underflow may allow an attacker to overwrite function pointers located in the regions of memory before the array in question. If those function pointers are made to point at shellcode, that shellcode may be executed when they're invoked later on.
In this somewhat obscure piece of code, it appears there's a risk of buffer underflow when
int has a wider domain than
ntohl(string.st.len)+1 would cause the
uint32_t value to be converted to an
int type. Consider, for example, if
-4294967296 (which is one less than
0 - UINT32_MAX) and
4294967295... this would essentially be a 33-bit
int with padding to pad out to the width of a byte; uncommon, but possible. In this circumstance, the expression
ntohl(string.st.len)+1 is not
uint32_t in type; it's
int in type, and rather than wrapping back to 0 when unsigned integer overflow occurs, it probably wraps to
-4294967296 when signed integer overflow occurs.
If you're looking for a guarantee against buffer underflow, use the
U integer literal suffix (i.e.
ntohl(string.st.len)+1U). Then in that situation, you'll end up with the expression being either a
uint32_t or an
unsigned int (depending on which type has the largest domain).
If you consider that
ntohl(string.st.len) may return one less than the maximum value for that unsigned type (whatever it is), then
len=ntohl(string.st.len)+1 will result in the maximum value,
malloc(len+1) will cause unsigned wrapping so you'll end up invoking
malloc(0) and then
command[len]=0 will write well and truly beyond the end of the array. Then, of course, you'll also have a problem with
memcpy(command,string.st.data,len); (this is a buffer overflow).
Buffer underflows and overflows aren't the only risk. If you don't check the return value of
NULL then a null pointer dereference can be used to cause arbitrary code execution. This implies that you should have a method to communicate
malloc failures back to the caller. It also implies that you could use that same method to check and communicate that wrapping problem back to the caller.