Program do not crash on heap overflow

516 views Asked by At

I have written following program:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main(int argc, char *argv[]){
  char *input;
  input = (char*)malloc(16);
  printf("input is : %s\n", input);
}

When I run this as:

./test `python -c 'print "A"*5000'`

it does not crash. It rather prints data.

When I use free(input) after printf, it crashes.

Why does this happen?

2

There are 2 answers

1
kocica On

Why does this happen?

Buffer overflow (in this case heap overflow) doesn't cause immediately crash. Writing outside of bounds of allocated memory causes undefined behavior - anything might happen; even it can work correctly.

Is there a reliable way to create crash without having free()

If you don't even initialize pointer input and dereference it (read or write there), most likely you will get a SEGFAULT, but it's still 'only' undefined behavior.

From C99 draft standard

Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).


But be be careful

An overflow may result in data corruption or unexpected behavior by any process which uses the affected memory area. On operating systems without memory protection, this could be any process on the system.

6
Jonathan Leffler On

The code shown ignores its command line arguments:

int main(int argc, char *argv[]){
  char *input;
  input = (char*)malloc(16);
  printf("input is : %s\n", input);
}

It shouldn't matter what the Python script provides. However, your printf() is printing uninitialized data; that leads to undefined behaviour. If the printf() doesn't crash and there is a free(input); call after the printf(), then the free() shouldn't crash.

If you missed out a copy operation and intended to show something like this, then the rules are different:

int main(int argc, char *argv[]){
  char *input;
  input = (char*)malloc(16);
  strcpy(input, argv[1]);
  printf("input is : %s\n", input);
  free(input);
  return 0;
}

Now you are not checking that argv[1] is not a null pointer before you use it — that could cause a crash. And you are trampling way out of bounds of the allocated memory if you pass 5000 characters in argv[1]. Something will probably trigger a crash; it isn't defined what will cause the crash. The strcpy() may fail; the printf() probably won't fail if the copy doesn't (but that isn't guaranteed); the free() will probably fail because you trampled out of bounds (but even that isn't guaranteed). Such are the wonders of 'undefined behaviour'; anything could happen and it is valid behaviour.