implement slab allocation write-after-free check

pull/50/head
Daniel Micay 2018-09-07 00:00:32 -04:00
parent 918f0d3302
commit 99d68238d2
1 changed files with 29 additions and 8 deletions

View File

@ -20,6 +20,7 @@
static_assert(sizeof(void *) == 8, "64-bit only"); static_assert(sizeof(void *) == 8, "64-bit only");
static const bool guard_slabs = true; static const bool guard_slabs = true;
static const bool enable_write_after_free_check = true;
// either sizeof(uint64_t) or 0 // either sizeof(uint64_t) or 0
static const size_t canary_size = sizeof(uint64_t); static const size_t canary_size = sizeof(uint64_t);
@ -243,10 +244,20 @@ static void *slot_pointer(size_t size, void *slab, size_t slot) {
return (char *)slab + slot * size; return (char *)slab + slot * size;
} }
static void set_canary(struct slab_metadata *metadata, void *p, size_t size, size_t requested_size) { static void write_after_free_check(char *p, size_t size) {
if (requested_size != 0) { if (!enable_write_after_free_check) {
memcpy((char *)p + size - canary_size, &metadata->canary_value, canary_size); return;
} }
for (size_t i = 0; i < size; i += sizeof(uint64_t)) {
if (*(uint64_t *)(p + i)) {
fatal_error("write after free");
}
}
}
static void set_canary(struct slab_metadata *metadata, void *p, size_t size) {
memcpy((char *)p + size - canary_size, &metadata->canary_value, canary_size);
} }
static inline void *slab_allocate(size_t requested_size) { static inline void *slab_allocate(size_t requested_size) {
@ -273,7 +284,10 @@ static inline void *slab_allocate(size_t requested_size) {
size_t slot = get_free_slot(&c->rng, slots, metadata); size_t slot = get_free_slot(&c->rng, slots, metadata);
set_slot(metadata, slot); set_slot(metadata, slot);
void *p = slot_pointer(size, slab, slot); void *p = slot_pointer(size, slab, slot);
set_canary(metadata, p, size, requested_size); if (requested_size) {
write_after_free_check(p, size - canary_size);
set_canary(metadata, p, size);
}
pthread_mutex_unlock(&c->mutex); pthread_mutex_unlock(&c->mutex);
return p; return p;
@ -282,7 +296,7 @@ static inline void *slab_allocate(size_t requested_size) {
metadata->canary_value = get_random_u64(&c->rng); metadata->canary_value = get_random_u64(&c->rng);
void *slab = get_slab(c, slab_size, metadata); void *slab = get_slab(c, slab_size, metadata);
if (requested_size != 0 && memory_protect_rw(slab, slab_size)) { if (requested_size && memory_protect_rw(slab, slab_size)) {
pthread_mutex_unlock(&c->mutex); pthread_mutex_unlock(&c->mutex);
return NULL; return NULL;
} }
@ -300,7 +314,9 @@ static inline void *slab_allocate(size_t requested_size) {
size_t slot = get_free_slot(&c->rng, slots, metadata); size_t slot = get_free_slot(&c->rng, slots, metadata);
set_slot(metadata, slot); set_slot(metadata, slot);
void *p = slot_pointer(size, slab, slot); void *p = slot_pointer(size, slab, slot);
set_canary(metadata, p, size, requested_size); if (requested_size) {
set_canary(metadata, p, size);
}
pthread_mutex_unlock(&c->mutex); pthread_mutex_unlock(&c->mutex);
return p; return p;
@ -318,7 +334,9 @@ static inline void *slab_allocate(size_t requested_size) {
size_t slot = get_free_slot(&c->rng, slots, metadata); size_t slot = get_free_slot(&c->rng, slots, metadata);
set_slot(metadata, slot); set_slot(metadata, slot);
void *p = slot_pointer(size, slab, slot); void *p = slot_pointer(size, slab, slot);
set_canary(metadata, p, size, requested_size); if (requested_size) {
set_canary(metadata, p, size);
}
pthread_mutex_unlock(&c->mutex); pthread_mutex_unlock(&c->mutex);
return p; return p;
@ -337,7 +355,10 @@ static inline void *slab_allocate(size_t requested_size) {
void *slab = get_slab(c, slab_size, metadata); void *slab = get_slab(c, slab_size, metadata);
void *p = slot_pointer(size, slab, slot); void *p = slot_pointer(size, slab, slot);
set_canary(metadata, p, size, requested_size); if (requested_size) {
write_after_free_check(p, size - canary_size);
set_canary(metadata, p, size);
}
pthread_mutex_unlock(&c->mutex); pthread_mutex_unlock(&c->mutex);
return p; return p;