LightWeight IP: Buffer not freeing - c

I'm using an TCP/IP stack called lwip. I have implemented a function below to send data packets, inspired from a similar callback function that receives data packets.
Each time a packet is received, I create a buffer using the pbuf_alloc function. Then, I send the packet using udp_sendto. Finally, I free the buffer using pbuf_free. (See the code below.)
For some reason, pbuf_free is not freeing the buffer. (I get a buffer overflow after n packets, where n is the pool size.) The lwip wiki warns that:
The network driver may also not assume that the pbuf memory is
actually freed when it calls pbuf_free.
How can I force pbuf_free to free my buffer? How is the buffer overflow avoided?
(My implementation below.)
static err_t IAP_tftp_send_data_packet(struct udp_pcb *upcb, struct ip_addr *to, int to_port, int block)
{
err_t err;
struct pbuf *pkt_buf;
char packet[TFTP_DATA_PKT_LEN_MAX];
int bytesRead;
int bytesToSend;
/* Specify that we are sending data. */
IAP_tftp_set_opcode(packet, TFTP_DATA);
/* Specify the block number that we are sending. */
IAP_tftp_set_block(packet, block);
bytesRead = IAP_tftp_set_data(packet, block);
if(bytesRead != 0) {
bytesToSend = TFTP_DATA_PKT_LEN_MAX - (512 - bytesRead + 1);
} else {
bytesToSend = TFTP_DATA_PKT_LEN_MAX - 512;
}
pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_POOL);
if (!pkt_buf)
{
print("(TFTP) Buffer overflow!\r\n");
}
/* Copy the file data onto pkt_buf. */
memcpy(pkt_buf->payload, packet, bytesToSend);
err = udp_sendto(upcb, pkt_buf, to, to_port);
/* free the buffer pbuf */
printf("%d\n\r", pbuf_free(pkt_buf));
return err;
}

What version of lwIP are you using?
Depending on different versions the answers vary a lot.
The memp_malloc() allocation function called inside the pbuf_alloc() has failed or the pbufs chaining has failed.So, it returns NULL.
pbuf_alloc() will also return NULL, if the passed arguments also contains NULL.(due to NULL arguments check).
In newer versions, could you show what value the MEMP_OVERFLOW_CHECK macro contains? The lwIP shows a diferent behavior when the macro value >= 2.
And another cause might be if you are using multi-threading, the locking mechanisms inside the pbuf_alloc() fail, might cause it to return NULL.
Some versions require that you call pbuf_init(), before calling pbuf_alloc().
You can try this:
pkt_buf = NULL;//Use NULL, just incase the NULL is not 0 as per your compiler.
pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_REF);
if(pkt_buf == NULL)
{
printf("pbuf_alloc failed.\n");
}
else
{
/* Do something with the allocated pbufs and free it. */
}
PBUF_REF will allocate no buffer memory for pbuf. The pbuf should be used in a single thread only and if the pbuf gets queued, then pbuf_take should be called to copy the buffer.
You can also try PBUF_RAM which will allocate buffer in RAM.
For more informtaion, you can also browse the source files of the version of lwIP, that you are using.

The easiest solution seems to be to make the buffer static, i.e. re-use the same buffer for each call:
static struct pbuf *pkt_buf = NULL;
if( pkt_buf == NULL )
pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_POOL);
if( pkt_buf == NULL )
{
print("(TFTP) Buffer overflow!\r\n");
}
If your scenario involves unloading/reloading the driver, it will leak memory. To fix that, make the buffer static outside the IAP_tftp_send_data_packet() function, and call pbuf_free() when the driver unloads (assuming lwip tells you).

Just a passing thought, possibly completely nonsensical. In this code:
if(bytesRead != 0) {
bytesToSend = TFTP_DATA_PKT_LEN_MAX - (512 - bytesRead + 1);
} else {
bytesToSend = TFTP_DATA_PKT_LEN_MAX - 512;
}
pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_POOL);
...is it possible for bytesRead to assume the value 513 - TFTP_DATA_PKT_LEN_MAX ?
If it happened, wouldn't the request to allocate zero bytes fail? (this could be tested by printing the value of bytesToSend upon buffer overflow, and checking if it is nonzero).

