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:
2026-07-10 15:32:31 +03:00
parent abc60b5c15
commit ef89473695
+60 -1
View File
@@ -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);
}