Say for instance I have a TCP server that needs to know the unsigned integer (uint32_t
) size of some arbitrary data before receiving said data. In order to receive the arbitrary data the client would first have to send a the size bytes of a uint32_t
unsigned integer encoded using htonl
e.g. (client side):
uint32_t size_int = // some size integer calculated before
uint32_t nbo_data = htonl(size_int);
// send nbo_data to server...
To decode the bytes the server would do the following:
// First receive nbo_bytes into receive_buffer...
uint32_t nbo_data;
memcpy(&nbo_data, receive_buffer, sizeof(uint32_t));
uint32_t size_int = ntohl(nbo_data);
Now say for instance an attacker sent uint32_t bytes encoded with htonl
that exceeded the UINT32_MAX
value/4294967295. How could I prevent an integer overflow/underflow from occurring? Would a simple cast to a larger datatype i.e. long long
and bounds check be enough? Like so:
char receive_buffer[1024];
// First receive nbo_bytes into receive_buffer...
uint32_t nbo_data;
memcpy(&nbo_data, receive_buffer, sizeof(uint32_t));
long long size_int = (long long)ntohl(nbo_data);
// Check if size_int > UINT32_MAX or size_int < 0 here
// If true raise error.
Or is there a better approach/is this approach flawed and ineffective?
Now say for instance an attacker sent uint32_t bytes encoded with
htonl
that exceeded theUINT32_MAX
value/4294967295.
As has been expressed in comments, that's impossible.
htonl()
just transforms one four-byte sequence into another, such that the resulting sequence is a big-endian (network order) representation of the value of the argument. If the host machine uses big-endian order natively then that is a no-op.
uint32_t
expresses an unsigned integer type with 32 value bits and no padding bits. The interpretation of such a value is mandated by the language specifications, and it leaves no room for a 32-bit pattern that is not interpretable as a uint32_t
. The value of UINT32_MAX
follows from that.
Not even by maliciously twiddling bits can an adversary send a 32-bit value that is not interpretable as a uint32_t
between 0 and UINT32_MAX
, inclusive. Nor will the uint32_t
received induce ntohl()
to try to return an out-of-range value, because, again, no out-of-range or invalid values are expressible for type uint32_t
.
How could I prevent an integer overflow/underflow from occurring?
You don't need to do anything to avoid that. You should instead focus on how to detect or deal with the possibility that the value received is simply wrong or inconsistent.