struct pbuf does not represent a continuous region of memory. It is rather a chain of memory locations. Thus this will not work in general case:
memcpy(pkt_buf->payload, packet, bytesToSend);
You need to scatter-copy your data. The memcpy() from the code snippet may overflow the payload buffer and cause all kinds of side effects including inability to free the pbuf chain cleanly.

Related

Read/write exactly N bytes from/to file descriptor with C on Unix

I know that read/write C functions from <unistd.h> are not guaranteed to read/write exactly N bytes as requested by size_t nbyte argument (especially for sockets).
How to read/write full buffer from/to a file(or socket) descriptor?
That read() and write() do not guarantee to transfer the full number of bytes requested is a feature, not a shortcoming. If that feature gets in your way in a particular application then it is probably better to use the the existing facilities of the standard library to deal with it than to roll your own (though I certainly have rolled my own from time to time).
Specifically, if you have a file descriptor on which you want to always transfer exact numbers of bytes then you should consider using fdopen() to wrap it in a stream and then performing I/O with fread() and fwrite(). You might also use setvbuf() to avoid having an intermediary buffer. As a possible bonus, you can then also use other stream functions with that, such as fgets() and fprintf().
Example:
int my_fd = open_some_resource();
// if (my_fd < 0) ...
FILE *my_file = fdopen(my_fd, "r+b");
// if (my_file == NULL) ...
int rval = setvbuf(my_file, NULL, _IONBF, 0);
// if (rval != 0) ...
Note that it is probably best to thereafter use only the stream, not the underlying file descriptor, and that is the main drawback of this approach. On the other hand, you can probably allow the FD to be lost, because closing the stream will also close the underlying FD.
Nothing particularly special is required to make fread() and fwrite() to transfer full-buffer units (or fail):
char buffer[BUF_SIZE];
size_t blocks = fread(buffer, BUF_SIZE, 1, my_file);
// if (blocks != 1) ...
// ...
blocks = fwrite(buffer, BUF_SIZE, 1, my_file);
// if (blocks != 1) ...
Do note that you must get the order of the second and third arguments right, however. The second is the transfer unit size, and the third is the number of units to transfer. Partial units will not be transferred unless an error or end-of-file occurs. Specifying the transfer unit as the full number of bytes you want to transfer and asking (therefore) for exactly one unit is what achieves the semantics you ask about.
You use a loop.
For example, with proper error checking:
/** Read a specific number of bytes from a file or socket descriptor
* #param fd Descriptor
* #param dst Buffer to read data into
* #param minbytes Minimum number of bytes to read
* #param maxbytes Maximum number of bytes to read
* #return Exact number of bytes read.
* errno is always set by this call.
* It will be set to zero if an acceptable number of bytes was read.
* If there was
and to nonzero otherwise.
* If there was not enough data to read, errno == ENODATA.
*/
size_t read_range(const int fd, void *const dst, const size_t minbytes, const size_t maxbytes)
{
if (fd == -1) {
errno = EBADF;
return 0;
} else
if (!dst || minbytes > maxbytes) {
errno = EINVAL;
return 0;
}
char *buf = (char *)dst;
char *const end = (char *)dst + minbytes;
char *const lim = (char *)dst + maxbytes;
while (buf < end) {
ssize_t n = read(fd, buf, (size_t)(lim - buf));
if (n > 0) {
buf += n;
} else
if (n == 0) {
/* Premature end of input */
errno = ENODATA; /* Example only; use what you deem best */
return (size_t)(buf - (char *)dst);
} else
if (n != -1) {
/* C library or kernel bug */
errno = EIO;
return (size_t)(buf - (char *)dst);
} else {
/* Error, interrupted by signal delivery, or nonblocking I/O would block. */
return (size_t)(buf - (char *)dst);
}
}
/* At least minbytes, up to maxbytes received. */
errno = 0;
return (size_t)(buf - (char *)dst);
}
Some do find it odd that it clears errno to zero on successful calls, but it is perfectly acceptable in both standard and POSIX C.
Here, it means that typical use cases are simple and robust. For example,
struct message msgs[MAX_MSGS];
size_t bytes = read_range(fd, msgs, sizeof msgs[0], sizeof msgs);
if (errno) {
/* Oops, things did not go as we expected. Deal with it.
If bytes > 0, we do have that many bytes in msgs[].
*/
} else {
/* We have bytes bytes in msgs.
bytes >= sizeof msgs[0] and bytes <= sizeof msgs.
*/
}
If you have a pattern where you have fixed or variable sized messages, and a function that consumes them one by one, do not assume that the best option is to try and read exactly one message at a time, because it is not.
This is also why the above example has minbytes and maxbytes instead of a single exactly_this_many_bytes parameter.
A much better pattern is to have a larger buffer, where you memmove() the data only when you have to (because you're running out of room, or because the next message is not sufficiently aligned).
For example, let's say you have a stream socket or file descriptor, where each incoming message consists of a three byte header: the first byte identifies the message type, and the next two bytes (say, less significant byte first) identify the number of data payload bytes associated with the message. This means that the maximum total length of a message is 1+2+65535 = 65538 bytes.
For efficiently receiving the messages, you'll use a dynamically allocated buffer. The buffer size is a software engineering question, and other than that it has to be at least 65538 bytes, its size – and even whether it should grow and shrink dynamically – depends on the situation. So, we'll just assume that we have unsigned char *data; pointing to a buffer of size size_t size; already allocated.
The loop itself could look something like the following:
size_t head = 0; /* Offset to current message */
size_t tail = 0; /* Offset to first unused byte in buffer */
size_t mlen = 0; /* Total length of the current message; 0 is "unknown"*/
while (1) {
/* Message processing loop. */
while (head + 3 <= tail) {
/* Verify we know the total length of the message
that starts at offset head. */
if (!mlen)
mlen = 3 + (size_t)(data[head + 1])
+ (size_t)(data[head + 2]) << 8;
/* If that message is not yet complete, we cannot process it. */
if (head + mlen > tail)
break;
/* type datalen, pointer to data */
handle_message(data[head], mlen - 3, data + head + 3);
/* Skip message in buffer. */
head += mlen;
/* Since we do not know the length of the next message,
or rather, the current message starting at head,
we do need to reset mlen to "unknown", 0. */
mlen = 0;
}
/* At this point, the buffer contains less than one full message.
Whether it is better to always move a partial leftover message
to the beginning of the buffer, or only do so if the buffer
is full, depends on the workload and buffer size.
The following one may look complex, but it is actually simple.
If the current start of the buffer is past the halfway mark,
or there is no more room at the end of the buffer, we do the move.
Only if the current message starts in the initial half, and
when there is room at the end of the buffer, we leave it be.
But first: If we have no data in the buffer, it is always best
to start filling it from the beginning.
*/
if (head >= tail) {
head = 0;
tail = 0;
} else
if (head >= size/2 || tail >= size) {
memmove(data, data + head, tail - head);
tail -= head;
head = 0;
}
/* We do not have a complete message, but there
is room in the buffer (assuming size >= 65538),
we need to now read more data into the buffer. */
ssize_t n = read(sourcefd, data + tail, size - tail);
if (n > 0) {
tail += n;
/* Check if it completed one or more messages. */
continue;
} else
if (n == 0) {
/* End of input. If buffer is empty, that's okay. */
if (head >= tail)
break;
/* Ouch: We have partial message in the buffer,
but there will be no more incoming data! */
ISSUE_WARNING("Discarding %zu byte partial message due to end of input.\n", tail - head);
break;
} else
if (n != -1) {
/* This should not happen. If it does, it is a C library
or kernel bug. We treat it as fatal. */
ISSUE_ERROR("read() returned %zd; dropping connection.\n", n);
break;
} else
if (errno != EINTR) {
/* Everything except EINTR indicates an error to us; we do
assume that sourcefd is blocking (not nonblocking). */
ISSUE_ERROR("read() failed with errno %d (%s); dropping connection.\n", errno, strerror(errno));
break;
}
/* The case n == -1, errno == EINTR usually occurs when a signal
was delivered to a handler using this thread, and that handler
was installed without SA_RESTART. Depending on what kind of
a device or socket sourcefd is, there could be additional cases;
but in general, it just means "something unrelated happened,
but you were to be notified about it, so EINTR you get".
Simply put, EINTR is not really an error, just like
EWOULDBLOCK/EAGAIN is not an error for nonblocking descriptors,
they're just easiest to treat as an "error-like situation" in C.
*/
}
/* close(sourcefd); */
Note how the loop does not actually try to read any specific amount of data? It just reads as much as it can, and processes it as it goes.
Could one read such messages precisely, by first reading exactly the three-byte header, then exactly the data payload? Sure, but that means you make an awful amount of syscalls; at minimum two per message. If the messages are common, you probably do not want to do that because of the syscall overhead.
Could one use the available buffer more carefully, and remove the type and data payload length from the next message in the buffer as soon as possible? Well, that is the sort of question one should discuss with colleagues or developers having written such code before. There are positives (mainly, you save three bytes), and negatives (added code complexity, which always makes code harder to maintain long term, and risks introducing bugs). On a microcontroller with just 128 bytes of buffer for incoming command messages, I probably would do that; but not on a desktop or server that prefers a few hundred kilobytes to a couple of megabytes of buffer for such code (since the memory "waste" is often covered by the smaller number of syscalls especially when processing lots of messages). No quick answers! :)-
Both read and write on success return ssize_t containing amount of bytes read/written. You can use it to construct a loop:
A reliable read():
ssize_t readall(int fd, void *buff, size_t nbyte) {
size_t nread = 0; size_t res = 0;
while (nread < nbyte) {
res = read(fd, buff+nread, nbyte-nread);
if (res == 0) break;
if (res == -1) return -1;
nread += res;
}
return nread;
}
A reliable write() (almost same):
ssize_t writeall(int fd, void *buff, size_t nbyte) {
size_t nwrote = 0; size_t res = 0;
while (nwrote < nbyte) {
res = write(fd, buff+nwrote, nbyte-nwrote);
if (res == 0) break;
if (res == -1) return -1;
nwrote += res;
}
return nwrote;
}
Basically it reads/writes until total amount of bytes != nbyte.
Please note, this answer uses only <unistd.h> functions, assuming there is a reason to use it. If you can use <stdio.h> too, see answer by John Bollinger, which uses fdopen;setvbuf and then fread/fwrite. Also, take a look at answer by Blabbo is Verbose for read_range function with a lot of features.

