forked from lda/telodendria
Add some basic heap memory bounds protection.
This commit is contained in:
parent
d38ec7cb38
commit
e71ffec164
6 changed files with 80 additions and 21 deletions
|
@ -35,6 +35,11 @@ addprefix() {
|
||||||
: "${LD_EXTRA:=-flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections}"
|
: "${LD_EXTRA:=-flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections}"
|
||||||
: "${LDFLAGS:=-lm -pthread}"
|
: "${LDFLAGS:=-lm -pthread}"
|
||||||
|
|
||||||
|
if [ "${DEBUG}" = "1" ]; then
|
||||||
|
CFLAGS="${CFLAGS} -o0 -g"
|
||||||
|
LD_EXTRA=""
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -n "${TLS_IMPL}" ]; then
|
if [ -n "${TLS_IMPL}" ]; then
|
||||||
case "${TLS_IMPL}" in
|
case "${TLS_IMPL}" in
|
||||||
"LIBRESSL")
|
"LIBRESSL")
|
||||||
|
@ -130,6 +135,7 @@ recipe_build() {
|
||||||
mkdir -p "${BUILD}" "${OUT}/bin" "${OUT}/lib"
|
mkdir -p "${BUILD}" "${OUT}/bin" "${OUT}/lib"
|
||||||
cd "${SRC}"
|
cd "${SRC}"
|
||||||
|
|
||||||
|
|
||||||
echo "CC = ${CC}"
|
echo "CC = ${CC}"
|
||||||
echo "CFLAGS = ${CFLAGS}"
|
echo "CFLAGS = ${CFLAGS}"
|
||||||
echo "LDFLAGS = ${LDFLAGS}"
|
echo "LDFLAGS = ${LDFLAGS}"
|
||||||
|
|
|
@ -24,10 +24,13 @@
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <Int.h>
|
||||||
|
|
||||||
#ifndef MEMORY_TABLE_CHUNK
|
#ifndef MEMORY_TABLE_CHUNK
|
||||||
#define MEMORY_TABLE_CHUNK 256
|
#define MEMORY_TABLE_CHUNK 256
|
||||||
#endif
|
#endif
|
||||||
|
@ -44,6 +47,13 @@ struct MemoryInfo
|
||||||
void *pointer;
|
void *pointer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MEM_BOUND_TYPE UInt16
|
||||||
|
#define MEM_BOUND 0xADDE
|
||||||
|
|
||||||
|
#define MEM_BOUND_LOWER(p) *((MEM_BOUND_TYPE *) p)
|
||||||
|
#define MEM_BOUND_UPPER(p, x) *(((MEM_BOUND_TYPE *) (((UInt8 *) p) + x)) + 1)
|
||||||
|
#define MEM_SIZE_ACTUAL(x) (((x) * sizeof(UInt8)) + (2 * sizeof(MEM_BOUND_TYPE)))
|
||||||
|
|
||||||
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static void (*hook) (MemoryAction, MemoryInfo *, void *) = NULL;
|
static void (*hook) (MemoryAction, MemoryInfo *, void *) = NULL;
|
||||||
static void *hookArgs = NULL;
|
static void *hookArgs = NULL;
|
||||||
|
@ -143,6 +153,21 @@ MemoryDelete(MemoryInfo * a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
MemoryCheck(MemoryInfo *a)
|
||||||
|
{
|
||||||
|
if (MEM_BOUND_LOWER(a->pointer) != MEM_BOUND ||
|
||||||
|
MEM_BOUND_UPPER(a->pointer, a->size - (2 * sizeof(MEM_BOUND_TYPE))) != MEM_BOUND)
|
||||||
|
{
|
||||||
|
if (hook)
|
||||||
|
{
|
||||||
|
hook(MEMORY_CORRUPTED, a, hookArgs);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
MemoryAllocate(size_t size, const char *file, int line)
|
MemoryAllocate(size_t size, const char *file, int line)
|
||||||
{
|
{
|
||||||
|
@ -151,22 +176,26 @@ MemoryAllocate(size_t size, const char *file, int line)
|
||||||
|
|
||||||
pthread_mutex_lock(&lock);
|
pthread_mutex_lock(&lock);
|
||||||
|
|
||||||
p = malloc(size);
|
|
||||||
if (!p)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&lock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
a = malloc(sizeof(MemoryInfo));
|
a = malloc(sizeof(MemoryInfo));
|
||||||
if (!a)
|
if (!a)
|
||||||
{
|
{
|
||||||
free(p);
|
|
||||||
pthread_mutex_unlock(&lock);
|
pthread_mutex_unlock(&lock);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
a->size = size;
|
p = malloc(MEM_SIZE_ACTUAL(size));
|
||||||
|
if (!p)
|
||||||
|
{
|
||||||
|
free(a);
|
||||||
|
pthread_mutex_unlock(&lock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(p, 0, MEM_SIZE_ACTUAL(size));
|
||||||
|
MEM_BOUND_LOWER(p) = MEM_BOUND;
|
||||||
|
MEM_BOUND_UPPER(p, size) = MEM_BOUND;
|
||||||
|
|
||||||
|
a->size = MEM_SIZE_ACTUAL(size);
|
||||||
a->file = file;
|
a->file = file;
|
||||||
a->line = line;
|
a->line = line;
|
||||||
a->pointer = p;
|
a->pointer = p;
|
||||||
|
@ -185,7 +214,7 @@ MemoryAllocate(size_t size, const char *file, int line)
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&lock);
|
pthread_mutex_unlock(&lock);
|
||||||
return p;
|
return ((MEM_BOUND_TYPE *) p) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
|
@ -203,17 +232,20 @@ MemoryReallocate(void *p, size_t size, const char *file, int line)
|
||||||
if (a)
|
if (a)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&lock);
|
pthread_mutex_lock(&lock);
|
||||||
new = realloc(a->pointer, size);
|
new = realloc(a->pointer, MEM_SIZE_ACTUAL(size));
|
||||||
if (new)
|
if (new)
|
||||||
{
|
{
|
||||||
MemoryDelete(a);
|
MemoryDelete(a);
|
||||||
a->size = size;
|
a->size = MEM_SIZE_ACTUAL(size);
|
||||||
a->file = file;
|
a->file = file;
|
||||||
a->line = line;
|
a->line = line;
|
||||||
|
|
||||||
a->pointer = new;
|
a->pointer = new;
|
||||||
MemoryInsert(a);
|
MemoryInsert(a);
|
||||||
|
|
||||||
|
MEM_BOUND_LOWER(a->pointer) = MEM_BOUND;
|
||||||
|
MEM_BOUND_UPPER(a->pointer, size) = MEM_BOUND;
|
||||||
|
|
||||||
if (hook)
|
if (hook)
|
||||||
{
|
{
|
||||||
hook(MEMORY_REALLOCATE, a, hookArgs);
|
hook(MEMORY_REALLOCATE, a, hookArgs);
|
||||||
|
@ -236,8 +268,7 @@ MemoryReallocate(void *p, size_t size, const char *file, int line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ((MEM_BOUND_TYPE *) new) + 1;
|
||||||
return new;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -333,6 +364,7 @@ MemoryInfoGet(void *p)
|
||||||
|
|
||||||
pthread_mutex_lock(&lock);
|
pthread_mutex_lock(&lock);
|
||||||
|
|
||||||
|
p = ((MEM_BOUND_TYPE *) p) - 1;
|
||||||
hash = MemoryHash(p);
|
hash = MemoryHash(p);
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
|
@ -345,6 +377,7 @@ MemoryInfoGet(void *p)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
MemoryCheck(allocations[hash]);
|
||||||
pthread_mutex_unlock(&lock);
|
pthread_mutex_unlock(&lock);
|
||||||
return allocations[hash];
|
return allocations[hash];
|
||||||
}
|
}
|
||||||
|
@ -362,7 +395,7 @@ MemoryInfoGetSize(MemoryInfo * a)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return a->size;
|
return MEM_SIZE_ACTUAL(a->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
|
@ -395,7 +428,7 @@ MemoryInfoGetPointer(MemoryInfo * a)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return a->pointer;
|
return ((MEM_BOUND_TYPE *) a->pointer) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -441,7 +474,6 @@ void
|
||||||
}
|
}
|
||||||
|
|
||||||
pc = MemoryInfoGetPointer(info);
|
pc = MemoryInfoGetPointer(info);
|
||||||
|
|
||||||
for (pI = 0; pI < MemoryInfoGetSize(info); pI++)
|
for (pI = 0; pI < MemoryInfoGetSize(info); pI++)
|
||||||
{
|
{
|
||||||
if (pI > 0 && pI % MEMORY_HEXDUMP_WIDTH == 0)
|
if (pI > 0 && pI % MEMORY_HEXDUMP_WIDTH == 0)
|
||||||
|
|
|
@ -86,7 +86,8 @@ typedef enum MemoryAction
|
||||||
MEMORY_ALLOCATE,
|
MEMORY_ALLOCATE,
|
||||||
MEMORY_REALLOCATE,
|
MEMORY_REALLOCATE,
|
||||||
MEMORY_FREE,
|
MEMORY_FREE,
|
||||||
MEMORY_BAD_POINTER
|
MEMORY_BAD_POINTER,
|
||||||
|
MEMORY_CORRUPTED
|
||||||
} MemoryAction;
|
} MemoryAction;
|
||||||
|
|
||||||
#define Malloc(x) MemoryAllocate(x, __FILE__, __LINE__)
|
#define Malloc(x) MemoryAllocate(x, __FILE__, __LINE__)
|
||||||
|
|
1
TODO.txt
1
TODO.txt
|
@ -24,6 +24,7 @@ Milestone: v0.3.0
|
||||||
[x] Documentation
|
[x] Documentation
|
||||||
[x] hdoc(1) and hdoc(5)
|
[x] hdoc(1) and hdoc(5)
|
||||||
[x] Fix memory leaks in hdoc
|
[x] Fix memory leaks in hdoc
|
||||||
|
[x] Detect memory write out of bounds
|
||||||
|
|
||||||
Milestone: v0.4.0
|
Milestone: v0.4.0
|
||||||
-----------------
|
-----------------
|
||||||
|
|
|
@ -175,6 +175,10 @@ start:
|
||||||
if (flags & ARG_VERBOSE)
|
if (flags & ARG_VERBOSE)
|
||||||
{
|
{
|
||||||
LogConfigLevelSet(LogConfigGlobal(), LOG_DEBUG);
|
LogConfigLevelSet(LogConfigGlobal(), LOG_DEBUG);
|
||||||
|
MemoryHook(TelodendriaMemoryHook, (void *) ARG_VERBOSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
MemoryHook(TelodendriaMemoryHook, NULL);
|
MemoryHook(TelodendriaMemoryHook, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <Routes.h>
|
#include <Routes.h>
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
const char
|
const char
|
||||||
TelodendriaLogo[TELODENDRIA_LOGO_HEIGHT][TELODENDRIA_LOGO_WIDTH] = {
|
TelodendriaLogo[TELODENDRIA_LOGO_HEIGHT][TELODENDRIA_LOGO_WIDTH] = {
|
||||||
|
@ -71,8 +72,12 @@ void
|
||||||
TelodendriaMemoryHook(MemoryAction a, MemoryInfo * i, void *args)
|
TelodendriaMemoryHook(MemoryAction a, MemoryInfo * i, void *args)
|
||||||
{
|
{
|
||||||
char *action;
|
char *action;
|
||||||
|
int warn = 0;
|
||||||
|
|
||||||
(void) args;
|
if (!args && ((a == MEMORY_ALLOCATE) || (a == MEMORY_REALLOCATE) || (a == MEMORY_FREE)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (a)
|
switch (a)
|
||||||
{
|
{
|
||||||
|
@ -86,18 +91,28 @@ TelodendriaMemoryHook(MemoryAction a, MemoryInfo * i, void *args)
|
||||||
action = "Freed";
|
action = "Freed";
|
||||||
break;
|
break;
|
||||||
case MEMORY_BAD_POINTER:
|
case MEMORY_BAD_POINTER:
|
||||||
|
warn = 1;
|
||||||
action = "Bad pointer to";
|
action = "Bad pointer to";
|
||||||
break;
|
break;
|
||||||
|
case MEMORY_CORRUPTED:
|
||||||
|
warn = 1;
|
||||||
|
action = "Corrupted block of";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
action = "Unknown operation on";
|
action = "Unknown operation on";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log(a == MEMORY_BAD_POINTER ? LOG_WARNING : LOG_DEBUG,
|
Log(warn ? LOG_WARNING : LOG_DEBUG,
|
||||||
"%s:%d: %s %lu bytes of memory at %p.",
|
"%s:%d: %s %lu bytes of memory at %p.",
|
||||||
MemoryInfoGetFile(i), MemoryInfoGetLine(i),
|
MemoryInfoGetFile(i), MemoryInfoGetLine(i),
|
||||||
action, MemoryInfoGetSize(i),
|
action, MemoryInfoGetSize(i),
|
||||||
MemoryInfoGetPointer(i));
|
MemoryInfoGetPointer(i));
|
||||||
|
|
||||||
|
if (a == MEMORY_CORRUPTED)
|
||||||
|
{
|
||||||
|
raise(SIGSEGV);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in a new issue