C: memcpy segfault with void* pointers - c

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.

Related

Implementing Paranoid Array in C

I have the following assignment for an online class and was wondering if anyone was familiar with paranoid arrays, as it's very difficult to get help for this specific class.
Your paranoid array will expose a very simple interface provided in parray.h. You can
assume the parray will not be free’d. The parray new call creates an array of a set-number
of entries (count argument) of a fixed size (size argument). Internally, the parray will
not arrange the elements consecutively in memory, so the parray entry function returns a
pointer to a given entry (specified by argument index).
In order to trigger a segfault upon overflow within an element, you should use guard
pages. A guard page’s main purpose is to trigger segfaults when it is accessed. Thus, pagetable read, write, and execute permissions on a guard table are disabled, so any access to
the page will trigger the fault. When a guard page is placed immediately after a buffer or
data structure, any buffer overflow bugs affecting that piece of memory will hit the guard
page, triggering an instant segfault
Every entry in your array should be bounded by guard pages on each side. For example,
an array with 10 entries should use 11 guard pages: one before the first entry, one after the
last entry, and nine in between consecutive entries.
My parray_new and parray_entry call is as follows:
typedef char byte;
parray_t* parray_new(int size, int count)
{
struct parray* p = NULL;
// TODO: Allocate and return parray
// Add guard pages first at this time
int pagesize = getpagesize();
p->size = (size * count) + (pagesize * count) + pagesize;
p->array = malloc(p->size + pagesize - 1);
if(posix_memalign(&p->array, p->size, count))
{
exit(0);
}
return p;
}
void* parray_entry(struct parray* p, int index)
{
//int pagesize = getpagesize();
byte* entry = NULL;
// TODO: compute correct entry
if (mprotect(&p->array, p->size-1, PROT_READ))
{
exit(0);
}
if (mprotect(&p->array, p->size, PROT_WRITE))
{
exit(0);
}
entry = (void*)(p->array + index);
return entry;
}
I also have the following handler:
static void handler(int sig, siginfo_t *si, void* unused)
{
// TODO: Use fprintf or perror to print
// a message indicating a segmentation fault
// happened and provide the memory address
// where the fault happened
fprintf(stderr, "Segmentation Fault\n k = %d, %p\n", sig, si >si_addr);
}
Finally, the main method:
int main(void)
{
struct sigaction sa;
/*
* TODO: Overwrite the signal handler for
* SIGSEGV
*/
memset(&sa, '\0', sizeof(sa));
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
if (sigaction(SIGSEGV, &sa, NULL) == -1)
{
perror("sigaction");
exit(EXIT_FAILURE);
}
}
There's also several tests to run in the main method, but I've left those out because I encounter an error before I even reach them. What happens is, the handler prints forever (Segmentation fault, k = 11, 0x8). I do not know the significance of 11 or 0x8, but it does not stop printing that sequence until I force it.
Any help would be greatly appreciated, and I apologize for the length of this post. Thanks
Edit: from what I can see, the handler continues to print. It's not so much that I'm getting a seg fault (I might be), but whatever I put in the handler it continues to print. Also if I change it to perror it does the same. What can I do to allow the program to continue after the handler?

Why a child process fails to write to a shared memory?

