bufbomb
or MIT 6.033’s buffer overrun hands-on#include <inttypes.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
uint16_t x = 0xbeef;
uint8_t a, b;
a = (uint8_t)x;
b = *(uint8_t *)&x;
printf("%" PRIx8 " %" PRIx8 "\n", a, b);
}
a
: always 0xef
b
: depends on endiannessn
from networkn
bytesn
is not known in advancevoid *
malloc(size_t n);
n
bytesptr
[ptr, ptr + n)
is now yoursNULL
void
free(void *ptr);
ptr
ptr
is a return value from malloc
/calloc
/realloc
ptr
has never been freed beforecalloc
, realloc
/* allocate a block of n ints: [0, n-1] */
int *foo(size_t n) {
size_t i;
int *p = malloc(n * sizeof(int));
if (p == NULL)
return NULL;
for (i = 0; i < n; i++)
p[i] = i;
return p;
}
void bar(size_t n) {
int *p = foo(n);
...
free(p);
}
what if n
is a very large integer?
/**
* malloc_array - allocate memory for an array.
* n: number of elements.
* size: element size.
*/
void *malloc_array(size_t n, size_t size)
{
???
return malloc(n * size);
}
assume the maximum value of size_t
is SIZE_MAX
see also: kmalloc_array, reallocarray, and dlcalloc
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
char gvar[128];
int main(void) {
char buf[64];
void *ptr = malloc(32);
printf("gvar: %p\n", gvar);
printf("buf: %p\n", buf);
printf("ptr: %p\n", ptr);
printf("main: %p\n\n", main);
snprintf(buf, sizeof(buf), "cat /proc/%d/maps", getpid());
return system(buf);
}
lifetime of gvar
, buf
, and ptr
?
allocation type | lifetime | |
---|---|---|
gvar |
static (global) | the entire program execution |
buf |
automatic (local) | between function entry & exit |
ptr |
dynamic | between malloc & free |
can overflow happen?
example: libgc/Boehm GC
malloc()
free()
anymoreless control: unpredictable pause
examples: Objective-C, file descriptors, C++’s shared_ptr
NSArray *arr = [ [ NSArray alloc ] init ]; // counter: 1
[arr retain]; // counter: 2
[arr release]; // counter: 1
[arr release]; // counter: 0, freed
retain
: counter incremented by 1release
: counter decremented by 1examples: Apache web server, Subversion
apr_pool_t *pool;
apr_pool_create(&pool, NULL);
...
char *buf = apr_palloc(pool, 128);
long *arr = apr_palloc(pool, sizeof(long) * 10);
...
apr_pool_destroy(pool);
apr_palloc(pool, n)
: allocate n bytes from poolapr_pool_destroy(pool)
: free the entire poolwrite and test a program that defines:
Point
float
s for the x, y coordinateRectangle
Point
sRectangle
Point
is in a Rectangle
see solution
typedef struct complex_st {
double real; // real component
double imag; // imaginary component
} Complex;
typedef struct complex_set_st {
int num_points_in_set;
Complex *points; // an array of Complex
} ComplexSet;
ComplexSet *AllocSet(Complex c_arr[], int size) { ... }
void FreeSet(ComplexSet *set) { ... }
AllocSet
needs to use malloc
twice: to allocate a ComplexSet
, and to allocate points
inside it; FreeSet
needs to use free twice
see solution
typedef
)