amdgpu: vmalloc/vfree use mmap with guard pages
vmalloc now allocates with PROT_NONE guard pages on each side, matching Linux kernel vmalloc behavior. Buffers overflow into a guard page and segfault instead of silently corrupting adjacent heap allocations.
This commit is contained in:
@@ -49,13 +49,72 @@ static void redox_jiffies_advance(unsigned long delta)
|
||||
__sync_add_and_fetch(&jiffies, delta);
|
||||
}
|
||||
|
||||
struct redox_vmalloc_region {
|
||||
void *base;
|
||||
size_t total_size;
|
||||
struct redox_vmalloc_region *next;
|
||||
};
|
||||
|
||||
static pthread_mutex_t g_vmalloc_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static struct redox_vmalloc_region *g_vmalloc_regions;
|
||||
|
||||
void *vmalloc(unsigned long size)
|
||||
{
|
||||
return malloc((size_t)size);
|
||||
size_t aligned = PAGE_ALIGN((size_t)size);
|
||||
size_t total = aligned + 2 * PAGE_SIZE;
|
||||
void *base = mmap(NULL, total, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (base == MAP_FAILED) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *usable = (char *)base + PAGE_SIZE;
|
||||
if (mprotect(usable, aligned, PROT_READ | PROT_WRITE) != 0) {
|
||||
munmap(base, total);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct redox_vmalloc_region *reg = malloc(sizeof(*reg));
|
||||
if (!reg) {
|
||||
munmap(base, total);
|
||||
return NULL;
|
||||
}
|
||||
reg->base = base;
|
||||
reg->total_size = total;
|
||||
|
||||
pthread_mutex_lock(&g_vmalloc_lock);
|
||||
reg->next = g_vmalloc_regions;
|
||||
g_vmalloc_regions = reg;
|
||||
pthread_mutex_unlock(&g_vmalloc_lock);
|
||||
|
||||
return usable;
|
||||
}
|
||||
|
||||
void vfree(const void *addr)
|
||||
{
|
||||
if (!addr) {
|
||||
return;
|
||||
}
|
||||
|
||||
void *usable_base = (char *)addr - 0;
|
||||
void *region_base = (char *)addr - PAGE_SIZE;
|
||||
|
||||
struct redox_vmalloc_region **link;
|
||||
pthread_mutex_lock(&g_vmalloc_lock);
|
||||
link = &g_vmalloc_regions;
|
||||
while (*link) {
|
||||
if ((*link)->base == region_base) {
|
||||
struct redox_vmalloc_region *reg = *link;
|
||||
*link = reg->next;
|
||||
pthread_mutex_unlock(&g_vmalloc_lock);
|
||||
munmap(reg->base, reg->total_size);
|
||||
free(reg);
|
||||
return;
|
||||
}
|
||||
link = &(*link)->next;
|
||||
}
|
||||
pthread_mutex_unlock(&g_vmalloc_lock);
|
||||
|
||||
free((void *)addr);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user