GCC 4.7.0 run time issue - receiving signal 11 (SigSegv) - c

The following is a code snippet from my read from pipe function. This executes properly and verified that the data is got into buffer .
int readFrom(char *buffer)
{
int nread;
if((nread = read(readfd,buffer,100)) < 0)
{
printf("\nerror in reading data from FIFO\n");
return(-1);
}
buffer[nread]='\0';
return(0);
}
In the above example nread is less than 100 . I am using GCC-4.7.0.
We had an abstraction layer for the above function like below :
int pipe_input(char *parmPtr, int size)
{
char readMsg[100];
if( readFrom((char *)&readMsg) == -1)
return ERROR;
if (strlen(readMsg) < 1)
{
printf("Incorrect Input\n");
return ERROR;
}
strncpy(parmPtr, readMsg, ((size < 100)?size:100));
return 0;
}
In the above function as well it was verified that read message is proper and parmptr is properly loaded with the value. But in the function Where i am trying to call pipe_input I am getting a sigsegv. This happens with GCC-4.7.0 but the same code compiled with GCC-4.2.4 executes fine. I verified the warnings, but there are no warning for the above. Any pointers would be highly helpful.
Below code snippet for calling pipe_input :
int Calling_func(void)
{
char alpha[100] ;
pipe_input(alpha,100);
printf("alpha value is %s \r\n",alpha);
}
getting sigsegv at the print statement.

You have off-by-one errors in your code. Your array has 100 elements, but you're not taking NULL-termination into account:
strncpy(parmPtr, readMsg, ((size < 100)?size:100));
and:
buffer[nread]='\0';
The last element is buffer[99] (since array indices start from 0, not 1,) but you can write to buffer[100]. This can result in a segfault.
You should probably declare all arrays with a size of 101 instead and see if it helps. If you're on Linux, you should also run your program in Valgrind; it can tell you exactly how the segfault occurred.

Related

C Server and Client - Segmentaion fault and showing garbage

I am programming a game of connect four server and client, and I need to transmit the game array to the client via a string.
I am trying to collect the array in a string variable, playerBoard, using strcat, but it seems that when it gets to the client, it displays garbage, and also, the server is showing me Segmentation fault as an error
Server:
else
{
bzero(playersBoard, 100);
int k, j;
for( k = 0; k < HEIGTH; k++ )
{
for( j=0; j < WIDTH; j++ )
{
strcat(playersBoard, (char *)gameArray[k][j]);
strcat(playersBoard, " ");
}
}
strcat(playersBoard, "Now is your turn");
printf("Players board is : \n%s\n", playersBoard);
if(write(tdL.cl, playersBoard, 100) <= 0)
{
printf("[thread %d]\n", tdL.idThread);
perror("[thread] Error at write\n");
}
else
printf("[thread %d] Message was sent with success\n", tdL.idThread);
goto playerOneRetry;
}
Client:
if (write (sd, message, sizeof(message)) <= 0)
{
perror ("[client]Eroare la write() spre server.\n");
return errno;
}
char message2[100];
fflush(stdout);
if (read (sd, message2, 100 ) < 0)
{
perror ("[client]Eroare la read() de la server.\n");
return errno;
}
//writing message
printf ("[client]Message received is : %s\n", message2);
(char *)gameArray[k][j]
1e : (char *)gameArray[k][j] : why the cast ? gameArray[k][j] should be a 2 dim. array of type (char *). If you need to make the cast you probably defined it wrong which would cause the seg. fault.
2e : are you sure you don't overrun playersBoard ? That would cause it.
3e : bzero(playersBoard, 100); : the size of playersBoard is probably known. You should always try to avoid the static 100 and replace it by maybe : sizeof(playerBoard).
4e : You can prevent overrun of playersBoard. Using strncat and don't write more than you can. In the line of defensive programming .. you should.
The expression gameArray[k][j] is a single character, it's not a string. You can not use it as argument in strcat. Trying to cast the character to char * will turn the encoded character into a pointer which is not going to point to a valid string. Using it as such will lead to undefined behavior.
You can append a single character to a string like e.g.
playersBoard[strlen(playersBoard)] = gameArray[k][j];
playersBoard[strlen(playersBoard) + 1] = '\0';
You should really keep an eye on the warnings the compiler will emit, and without the cast it should have said something. Warnings are often a sing of you doing something you should not be doing, and disabling them is usually not a good idea as it only hides the symptom and not the problem.
Also be careful with casting, in most situations it's considered a code smell. If you find you need to cast something then you probably are doing something wrong as well.
The combination of warnings and casting is the worst of all, as like I said above you only hide the problem, but don't solve it.

Using fgets() to read from different pipes, reading same message from both (should be different)

