MODE=-DGHC_CRASH_MODE
#!/bin/bash
##
# Heap overflow Checker
# Version: 0.2.0
# Written by grip2
##
mkdir heapof_check
cd heapof_check
## README
cat <<> README
grip2@debian:~/heapof_check$ ls
Makefile README ghc.c test.c
grip2@debian:~/heapof_check$ make
gcc -shared -o ghc.so -fPIC ghc.c -nostdlib -ldl -Wall
ghc.c:30: warning: integer constant is too large for 'long' type
grip2@debian:~/heapof_check$ export LD_PRELOAD=/home/grip2/heapof_check/ghc.so
grip2@debian:~/heapof_check$ ./test
[** warning **] head overflow at 0x80496d0
[** warning **] tail overflow at 0x80496f0
[** error **] free NULL pointer
grip2@debian:~/heapof_check$ export LD_PRELOAD=
grip2@debian:~/heapof_check$
__EOF__
## ghc.c
cat <<> ghc.c
/**
* ghc.c -- Heap overflow Check
* version: 0.2.0
* Written by grip2
*/
#define _GNU_SOURCE /* for RTLD_NEXT */
#include
#include
#include
#include
#include
#include
#include
#include
enum { /* memory Alloc MODE */
AMODE_MALLOC = 0,
#define AMDOE_MALLOC AMODE_MALLOC
AMODE_SBRK,
#define AMDOE_SBRK AMODE_SBRK
};
#define hc_log(...) do { printf(__VA_ARGS__); printf("\n"); } while (0)
void *malloc(size_t size);
void free(void *ptr);
void *realloc(void *ptr, size_t size);
void *calloc(size_t nmemb, size_t size);
static void __hc_init(void);
typedef void *malloc_t(size_t size);
static malloc_t *pmalloc;
typedef void free_t(void *);
static free_t *pfree;
#ifndef GHC_CRASH_MODE
typedef long long magic_stamp_t;
static magic_stamp_t magic_stamp = 0x1976112619770116;
#endif
static volatile int init_flag = 0; /* for pmalloc, pfree, etc. */
int hc_lock = 0;
#if 0
int main(void)
{
char *banner = "** ghc.so - Heap overflow Check.\n"
"** Version 0.2.0\n"
"Written by grip2
return 0;
}
#endif
static void __hc_init(void)
{
char *error;
#ifdef GHC_DEBUG
printf("** Heap overflow Checker init ...\n");
#endif
dlerror(); /* see man dlsym */
pmalloc = (malloc_t *) dlsym(RTLD_NEXT, "malloc");
if ((error = dlerror()) != NULL) { /* JFF: man dlerror */
fprintf(stderr, "in %s line %d: %s\n", __FILE__, __LINE__,
error);
goto err;
}
pfree = (free_t *) dlsym(RTLD_NEXT, "free");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "in %s line %d: %s\n", __FILE__, __LINE__, error);
goto err;
}
return;
err:
exit(-1); /* kill program is better than continue */
}
static void safe_hc_init(void)
{
int val;
val = 1;
__asm__ volatile (
"xchgl %1,%0"
:"=r" (hc_lock)
:"m" (val), "0" (hc_lock)
:"memory");
if (!val) {
__hc_init();
init_flag = 1;
} else {
while (init_flag == 0);
}
}
#ifndef GHC_CRASH_MODE
static inline void *get_head_from_user(void *ptr)
{
void *pmem;
pmem = (char *) ptr - sizeof(magic_stamp) - 2*sizeof(int);
return pmem;
}
static inline void *get_user_from_head(void *pmem)
{
void *ptr;
ptr = (char *) pmem + sizeof(magic_stamp) + 2*sizeof(int);
return ptr;
}
static int memcheck(void *pmem)
{
magic_stamp_t tail_stamp, head_stamp;
int size, size2; /* don't use size_t or unsigned type */
int res = 0;
void *ptr;
/* get head stamp */
memcpy(&head_stamp, pmem, sizeof(head_stamp));
if (memcmp(&head_stamp, &magic_stamp, sizeof(magic_stamp)) != 0) {
hc_log("[** warning **]\t head overflow at %p (stamp)", pmem);
res = -1;
}
/* check length section */
size = *(int *) ((char *) pmem + sizeof(head_stamp));
size2 = *(int *) ((char *) pmem + sizeof(head_stamp) + sizeof(int));
if (size != size2 || size < 0) {
hc_log("[** warning **]\t head overflow at %p (user length)", (char *) pmem + sizeof(head_stamp));
return -1;
}
/* get tail stamp */
ptr = get_user_from_head(pmem);
memcpy(&tail_stamp, ptr + size, sizeof(tail_stamp));
if (memcmp(&tail_stamp, &magic_stamp, sizeof(magic_stamp)) != 0) {
hc_log("[** warning **]\t tail overflow at %p", (char *) pmem + size);
return -1;
}
return res;
}
#endif /* ifndef GHC_CRASH_MODE */
static inline size_t get_user_size(void *ptr)
{
size_t size;
#ifdef GHC_CRASH_MODE
size = *(int *) (ptr - sizeof(unsigned long) - sizeof(unsigned int));
#else
void *pmem;
pmem = get_head_from_user(ptr);
if (memcheck(pmem) != 0)
return -1;
size = *(int *) ((char *) pmem + sizeof(magic_stamp));
#endif
return size;
}
static void *__ghc_alloc(size_t size, int mode)
{
void *pmem, *ptr = NULL;
size_t realsize;
#ifdef GHC_DEBUG
printf("** __ghc_alloc -- mode [%d]\n", mode);
#endif
#ifdef GHC_CRASH_MODE
/**
* memory map: | stuff1 | user_length | real start_addr | user chunk | memory trap | stuff2 | */
realsize = sizeof(unsigned int) /* user_length */
+ sizeof(unsigned long) /* start_addr */
+ size /* user chunk */
+ PAGE_SIZE /* trap */
+ (PAGE_SIZE-1); /* padding (stuff1 + stuff2)*/
#else /* !GHC_CRASH_MODE */
/**
* memory map: | magic | user length | user length | user space | magic | */
realsize = size + 2*sizeof(magic_stamp) + 2*sizeof(int);
#endif
switch (mode) {
case AMODE_MALLOC:
assert(init_flag);
pmem = pmalloc(realsize);
break;
case AMODE_SBRK:
pmem = sbrk(realsize);
if (pmem == (void *) -1)
pmem = NULL;
break;
default:
fprintf(stderr, "Unkonwn ALLOC_MODE [%d]\n", mode);
exit(-1);
}
#ifdef GHC_DEBUG
printf(" ** GHC real malloc: %p\n", pmem);
#endif
if (pmem) {
#ifdef GHC_CRASH_MODE
void *trap;
trap = (void *) ((unsigned long)(pmem + realsize - PAGE_SIZE) & ~(PAGE_SIZE-1));
ptr = trap - size;
*(unsigned long *)(ptr-sizeof(unsigned long)) = (unsigned long) pmem;
*(unsigned int *)(ptr-sizeof(unsigned long)-sizeof(unsigned int)) = size;
if (mprotect(trap, PAGE_SIZE, PROT_NONE)) {
perror("mprotect");
exit(-1);
}
#else /* !GHC_CRASH_MODE */
/* set head stamp */
memcpy(pmem, &magic_stamp, sizeof(magic_stamp));
*(int *) ((char *) pmem + sizeof(magic_stamp)) = (int) size;
*(int *) ((char *) pmem + sizeof(magic_stamp) + sizeof(int)) = (int) size;
/* get user chunk pointer */
ptr = get_user_from_head(pmem);
/* set tail stamp */
memcpy((char *) ptr + size, &magic_stamp, sizeof(magic_stamp));
#endif
}
return ptr;
}
void *malloc(size_t size)
{
#ifdef GHC_DEBUG
printf("** GHC malloc\n");
#endif
if (init_flag == 0) {
safe_hc_init();
}
return __ghc_alloc(size, AMODE_MALLOC);
}
static void __ghc_free(void *ptr)
{
void *pmem;
#ifdef GHC_DEBUG
printf("** __ghc_free\n");
#endif
if (!ptr) {
hc_log("[** warning **]\t free NULL pointer");
return;
}
#ifdef GHC_CRASH_MODE
void *trap;
int size = get_user_size(ptr);
trap = ptr + size;
if (mprotect(trap, PAGE_SIZE, PROT_READ|PROT_WRITE)) {
perror("mprotect");
exit(-1);
}
pmem = *(void **) (ptr - sizeof(unsigned long));
#else
/* get head pointer */
pmem = get_head_from_user(ptr);
if (memcheck(pmem) != 0)
return;
#endif
#ifdef GHC_DEBUG
printf(" ** GHC real free: %p\n", pmem);
#endif
pfree(pmem);
}
void free(void *ptr)
{
#ifdef GHC_DEBUG
printf("** GHC free\n");
#endif
if (init_flag == 0) {
if (!hc_lock) {
fprintf(stderr, "** PANIC PRELOAD - free **\n");
#ifdef GHC_DEBUG
exit(-1);
#endif
}
return;
}
__ghc_free(ptr);
}
void *realloc(void *ptr, size_t size)
{
void *new;
size_t oldsize;
#ifdef GHC_DEBUG
printf("** GHC realloc\n");
#endif
if (init_flag == 0) {
fprintf(stderr, "** PANIC PRELOAD - realloc **\n");
return NULL;
}
if (!ptr) /* see man realloc */
return __ghc_alloc(size, AMODE_MALLOC);
if (!size) { /* see man realloc */
__ghc_free(ptr);
return NULL;
}
new = __ghc_alloc(size, AMODE_MALLOC);
if (new) {
oldsize = get_user_size(ptr);
memcpy(new, ptr, (oldsize*>*/size)?oldsize:size);
__ghc_free(ptr);
}
return new;
}
void *calloc(size_t nmemb, size_t size)
{
void *p;
size_t len;
int mode;
#ifdef GHC_DEBUG
printf("** GHC calloc\n");
#endif
len = nmemb*size;
mode = (!init_flag && hc_lock)? AMODE_SBRK : AMODE_MALLOC;
if (mode == AMODE_MALLOC) {
safe_hc_init();
}
p = __ghc_alloc(len, mode);
if (p)
bzero(p, len); /* see man calloc */
return p;
}
/* wait a moment ... */
/*
void hc_log(...)
{
}
*/
__EOF__
## test.c
cat <<> test.c
#include
#include
#include
int main(void)
{
void *p = malloc(16);
void *q = malloc(16);
bzero(p, 16);
bzero(p, 18);
#ifndef GHC_CRASH_MODE
*(char *) (p - 9) = 2;
#endif
q = realloc(q, 32);
free(q);
free(p);
free(NULL);
return 0;
}
__EOF__
## Makefile
cat <<> Makefile
#MODE=-DGHC_CRASH_MODE
CFLAG= -Wall -O2 -DNDEBUG \$(MODE)
#CFLAG= -DGHC_DEBUG -ggdb \$(MODE)
CC=gcc
all: test so
test: test.c
\$(CC) \$< -o test \$(CFLAG)
so: ghc.c
\$(CC) -shared -o ghc.so -fPIC \$< -nostdlib -ldl \$(CFLAG)
clean:
rm -f *.o ghc.so test
__EOF__
没有评论:
发表评论