Getting Segmentation Fault in C when using sleep with Pthreads - c

I am creating a thread in C with PThreads which executes a function that is running in an infinit loop and prints some random json string every second into the console. At the beginning he prints the result of the function simulateLED with no problem, but after sleeping for 1 second, I'll get a Segmentation Fault (Core dumped). If I remove sleep, I'll not get it and the program works fine. Why do I get a Segmentation Fault with sleeping and how to fix it?
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
char *simulateLED() {
int temp;
int luftf;
char* jsonString;
time_t t;
srand((unsigned) time(&t));
int x=-10, y=50;
temp=(rand()%((y+1)-x))+x;
x=2, y=30;
luftf=(rand()%((y+1)-x))+x;
printf("%d %d\n", temp, luftf);
fflush(stdout);
sprintf(jsonString, "{\n\"TEMP\": %d,\n\"HUMI\": %d\n}", temp, luftf);
return jsonString;
}
void *simAndSendThread(void *param) {
while(1) {
printf("%s", simulateLED());
sleep(1);
}
}
int main(int argc, char *argv[]) {
pthread_t thread;
if(pthread_create(&thread, NULL, simAndSendThread, NULL)) {
fprintf(stderr, "Error creating thread\n");
return 1;
}
if(pthread_join(thread, NULL)) {
fprintf(stderr, "Error joining thread\n");
return 2;
}
pthread_exit(NULL);
return 0;
}

As #DavidSchwartz has pointed out, the reason for the Segmentation fault (core dumped) error is related to the jsonString pointer, that is currently not initialized (i.e., not pointing to anything). Hence, sprintf is writing to a random location, which might or might not work at times.
In order to fix it, you can statically assign space to the jsonString variable when you declare it, such as:
...
char jsonString[256];
...
This implies that you can have a string up to 255 characters (1 extra character reserved for \0). Alternatively, you can dynamically allocate the space using malloc:
...
char *jsonString = (char *)malloc(sizeof(char) * 256);
// Your code here
free(jsonString);
...
In this case, you must remember to release the allocation at the end of your function using free, otherwise you will leak memory. In case you haven't learned about dynamic memory yet, see When and why to use malloc?.
P.S.: If you are on Linux, I strongly recommend to use valgrind when you have memory-related errors. This tool will most probably hint where did you made the mistake. Check the Valgrind Quick Start Guide for more information.

You haven't allocated memory to jsonString and still trying to do sprintf and after return print
Try this
char* jsonString;
jsonString = malloc( 1024 );
And don't forget to free once done, you are using a while(1) and if you don't free there is every chance that you'll hit the out of memory error very soon.
If you enable full warnings you should have received a warning message for uninitialized variable for which eventually would have avoided all the crahes.

Related

How am I supposed to successfully achieve buffer overflow?

