swapcontext() segmentation fault - c

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)));

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".

Getting Segmentation Fault in C when using sleep with Pthreads

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.

Segfault when passing structure from main() to worker functions

I am trying to write a simple game in C and I'm getting a SEGFAULT and have no idea why!
Here is the code for the program:
#include <stdio.h>
#include <string.h>
#define MAX_PLYS_PER_GAME (1024)
#define MAX_LEN (100)
typedef struct {
char positionHistory[MAX_PLYS_PER_GAME][MAX_LEN];
} Game;
void getInitialGame(Game * game) {
memset(game->positionHistory, 0, MAX_PLYS_PER_GAME*MAX_LEN*sizeof(char));
}
void printGame(Game game) {
printf("Game -> %p (%d)\n", &game, sizeof(game));
fflush(stdout);
}
int hasGameEnded(Game game) {
printGame(game);
return 0;
}
int main(int argc, char *argv[]) {
Game game;
getInitialGame(&game);
if (hasGameEnded(game))
return -1;
return 0;
}
I tried debugging with gdb but the results didn't get me too far:
C:\Users\test>gdb test.exe
GNU gdb 5.1.1 (mingw experimental)
<snip>
This GDB was configured as "mingw32"...
(gdb) run
Starting program: C:\Users\test/test.exe
Program received signal SIGSEGV, Segmentation fault.
0x00401368 in main (argc=1, argv=0x341c88) at fast-chess-bug.c:29
29 if (hasGameEnded(game))
(gdb) bt
#0 0x00401368 in main (argc=1, argv=0x341c88) at fast-chess-bug.c:29
It is probably a stack overflow (really!), although I'm not sure.
You are declaring Game game; in main(). That means all 102400 bytes of game are going on the stack.
Both printGame and hasGameEnded take a Game game, NOT a Game * game. That is, they are getting a copy of the Game, not a pointer to the existing Game. Therefore, you dump another 102400 bytes on the stack whenever you call either one.
I am guessing that the call to printGame is clobbering the stack in a way that causes problems with the hasGameEnded call.
The easiest fix I know of (without getting into dynamic memory allocation, which may be better long-term) is:
Move Game game; outside of main(), e.g., to the line just above int main(...). That way it will be in the data segment and not on the stack.
Change printGame and hasGameEnded to take Game *:
void printGame(Game * game) {
printf("Game -> %p (%d)\n", game, sizeof(Game));
fflush(stdout);
}
int hasGameEnded(Game * game) {
printGame(game);
return 0;
}
That should get you moving forward.
You're likely running out of stack space.
C is pass-by-value. So this code
int hasGameEnded(Game game)
creates a copy of the entire struct {} Game, most likely on the stack.
If the following code works, you ran out of stack space:
...
void printGame(Game *game) {
printf("Game -> %p (%zu)\n", game, sizeof(*game));
fflush(stdout);
}
int hasGameEnded(Game *game) {
printGame(game);
return 0;
}
int main(int argc, char *argv[]) {
Game game;
getInitialGame(&game);
if (hasGameEnded(&game))
return -1;
return 0;
}
Note carefully the changes. Instead of passing the entire structure to hasGameEnded, it's now passing just the address of the structure. That change flows down the call stack, culminating in changes to printGame().
Note also that the proper format specifier for sizeof includes a z modifier. And I took the liberty of making it u for unsigned since a size can't be negative.

How to check if malloc() overcommits memory

In my C program, based on the user's input, memory will be allocated for a given simulation. The initial problem I faced is that user can ask for a huge number to allocate but malloc() never fails until it runs out of memory then the program crashes.
I investigated the logic behind this and it now makes sense to me, see [1][2]. A possible workaround given here "SIGKILL while allocating memory in C++" suggests to set overcommit_memory in in /proc/sys/vm/overcommit_memory from 0 to 2.
This solved the problem from one side. But since I am using -fsanitize=address I get error from sanitizer.
Is there any better solution to this?
I guess the clang AddressSanitizer is failing because there is a legit leak. So my answer ignores that:
Alternatives:
Disable the overcommit behaviour, as you have already figured out: that is going to affect other processes and requires root.
run you app in a docker image with the oom killer disabled: that doesn't affect other processes but requires root to install docker (this is my favourite solution though).
write after malloc: may take long to alloc a huge chunk of memory and your process can still get killed because of other running process but doesn't require root.
use ulimit -v to limit the amount of memory depending on the machine: that also doesn't require root but your process might be killed anyway.
Code for the third alternative (for linux):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <setjmp.h>
jmp_buf resume_malloc;
void handle_malloc_error(int sig)
{
longjmp(resume_malloc, sig);
}
void *memalloc(size_t sz) {
void *p = 0;
int sig = setjmp(resume_malloc);
if ( sig == 0 ) {
p = malloc(sz);
signal(SIGSEGV, &handle_malloc_error);
memset(p, 0, sz);
} else {
p = 0;
}
signal(SIGSEGV, SIG_DFL);
return p;
}
int main(int argc, char *argv[])
{
size_t sz = 160L * 1024 * 1024 * 1024L;
void *p;
for (int i=0; i < 100; i++) {
printf("size: %lu\n", sz);
p = memalloc(sz);
if ( p == 0 ) {
printf("out of memory\n");
break;
}
sz *= 2;
}
}

Consistently Getting Null Value in C String using getcwd

I am trying to make a simple program that just writes your working directory to a file, and I cannot, for the life of me, figure out what I am doing wrong. No matter what I do, my buffer is storing null after my call to getcwd(). I suspect it may have to do with permissions, but allegedly, linux now did some wizardry to ensure that getcwd almost never has access problems (keyword, "almost"). Can anyone test it on their machines? Or is there an obvious bug I am missing?
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
printf("Error is with fopen if stops here\n");
FILE* out_file = fopen("dir_loc.sh","w+");
char* loc = malloc(sizeof(char)*10000);
size_t size = sizeof(loc);
printf("Error is with cwd if stops here\n");
loc = getcwd(loc,size);
printf("%s",loc);
fprintf(out_file,"cd %s",loc);
printf("Error is with fclose if stops here\n");
free(loc);
fclose(out_file);
return 0;
}
compiled with gcc main.c (the file is named "main.c")
EDIT: As was mentioned by different posters, sizeof(loc) was taking the size of a char pointer, and not the size of the amount of space allocated to that pointer. Changed it to malloc(sizeof(char)*1000) and it all works gravy.
Your problem is here:
size_t size = sizeof(loc);
You're getting the size of a char pointer, not the allocated memory for your char.
Change it to:
size_t size = sizeof(char) * 10000;
or even to
size_t size = 10000;
since sizeof(char) is guaranteed to be 1.
And since you're using size in your subsequent call to getcwd, you're obviously gonna have too little space to store most paths, so your result is unsurprising
If you don't want to go about changing multiple different numbers in the code every time you make a change, you can use #DEFINE text replacement to solve that.
Like this:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define LOC_ARRAY_SIZE 10000 // Here you define the array size
int main(int argc, char *argv[])
{
printf("Error is with fopen if stops here\n");
FILE* out_file = fopen("dir_loc.sh","w+");
char* loc = malloc(sizeof(char)*LOC_ARRAY_SIZE); // sizeof(char) could be omitted
size_t size = sizeof(char)*LOC_ARRAY_SIZE;
printf("Error is with cwd if stops here\n");
loc = getcwd(loc,size);
printf("%s",loc);
fprintf(out_file,"cd %s",loc);
printf("Error is with fclose if stops here\n");
free(loc);
fclose(out_file);
return 0;
}

Resources