Questions on scull_follow function in linux device drivers 3rd edition

I never found the definition for scull_follow in the book, so I'm trying to understand it based off a github repo(https://github.com/martinezjavier/ldd3).
Here is the code I am trying to understand:
struct scull_qset *scull_follow(struct scull_dev *dev, int n) {
struct scull_qset *qs = dev->data;
/* Allocate first qset explicitly if need be */
if (!qs) { // if NULL
qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
if (qs == NULL)
return NULL; /* Never mind */
memset(qs, 0, sizeof(struct scull_qset));
}
/* Then follow the list */
while (n--) {
if (!qs->next) {
qs->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
if (qs->next == NULL)
return NULL; /* Never mind */
memset(qs->next, 0, sizeof(struct scull_qset));
}
qs = qs->next;
continue;
}
return qs;
}
Here is struct scull_qset:
struct scull_qset {
void **data;
struct scull_qset *next;
};
Conceptually, I understand that all scull_follow does is that it follows the list up to the right position so that you know where to start reading/writing.
I'm mainly confused on this part of the code.
/* Allocate first qset explicitly if need be */
if (!qs) { // if NULL
qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
if (qs == NULL)
return NULL; /* Never mind */
memset(qs, 0, sizeof(struct scull_qset));
}
Let's say the user opens this driver and attempts to read from it first without writing. that should mean that it should go into the if statement and allocate some memory. Then, why is there a second check for if qs is NULL or not? Won't it always be not NULL because it was allocated some memory?
After that what is the memset function for? I understand that it copies 0 into qs, but what is the point of that other than initializing this memory region? Is it so that when you call the copy_to_user function in your read function it'll know that because it is filled with 0s, nothing of 'value' has been written to it so you will just get a blank output when reading, assuming the first operation you do is reading?
Thanks for answering my questions.
This:
qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
if (qs == NULL)
return NULL;
Is standard C programming good practice: whenever a function can fail, you always need to check the return value. This is true for any kind of function that can fail, not only malloc() and friends. In this case, kmalloc() can fail to allocate memory, returning NULL, so the code is checking for that error. If that happens, the function safely aborts execution by doing a return NULL;, and the caller will then handle that as needed.
This:
memset(qs, 0, sizeof(struct scull_qset));
Is standard kernel programming good practice: whenever you allocate uninitialized memory (like kmalloc() does), it could contain sensitive kernel data. You never want uninitialized data to reach userspace through a copy_to_user() or similar calls. In order to avoid this, you need to make sure to initialize it before making it available to userspace. Filling it with zeroes using memset() is one of the simplest way to do this.
In the case an user program does a read as the first syscall on the scull driver, it would just read a bunch of 0 bytes.