I am currently tackling on an assignment, where I need to upload exploit.c and target.c onto a ubuntu server, and successfully achieve a buffer overflow attack with exploit onto target. I was provided a shellcode. Now, target.c is not to be altered, just exploit.c. I had to use GDB on exploit.c to force an external breakpoint on foo() from target.c, to figure out the return addresses using info frame.
I was provided with the working shellcode, and minimal instructions.
I am pretty sure I was able to successfully pull the return addresses, but my issue is that I cannot figure out what code to put into exploit.c to have it successfully perform a buffer overflow attack. I was also instructed that one of the return addresses must be input into the exploit code for it to function properly.
I understand that the exploit is trying to call back to the return address, to then push itself into the buffer, so I can obtain access to the shell.
Here is exploit.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "shellcode.h"
// replace this define environment to have the correct path of your own target code
#define TARGET "/*******************"
int main(void)
{
char *args[3];
char *env[2];
char *tmp = NULL;
// Creating an input buffer that can cause buffer overflow in strcpy function in the target.c executable code
int buffSize = 1000;
char buff[buffSize];
// Intialize buffer elements to 0x01
int i;
for (i=0; i < buffSize; i++) buff[i] = 0x01;
// write your code below to fill the 22 bytes shellcode into the buff variable, and
// at the correct location overwrite the return address correctly in order to achieve stack overflow
// Your own code starts here:
strcpy (buff[buffSize-22], shellcode);
// Your code ends here.
// prepare command line input to execute target code
args[0] = TARGET; // you must have already compiled and generated the target executable code first
args[1] = buff; // the first input parameter to the target code (artfully crafted buffer overflow string)
args[2] = NULL;
env[0] = "FOO=bar";
env[1] = NULL;
if (0 > execve(TARGET, args, env))
fprintf(stderr, "execve failed.\n");
return 0;
}
Here is the target.c code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int foo(char* arg)
{
char localBuf[240];
short len = 240;
float var1=2.4;
int *ptr = NULL;
strcpy(localBuf, arg);
printf("foo() finishes normally.\n");
return 0;
}
int kbhit(void)
{
struct timeval tv;
fd_set read_fd;
tv.tv_sec=0; tv.tv_usec=0;
FD_ZERO(&read_fd); FD_SET(0,&read_fd);
if(select(1, &read_fd, NULL, NULL, &tv) == -1)
return 0;
if(FD_ISSET(0,&read_fd))
return 1;
return 0;
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "target: argc != 2\n");
exit(EXIT_FAILURE);
}
printf("Press any key to call foo function...\n");
while(!kbhit())
;
foo(argv[1]);
return 0;
}
I compiled both target and exploit. Then I ran GDB on exploit, and formed a breakpoint using "break target.c:10". Using Info Frame I was able to obtain the return addresses.
I used strcpy, because it is essentially the only line of code we were taught for this section involving overflow attacks, even though it clearly states in the document "Fill the shell executable code (in the string array shellcode[]) byte-by-
byte into the buff for your modified return address to execute, do not
use strcpy() because shellcode[] is not an ASCII string (and not
copying NULL byte, too)."
Exploit compiles fine, and it runs fine, but it does not give me access to a shell. I was instructed that I would know if it worked, if I was presented with two dollar signs ($$) instead of one ($).
I am a network engineer, and I am not entirely savvy with C, or attacking vulnerabilities in programs, any help would be appreciated. The entire lesson revolves around "stack overflow", but this assignment is called "buffer overflow attack".

Segmentation fault after pthread_cancel

In my program I have two threads, one calculates some recursive function and other displays "progress dots" as first threads does calculations. There is the code:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#define test_errno(msg) do{if (errno) {perror(msg); exit(EXIT_FAILURE);}} while(0)
void *progressDotsThread(void* _arg){
for(int i=0;;i++){
printf(".");
fflush(stdout);
sleep(1);
}
}
void *seriesCalculateThread(void* n){
int result;
if((long)n==1) return (void*)(1);
else if((long)n==2) return (void*)(-5);
else{
int nmin1 = (long)seriesCalculateThread( (void*) ( (long)n -1 ));
int nmin2 = (long)seriesCalculateThread( (void*) ( (long)n -2 ));
result = nmin1*((long)n)*nmin2;
return (void*)(result);
}
}
int main(void) {
long n=0;
int result =0;
pthread_t w1,w2;
printf("Give n\n");
scanf ("%d",&n);
if(n<1){
printf("Value must be higher than 0");
}
else{
errno= pthread_create(&w2,NULL,seriesCalculateThread,(void *)n);
test_errno("pthread_create");
errno= pthread_create(&w1,NULL,progressDotsThread,NULL);
test_errno("pthread_create");
if(!pthread_join(w2,(void**)&result)){
errno = pthread_cancel(w1); //<--- Where segmentation fault happens
test_errno("pthread_cancel");
}
printf("%d\n", result);
}
return EXIT_SUCCESS;
}
I pthread_create both of them and then I if(!pthread_join) the one that does calculations and when calculations finish I cancel the one that display dots.
if(!pthread_join(w2,(void**)&result)){
errno = pthread_cancel(w1); //<--- Where segmentation fault happens
test_errno("pthread_cancel");
}
I do that although I get segmentation fault after pthread_cancel(w1) is called and I have no idea why that happens.
I tried compiling it terminal with gcc -g -Wall -pthread psthreadss.c -lpthread and it didn't work as well as in eclipse. I use Ubuntu 18.04 if that's revelant.
and then I if(!pthread_join) the one that does calculations and when calculations finish I cancel the one that display dots.
Your program has a logical bug, and a memory corruption bug.
The logical bug: you are assuming that !pthread_join means that calculations finished. It doesn't mean that. pthread_join returns non-zero status only if you invoked it with incorrect parameters (thread id w2 is not known, has not been started, or has already been joined).
Your code should instead look something like this:
int rc = pthread_join(w2, ...);
assert(rc == 0);
rc = pthread_cancel(w1);
assert (rc == 0);
On to the memory corruption bug: on a 64-bit system (which is what I assume you are using), sizeof(int) == sizeof(result) == 4, but sizeof(void*) == 8.
This code:
int result =0;
...
pthread_join(w1, (void**)&result)
takes an address of 4-byte result, and asks pthread_join to store an 8-byte value in there. Predictable outcome from this is stack corruption.
I don't see how exactly that triggers the SIGSEGV, but once you have undefined behavior in your program, all bets are off.
To fix this, change result type to intptr_t. I expect the crash to disappear after that fix.
You should also try to use Address Sanitizer: gcc -fsanitize=address -g ... before making any changes. There is a high chance it will tell you about stack overflow.