I have a simple program that writes to a shared memory and reads from a shared memory, but while reading I am getting segmentation fault.
When I am debugging, the child process is not writing information to the shared memory, and after that, the parent process is trying to read from the shared memory which has no data and is throwing segmentation fault at 1st printf, in parent printf("%d\n",ptr->nread);
Why the child process is not able to write data to the shared memory? (it is failing at ptr->nread=20; line)
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#define SIZE 5*1024
struct databuf{
int nread;
char *buf;
int xyz;
};
struct databuf* ptr;
main()
{
int shmid,pid;
shmid = shmget((key_t)1,SIZE,IPC_CREAT|0777);
pid = fork();
if(pid==0)
{
ptr = (struct databuf *)shmat(shmid,(char*)0,0);
ptr->nread=20;
ptr->buf=ptr+sizeof(ptr->nread);
strcpy(ptr->buf, "abc");
ptr->xyz=20;
}
else
{
wait(0);
ptr = (struct databuf *)shmat(shmid,(char*)0,0);
printf("%d\n",ptr->nread);
printf("%s\n",ptr->buf);
printf("%d\n",ptr->xyz);
}
return 0;
}
If ptr->nread is failing then you should put a error checking code something like this, before acessing the ptr.
ptr = (struct databuf *)shmat(shmid,(char*)0,0);
if (data == (struct databuf *)(-1)) {
perror("shmat failed");
exit(1);
}
ptr->nread=20;
Ref: http://linux.die.net/man/2/shmat
ptr->buf=ptr+sizeof(ptr->nread);
could be written as:
ptr->buf=(char*)ptr+sizeof(struct databuf)+ptr->nread;
or
ptr->buf=(char*)ptr+ptr->nread;
The string can now be accessed in the parent process.
Brief Explanation:
If you're using shared memory, you have to make sure all the data you want to access in other processes is in the shared memory segment. Leave the data at a specified offset(in your case ptr+ptr->nread) in the memory segment. And be careful not to overwrite the existing data in the shared memory. sizeof(ptr->nread) will yield the sizeof(int).
Leaving to one side all the other issues with the code, I think:
shmid = shmget((key_t)1, SIZE, IPC_CREAT|0777) ;
is probably a mistake, unless you can (somehow) guarantee that (key_t)1 is not in use elsewhere. For parent-child communication, as in this case, the simpler approach is:
shmid = shmget((IPC_PRIVATE, SIZE, IPC_CREAT|0777) ;
In general, when something apparently inexplicable happens, I find it helps to make sure I have checked for error returns. In this case: shmget() returning -1 or shmat() returning -1... and I suspect that both have happened.
Worked solution added by #WhozCraig:
The following example works, and likely does what you're trying to accomplish. Pay note to how we calculate the address we store in ptr->buf after we home ptr to our shared memory base address. We have to leave room for the structure, so we calculate the address to start the first byte past the structure back-side.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
struct databuf
{
int nread;
char *buf;
int xyz;
};
#define SIZE (5*1024)
int main()
{
// acquire shared memory first (read/write access)
int shmid = shmget(IPC_PRIVATE, SIZE, IPC_CREAT|0666);
if (shmid == -1)
{
perror("Failed to acquire shared emory.");
exit(EXIT_FAILURE);
}
// fork child process
pid_t pid = fork();
// both parent and child need this. may as well do both before
// special casing child vs. parent logic.
struct databuf *ptr = shmat(shmid,(char*)0,0);
if (ptr == (void*)(-1))
{
perror("Failed to map shared memory to our process");
exit(EXIT_FAILURE);
}
// child process
if (pid==0)
{
ptr->nread = 20;
ptr->buf = ((char*)ptr) + sizeof(*ptr);
strcpy(ptr->buf, "abc");
ptr->xyz = 30;
}
// parent process
else
{
wait(NULL);
printf("ptr = %p, ptr->buf = %p\n", ptr, ptr->buf);
printf("%d\n",ptr->nread);
printf("%s\n",ptr->buf);
printf("%d\n",ptr->xyz);
}
return 0;
}
Sample Output (varies by system obviously)
ptr = 0x80000, ptr->buf = 0x8000c
20
abc
30
it is worth noting that this:
ptr->buf = ((char*)ptr) + sizeof(*ptr);
could be written as the following, using typed-pointer math:
ptr->buf = (char*)(ptr + 1);
The location where the cast is applied is important. The first applies it before we do any math, so we need to account for octet count. The second applies it after the pointer math, so simply adding one to to the typed pointer ptr will move us to the memory immediately past our ptr structure base.
Best of luck.
If you have a pointer from type T, an addition by one to the pointer will increment it by sizeof(T).
So you have to replace:
ptr->buf=ptr+sizeof(ptr->nread);
to
ptr->buf= ((char*)ptr )+sizeof(ptr->nread);
If you don't do that, your pointer will be incremented by sizeof(T)^2.

copy_from_user gives null pointer

I'm attempting to write an Open RG kernel module that, at given intervals, sends a message up to the user space. To this end, I need the kernel to hold a pointer to a static buffer in the user space where this message will be stored. I'm having trouble sending the pointer to the kernel.
The user space function call is something like this (simplified, obviously):
typedef struct {
char msg[MAX_BOOT_MSG];
} msg_t;
static msg_t common_mem;
void user_space_func() {
openrg_module_ctrl(KOS_CDT_TEST, TEST_IOCTL_SET_COMMON_MEM, &common_mem.msg);
}
The kernel space usage is like this:
static void* msg_write;
static int do_ioctl(kos_chardev_t *context, unsigned int cmd,
unsigned long data) {
switch (cmd)
{
case TEST_IOCTL_SET_COMMON_MEM:
received_ioctl = 1;
int ret = copy_from_user(&msg_write, (void *)data, sizeof(char*));
printk("setting common mem to %p, received %d\n", msg_write, ret);
return 0;
}
default:
return -1;
}
The output is setting common mem to 0000000000000000, received 0. I see that common_mem.msg isn't NULL. Any idea what I'm doing wrong?
data is the address of the buffer, so by reading from that address, you are copying the contents of the buffer.
Please note that memory in user space can be moved or swapped out, so this address is valid only for the duration of the system call; you must not store the address for later usage.
Better allocate some memory in your driver, and allow the application to access it with mmap.

Error with pointers in recv() function

I am doing socket programming for achieve communication between different entities in my application. When sending a message, I prefix the message with the length of the message and I terminate it with \0. I have recv() in a loop as follows:
void receive(int socket)
{
int num_of_bytes_read = 0, msg_len;
char *msg = NULL, *msg_p = NULL;
char recv_buf[MAX_LEN];
while(num_of_bytes_read = recv(socket, recv_buf, MAX_LEN, 0))
{
if(msg == NULL)
{
memcpy(&msg_len, message, 4);
msg_len = ntohl(msg_len);
if((msg = (char *)(sizeof(char) * msg_len)) == NULL)
systemError("Could not receive new message\n");
printf("%p\n", msg); /* prints 0xe!! Why is the address not 4B long??*/
msg_p = msg;
}
if(memcpy(&msg_p, recv_buf, num_of_bytes_read) == NULL)
systemError("memcpy failed in receive()\n");
msg_p += num_of_bytes_read;
}
printf("%p\n", msg); /* prints (nil) !!!!!*/
printf("%p\n", msg + sizeof(uint32_t)); /* prints 0x4 */
/* pass the a pointer to the beginning of the message skipping msg_len*/
int res = processMessage(msg + sizeof(uint32_t));
}
When I run the program I obviously get segmentation fault with the following error:
message=0x4
What is wrong with msg?? Can someone please help.
while(num_of_bytes_read = recv(socket, recv_buf, MAX_LEN, 0))
This is already wrong. You should test for > 0. If num_of_bytes is zero you should close the socket, and if it is -1 you should log the associated errno, e.g. with perror(), and close the socket, and in both cases stop reading.
if(msg == NULL)
{
memcpy(&msg_len, message, 4);
As long as message points to four bytes of addressable memory this will succeed. You have provided no information on the point. The purpose remains obscure.
msg_len = ntohl(msg_len);
Here you are assuming that message pointed to four bytes that magically contain an int that has magically been set to a value you are prepared to regard as a message length. Why, I don't know. Again you have provided no information on the point.
if((msg = (char *)(sizeof(char) * msg_len)) == NULL)
This is complete nonsense. Is there a malloc() missing in there somewhere?
systemError("Could not receive new message\n");
A meaningless error message. The problem appears to be about allocating memory, but it's anybody's guess. It certainly has nothing to do with receiving messages.
printf("%p\n", msg); /* prints 0xe!! Why is the address not 4B long??*/
Here you appear to think the address should be 4B long. I don't know why.
if(memcpy(&msg_p, recv_buf, num_of_bytes_read) == NULL)
You are copying data to the address of msg_p. This doesn't make sense. Also, at this point num_of_bytes_read could be -1 due to your incorrect loop condition above, so anything could happen, including trying to copy 0xffffffff bytes.
systemError("memcpy failed in receive()\n");
The only way you can get to this line is if msg_p's address was null, which is impossible. Remove the & from &msg_p in the memcpy() call. Now you can only get to this systemError() call if msg_p was zero, which would already have caused a SEGV, so you still can't get to this line. A bit of preventative coding is indicated here.
msg_p += num_of_bytes_read;
Again num_of_bytes_read could be -1 at this point, sending your pointer backwards instead of forwards.
printf("%p\n", msg); /* prints (nil) !!!!!*/
Nil indicates that msg was zero.
printf("%p\n", msg + sizeof(uint32_t)); /* prints 0x4 */
0x4 again indicates that msg was zero.
You need to improve your code in the areas indicated.
msg = (char *)(sizeof(char) * msg_len)
You are setting msg to some address based on the msg_len. Not actually anything to do with where the msg resides in memory...

LightWeight IP: Buffer not freeing

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.

Resources