Using ioctl(), read() and malloc() to receive a message from server not working properly

I am trying to make a simple server client program in C. On the client I try to receive the message from the server, but the size of the message is not predetermined. Therefore, I want to check how many bytes are coming in, and malloc the appropriate size.
I tried to use ioctl but it seems like it gets the info I want too late.
This is what I have.
char *message_from_server;
int length;
while(1){
ioctl(socket, FIONREAD, &length);
message_from_server = malloc(length);
read(socket, message_from_server, length);
}
The first time I use it, length is 0. The second time, length is equal to that of the first message. If I put the line ioctl(socket, FIONREAD, &length); after i read, that might give me trouble with mallocing the correct amount of space. Is this even a valid way to solve my problem?
I have heard that one can use realloc to solve my problem, but I am struggling to see how to it so solve my problem. If that is a better way to do it, I would be happy for any tips.
Thanks!
realloc allows you to increase the size of a memory block, preserving its content.
So, in your case:
read size of incoming packet
update memory block to store packet, preserving what have been read previously
read the packet
goto 1. or exit
Your code should look like:
/* memory to store message, initially, no memory */
char *message_from_server = NULL;
/* size of memory */
int total_length = 0;
/* sizeof incoming packet*/
int packet_lentgh;
/* position to write in memory */
int offset;
while(1){
/* read size of incoming packet*/
ioctl(socket, FIONREAD, &packet_lentgh);
if (0 != packet_lentgh)
{
/* something is ready to be read on socket */
/* update memory size */
total_length += packet_lentgh;
/* allocate much memory*/
message_from_server = realloc(message_from_server, total_length);
if (NULL == message_from_server)
{
perror("realloc");
abort();
}
/* compute the position to write in memory */
offset = total_length - packet_lentgh;
/* read the packet */
read(socket, message_from_server + offset, packet_lentgh);
}
else
{
/* nothing to read
wait for packet or stop loop... */
}
}