Segmentation fault when returning a pointer

I'm trying to make a code in C that can get environment variable and then search for a specific word from that result using strstr. I'm using UBUNTU OS and gcc compiler. Here is the code that I've written. The comment are what I expected to happen.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
extern char **environ;
extern char **tmp;
extern char **tmp2;
char *search_string(char *tmp,int x)
{
char string[]="ABC"; //I'm looking for ABC in the environment variable
char *pointer;
pointer=strstr(tmp,string); //pointer will point to the result of strstr
if(pointer != NULL)
{ printf("%s ,",tmp);
printf("data found : %s \n",pointer);
} else {
//hope to do something
}
return (pointer);
}
int main(char *tmp2)
{
int x = 0;
for(x=0;environ[x]!='\0';x++){ //I'm expecting it to keep looping until finish
tmp2=search_string(environ[x],x); //tmp2 will point to the function return value
printf("%s\n",tmp2); //print the return value
} //If the search_string return NULL, does it consider string or something else?
return 0;
}
After running the code, it crashes because of core dump. Here are the output.
ABC=/tmp ,data found : ABC=/tmp
ABC=/tmp
Segmentation fault (core dumped)
From what I see, it can only do the search_string for only 1 time. Then it crashes. Then I use gdb to find out at what line does it actually crash and here are the result:
Starting program: /home/fikrie/a.out
ABC=/tmp ,data found : ABC=/tmp
ABC=/tmp
Program received signal SIGSEGV, Segmentation fault.
__strlen_ia32 () at ../sysdeps/i386/i686/multiarch/../../i586/strlen.S:99
99 ../sysdeps/i386/i686/multiarch/../../i586/strlen.S: No such file or directory.
What I dont understand from the debug is that it's receiving error because of SEGV signal. Can someone point me on how to solve this problem? Is it because the search_string returns a NULL value?
The problem is that if search_string() doesn't find the string, it returns NULL. You then pass that NULL to printf(), which crashes.
In main(), you need something like:
if (tmp2)
printf("%s\n", tmp2);
Also, the tmp2 variable should be of type char *, not char **. And there's no reason not to declare it local to main().
A very simple change to your main loop stops the program from crashing:
int main(char *tmp2)
{
int x = 0;
for(x=0;environ[x]!='\0';x++){ //I'm expecting it to keep looping until finish
tmp2=search_string(environ[x],x); //tmp2 will point to the function return value
// >>>>> change these next two lines:
if(tmp2 != NULL) printf("%s\n",tmp2); //print the return value
else printf("%s does not contain ABC\n", environ[x]);
// <<<<< end of change
} //If the search_string return NULL, does it consider string or something else?
return 0;
}
Note that if you only expect one match, you could add a break; when you print the match. The above code prints out all the environment variables - you can see it doesn't stop...

