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 0xefb: 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);
ptrptr is a return value from malloc/calloc/reallocptr 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
floats for the x, y coordinateRectangle
PointsRectanglePoint is in a Rectanglesee 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)