C: memcpy segfault with void* pointers

Code -- Main loop:
int handleClient (struct clientData* clientData)
{
void* Buffer = malloc (INET_BUFFER_SIZE); <-- VOID* BUFFER FOR RECV()
int listenSocket = clientData->listenSocket;
struct sockaddr_in clientAddress = clientData->clientAddress;
printf("Received connection from client %s:%d.\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port));
while (1)
{
int packetSize;
if ((packetSize = recv(listenSocket, &Buffer, INET_BUFFER_SIZE, 0)) > 0)
{
if (packetSize == ECHO_SIZE)
{
handleEchoPacket(Buffer);
continue;
}
if (packetSize == MESSAGE_SIZE) <---THIS IS TRIGGERED BECAUSE OF PACKET SIZE
{
handleMessagePacket(Buffer);
continue;
}
}
}
Code -- handleMessagePacket(void* Buffer):
void handleMessagePacket (void* Buffer)
{
void* localBuffer = (void*) malloc(INET_BUFFER_SIZE);
memcpy(localBuffer, Buffer, INET_BUFFER_SIZE); <--SEGFAULT
(...)
}
GDB -- Partial output:
Program received signal SIGSEGV, Segmentation fault.
__memcpy_sse2_unaligned () (.....) <--Tells me it doesn't have source files, not relevant to the problem.
Basically, the problem happens when I copy one memory block from a void pointer to a local buffer. Both were malloc() heap memory of same type: void.
Any suggestions or comments are welcome!
Here is what is happening: when you pass the address of Buffer to recv, received data is placed in the space allocated to the address of your buffer, which is on the stack. When you subsequently call handleMessagePacket, the address that you pass is no longer valid: it has been written over by recv!
Removing the ampersand from the call of recv should fix this problem:
if ((packetSize = recv(listenSocket, Buffer, INET_BUFFER_SIZE, 0)) > 0)
// ^^ No ampersand
In general, situations like this are best diagnosed with a memory profiler, such as valgrind. The tool would promptly tell you that there is an invalid write into stack area for the Buffer write, and that the subsequent dereference of received data as a pointer (the issue that causes SIGSEGV now) is an invalid read.

C Socket Append Data To Buffer Gets Corrupted

I'm still refining my C coding skills and keep running into issues with properly managing memory--go figure. Anyhow, I'm reading from a socket and I'm fine as long as my total response length from the socket it no bigger than my buffer size. I know this because when I increase the buffer size large enough for the incoming data, it works just fine for the larger payloads. Creating a really large "just-in-case" buffer on the stack isn't feasible, obviously, so I want to grow the buffer dynamically on the heap. Here's what I'm doing currently:
raw_response = NULL;
// Receive from the Web server
retcode = recv(server_s, in_buf, BUF_SIZE, 0);
while ((retcode > 0) || (retcode == -1))
{
totalLength += retcode;
if (raw_response == NULL) {
raw_response = (char*)malloc(sizeof(char)*totalLength);
memcpy(raw_response, in_buf, totalLength);
} else {
raw_response = (char*)realloc(raw_response, sizeof(char)*totalLength);
memcpy(raw_response+previousLength, in_buf, retcode);
}
previousLength = retcode;
retcode = recv(server_s, in_buf, BUF_SIZE, 0);
if (retcode == 0 || retcode == -1) {
printf("\n\nNo more data, bailing. Data length was: %lu\n\n", totalLength);
}
}
If the raw_response is NULL, I know I have not received any data yet, so I use malloc. Otherwise, I use realloc so that I don't have to build up a new buffer. Instead I can just append the incoming data. So to get the end of the existing data after the first iteration, I take the address of raw_response and add the previous length to that and append the new data there assuming it's correctly appending on each subsequent call to recv().
The problem is that my final buffer is always corrupted unless I change BUF_SIZE to something larger than my total incoming data size.
Seem like it's probably just something simple I'm overlooking. Any thoughts?
The problem is these lines:
memcpy(raw_response+previousLength, in_buf, retcode);
previousLength = retcode;
Your function will work for the first and second iterations but after that will start corrupting data. I assume you meant to write previousLength += retcode;
There are some other problems with the code which aren't the answer to your question. Firstly, what happens if realloc or malloc fails? You don't check for this in your little sample. Also, you can always just use realloc (which will act like malloc if the pointer is NULL see this SO question). i.e.
char *tmp = realloc(raw_response, sizeof(*tmp) * totalLength);
if (tmp == NULL)
return -ENOMEM;
raw_response = tmp;
memcpy(raw_response + previousLength, in_buf, ret_code)
Secondly, you might call memcpy when ret_code is -1 (also changing totalLength by -1 which will again cause problems).

Resources