When should errno be assigned to ENOMEM?

The following program is killed by the kernel when the memory is ran out. I would like to know when the global variable should be assigned to "ENOMEM".
#define MEGABYTE 1024*1024
#define TRUE 1
int main(int argc, char *argv[]){
void *myblock = NULL;
int count = 0;
while(TRUE)
{
myblock = (void *) malloc(MEGABYTE);
if (!myblock) break;
memset(myblock,1, MEGABYTE);
printf("Currently allocating %d MB\n",++count);
}
exit(0);
}
First, fix your kernel not to overcommit:
echo "2" > /proc/sys/vm/overcommit_memory
Now malloc should behave properly.
As "R" hinted, the problem is the default behaviour of Linux memory management, which is "overcommiting". This means that the kernel claims to allocate you memory successfuly, but doesn't actually allocate the memory until later when you try to access it. If the kernel finds out that it's allocated too much memory, it kills a process with "the OOM (Out Of Memory) killer" to free up some memory. The way it picks the process to kill is complicated, but if you have just allocated most of the memory in the system, it's probably going to be your process that gets the bullet.
If you think this sounds crazy, some people would agree with you.
To get it to behave as you expect, as R said:
echo "2" > /proc/sys/vm/overcommit_memory
It happens when you try to allocate too much memory at once.
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
void *p;
p = malloc(1024L * 1024 * 1024 * 1024);
if(p == NULL)
{
printf("%d\n", errno);
perror("malloc");
}
}
In your case the OOM killer is getting to the process first.
I think errno will be set to ENOMEM:
Macro defined in stdio.h. Here is the documentation.
#define ENOMEM 12 /* Out of Memory */
After you call malloc in this statement:
myblock = (void *) malloc(MEGABYTE);
And the function returns NULL -because system is out of memory -.
I found this SO question very interesting.
Hope it helps!

swapcontext() segmentation fault

I am trying to create a simple hello world example using swapcontext()
Here is the code snippet:
#include <ucontext.h>
#include <stdio.h>
#include <stdlib.h>
static ucontext_t uctx_main, uctx_func1;
typedef struct test_struct
{
ucontext_t context;
int value;
}test_struct;
test_struct* array[10];
static void
func1(void)
{
printf("func1: started\n");
printf("func1: TESTING\n");
printf("func1: returning\n");
}
void init()
{
memset(array,NULL,10);
array[0] = (test_struct*)malloc(sizeof(test_struct));
array[0]->value = 10;
getcontext(&array[0]->context);
char* func1_stack = (char*)malloc(sizeof(char)*64);
//char func1_stack[64];
array[0]->context.uc_stack.ss_sp = func1_stack;
array[0]->context.uc_stack.ss_size = 64;
array[0]->context.uc_link = &uctx_main;
makecontext(&array[0]->context, func1, 0);
}
int main(int argc, char *argv[])
{
init();
printf("VALUE: %d\n",array[0]->value);
swapcontext(&uctx_main, &array[0]->context);
printf("VALUE: %d\n",array[0]->value);
printf("main: exiting\n");
exit(0);
}
But the problem is when the progam executes swapcontext() a segmentation fault occurs. I have fiddled around a bit and I figured out that the problem is the stack size that I am assigning to the context but I don't know what I am doing wrong.
P.S. I have tried assigning sizeof(func1_stack) but still got a seg fault
Can anyone give me a hint?
Using 64 as the stack size as coded is consistent with the actual given stack size. However, 64 bytes is fairly small for a stack. The example here uses 16K as the stack size. It may be that the size you are using is simply too small.
As an aside, the memset is probably not correct. It is setting the first 10 bytes of the array. It is not actually affecting anything, but it should probably be the following:
memset(array,0,sizeof(array)));

Resources