Im using fgets to read from 2 different pipes which have been sent 2 different messages thus should be returning 2 different messages. I have 2 pipes for each and closed the unneeded child end, all my fprintfs are flushed yet theyre both returning the same message then it just hangs. I have no idea why. Debugging didnt help me though i could have missed something.
int reader(FILE *output, int **pipes, char *getMessage) {
if(output == NULL) {
fprintf(stderr, "Player quit\n");
}
fgets(getMessage, sizeof(getMessage), output);
printf("mes %s\n", getMessage);
return 0;
}
Is my reader method (I am using the same buffer for both but i was using memset to try to clear it each time:
printf("test%c\n", roundDeck[deckPos]);
fprintf(input[pickturn], "yourturn %c\n", roundDeck[deckPos]);
fprintf(stdout, "yourturn %c\n", roundDeck[deckPos]);
fflush(input[pickturn]);
allHeldCards[pickturn][1] = roundDeck[deckPos];
roundDeck[deckPos] = '-';
//fclose(inPut);
deckPos++;
if(deckPos == 16) {
deckPos = 0;
}
printf("pt %d\n", pickturn);
reader(output[pickturn], pipes, getMessage);
if(msgProcess(pickturn, allIds, allFlags, allHeldCards,
getMessage, pipes, roundDeck,
deckPos, numPlayers, input) == 1) {
roundDeck[deckPos] = '-';
deckPos++;
if(deckPos == 16) {
deckPos = 0;
}
}
memset(getMessage, 0, 50);
the inputs were changing where they needed to do on the outside so maybe Im using memset incorrectly?
There is a problem here:
fgets(getMessage, sizeof(getMessage), output);
Since getMessage has type char *, then sizeof(getMessage) is sizeof(char *) which is likely to be 4 or 8. You read that many bytes from the "output" into getMessage.
Instead, you need to specify how many bytes to read. Even if you replace sizeof(getMessage) with your buffer size, that means it will block until all that number of bytes have been read, or the input is closed. Either your message protocol has to contain the length it expects to read, or you have to define your function to read until the input is closed or a certain delimiter occurs.
Then you have to make sure that the data you read contains a null-terminated string before you try and print it with %s or any other function that expects a string.
Not clear why your inputs are called output and your outputs are called input either.
It's hard to debug further without seeing more of a complete program than just these snippets

Real time input/output (chat-like)

I'm trying to make a little chat program after reading Beej's guide to programming.
And then I was thinking about the basics of the program itself, and I don't know how to print output of recv() and get input for send() at the same time, because the client can always write something and send, but how is it possible to also print something while he's trying to input ?
I thought about threads, and I learned a little bit about them, and I created 2 simple threads: The first one, prints a sentence every 3 seconds, and the second one get input, this little program of-course had a lot of issues, for ex. if you started typing, and the other thread needs to print something, it will simply take what you wrote, and print it with itself output.
Here is the code, I tried to recreate it, I hope you guys can help me ..
pthread_t tid[2];
void* printse();
void* getinput();
int main(int argc, char *argv[])
{
int error;
error = pthread_create(&(tid[1]), NULL, &getinput, NULL);
if(error != 0)
{
printf("ERROR\n");
} else {
printf("NOERROR\n");
}
error = pthread_create(&(tid[2]), NULL, &printse, NULL);
if(error != 0)
{
printf("ERROR\n");
} else {
printf("NOERROR\n");
}
sleep(5000);
return 0;
}
void* printse()
{
while(1)
{
printf("POTATO\n");
sleep(3);
}
return NULL;
}
void* getinput()
{
char *input;
while(scanf("%s", input) != EOF)
{
printf("-%s\n", input);
}
return NULL;
}
You have undefined behavior in your code: You haven an uninitialized pointer input in getinput.
Uninitialized (non-static) local variables have an indeterminate value, and it will seem to be random. As the value is indeterminate (and seemingly random) the scanf call will write to some unknown place in memory, overwriting whatever was there.
You could easily solve this by making input an array.

Socket Read/Write error

would install valgrind to tell me what the problem is, but unfortunately can't any new programs on this computer... Could anyone tell me if there's an obvious problem with this "echo" program? Doing this for a friend, so not sure what the layout of the client is on the other side, but I know that both reads and writes are valid socket descriptors, and I've tested that n = write(writes,"I got your message \n",20); and n = write(reads,"I got your message \n",20); both work so can confirm that it's not a case of an invalid fd. Thanks!
int
main( int argc, char** argv ) {
int reads = atoi(argv[1]) ;
int writes = atoi(argv[3]) ;
int n ;
char buffer[MAX_LINE];
memset(buffer, 0, sizeof(buffer));
int i = 0 ;
while (1) {
read(reads, buffer, sizeof(buffer));
n = write(writes,buffer,sizeof(buffer));
if (n < 0) perror("ERROR reading from socket");
}
There are a few problems, the most pressing of which is that you're likely pushing garbage data down the the write socket by using sizeof(buffer) when writing. Lets say you read data from the reads socket and it's less than MAX_LINES. When you go to write that data, you'll be writing whatever you read plus the garbage at the end of the buffer (even though you memset at the very beginning, continual use of the same buffer without reacting to different read sizes will probably generate some garbage.
Try getting the return value from read and using it in your write. If the read return indicates an error, clean up and either exit or try again, depending on how you want your program to behave.
int n, size;
while (1) {
size = read(reads, buffer, sizeof(buffer));
if (size > 0) {
n = write(writes, buffer, size);
if (n != size) {
// write error, do something
}
} else {
// Read error, do something
}
}
This, of course, assumes your writes and reads are valid file descriptors.
These two lines look very suspicious:
int reads = atoi(argv[1]) ;
int writes = atoi(argv[3]) ;
Do you really get file/socket descriptor numbers on the command line? From where?
Check the return value of your read(2) and write(2), and then the value of errno(3) - they probably tell you that your file descriptors are invalid (EBADF).
One point not made thus far: Although you know that the file descriptors are valid, you should include some sanity checking of the command line.
if (argc < 3) {
printf("usage: foo: input output\n");
exit(0);
}
Even with this sanity checking passing parameters like this on a command line can be dangerous.
The memset() is not needed, provided you change the following (which you should do nevertheless).
read() has a result, telling you how much it has actually read. This you should give to write() in order to write only what you actually have, removing the need for zeroing.
MAX_LINE should be at least 512, if not more.
There probably are some more issues, but I think I have the most important ones.

how can i cause a segmentation fault on this program? (to help me find a buffer overflow exploit)

I see that the code below uses memcpy which i can use to exploit this program and cause a buffer overflow, but i cant seem to make it crash. No matter what character argument i pass to it i just get "error opening packet file." Any ideas how?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MAX_ADDR_LEN 128
#define ADDR_LENGTH_OFFSET 4
#define ADDR_OFFSET 8
typedef unsigned char shsize_t;
typedef struct{
char addr[MAX_ADDR_LEN];
shsize_t len;
} arp_addr;
void
print_address(char *packet)
{
arp_addr hwaddr;
int i;
hwaddr.len = (shsize_t) *(packet + ADDR_LENGTH_OFFSET);
memcpy(hwaddr.addr, packet + ADDR_OFFSET, hwaddr.len);
printf("Sender hardware address: ");
for (i = 0; i < hwaddr.len - 1; i ++)
printf("%02hhx::", hwaddr.addr[i]);
printf("%02hhx\n", hwaddr.addr[hwaddr.len - 1]);
return;
}
int main(int argc, char *argv[])
{
struct stat sbuf;
char *packet;
int fd;
if (argc != 2){
printf("Usage: %s <packet file>\n", argv[0]);
return EXIT_FAILURE;
}
if ((stat(argv[1], &sbuf)) < 0){
printf("Error opening packet file\n");
return EXIT_FAILURE;
}
if ((fd = open(argv[1], O_RDONLY)) < 0){
printf("Error opening packet file\n");
return EXIT_FAILURE;
}
if ((packet = (char *)malloc(sbuf.st_size * sizeof(char))) == NULL){
printf("Error allocating memory\n");
return EXIT_FAILURE;
}
if (read(fd, packet, sbuf.st_size) < 0){
printf("Error reading packet from file\n");
return EXIT_FAILURE;
}
close(fd);
print_address(packet);
free(packet);
return EXIT_SUCCESS;
}
When you do something like write past the end of a buffer there is no guarantee that the program will crash. This is called undefined behavior, which literally means that you can make no reasonable assumptions as to what will happen.
The program itself appears relatively well behaved. As long as len is calculated properly I don't see any way for you to cause an overrun via input. Just because a program uses memcpy doesn't mean that it is vulnerable to attack. The only attack vector I see is if you pass it a carefully crafted file such that the length is calculated incorrectly:
hwaddr.len = (shsize_t) *(packet + ADDR_LENGTH_OFFSET)
In this line the program reads ADDR_LENGTH_OFFSET bytes from the address of packet to get the data length. Obviously that is problematic if you craft a file with an erroneous value for the data length in the header (i.e., a data length > MAX_ADDR_LEN).
BTW, the argument is a file, not a character. You won't be able to do anything passing it nonsense input because read will fail.
No matter what character argument i pass to it i just get "error
opening packet file."
You need to pass a valid file name as an argument, not random characters.
As others have indicated, the memcpy() isn't the security problem. The problem is that the length parameter passed to memcpy() comes from user input (the file you specified). If you specify a file that has a length field of, say, a billion, you will probably see a crash (and, yes, 'crash' is accepted vernacular).
Since there is rather limited checking on the size of the packet, you can pass it the name of an empty or very short file and the print_address() code will mess around out of bounds.
Also, since the code reads a length from the data read from the file, you can place an arbitrary number at relevant position and make the code go running around most places in memory.

Resources