kmem: Add KASAN state transitions
Memory allocated with kmem_* is unmapped upon free, so KASAN doesn't provide a lot of benefit, but since allocations are always a multiple of the page size we can create a redzone when the allocation request size is not a multiple of the page size. MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D29458
This commit is contained in:
parent
244f3ec642
commit
2b914b85dd
|
@ -71,12 +71,13 @@ __FBSDID("$FreeBSD$");
|
|||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h> /* for ticks and hz */
|
||||
#include <sys/asan.h>
|
||||
#include <sys/domainset.h>
|
||||
#include <sys/eventhandler.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/rwlock.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/vmem.h>
|
||||
|
@ -220,25 +221,26 @@ kmem_alloc_attr_domain(int domain, vm_size_t size, int flags, vm_paddr_t low,
|
|||
vm_object_t object;
|
||||
vm_offset_t addr, i, offset;
|
||||
vm_page_t m;
|
||||
vm_size_t asize;
|
||||
int pflags;
|
||||
vm_prot_t prot;
|
||||
|
||||
object = kernel_object;
|
||||
size = round_page(size);
|
||||
asize = round_page(size);
|
||||
vmem = vm_dom[domain].vmd_kernel_arena;
|
||||
if (vmem_alloc(vmem, size, M_BESTFIT | flags, &addr))
|
||||
if (vmem_alloc(vmem, asize, M_BESTFIT | flags, &addr))
|
||||
return (0);
|
||||
offset = addr - VM_MIN_KERNEL_ADDRESS;
|
||||
pflags = malloc2vm_flags(flags) | VM_ALLOC_WIRED;
|
||||
prot = (flags & M_EXEC) != 0 ? VM_PROT_ALL : VM_PROT_RW;
|
||||
VM_OBJECT_WLOCK(object);
|
||||
for (i = 0; i < size; i += PAGE_SIZE) {
|
||||
for (i = 0; i < asize; i += PAGE_SIZE) {
|
||||
m = kmem_alloc_contig_pages(object, atop(offset + i),
|
||||
domain, pflags, 1, low, high, PAGE_SIZE, 0, memattr);
|
||||
if (m == NULL) {
|
||||
VM_OBJECT_WUNLOCK(object);
|
||||
kmem_unback(object, addr, i);
|
||||
vmem_free(vmem, addr, size);
|
||||
vmem_free(vmem, addr, asize);
|
||||
return (0);
|
||||
}
|
||||
KASSERT(vm_page_domain(m) == domain,
|
||||
|
@ -251,6 +253,7 @@ kmem_alloc_attr_domain(int domain, vm_size_t size, int flags, vm_paddr_t low,
|
|||
prot | PMAP_ENTER_WIRED, 0);
|
||||
}
|
||||
VM_OBJECT_WUNLOCK(object);
|
||||
kasan_mark((void *)addr, size, asize, KASAN_KMEM_REDZONE);
|
||||
return (addr);
|
||||
}
|
||||
|
||||
|
@ -299,23 +302,24 @@ kmem_alloc_contig_domain(int domain, vm_size_t size, int flags, vm_paddr_t low,
|
|||
vm_object_t object;
|
||||
vm_offset_t addr, offset, tmp;
|
||||
vm_page_t end_m, m;
|
||||
vm_size_t asize;
|
||||
u_long npages;
|
||||
int pflags;
|
||||
|
||||
object = kernel_object;
|
||||
size = round_page(size);
|
||||
asize = round_page(size);
|
||||
vmem = vm_dom[domain].vmd_kernel_arena;
|
||||
if (vmem_alloc(vmem, size, flags | M_BESTFIT, &addr))
|
||||
if (vmem_alloc(vmem, asize, flags | M_BESTFIT, &addr))
|
||||
return (0);
|
||||
offset = addr - VM_MIN_KERNEL_ADDRESS;
|
||||
pflags = malloc2vm_flags(flags) | VM_ALLOC_WIRED;
|
||||
npages = atop(size);
|
||||
npages = atop(asize);
|
||||
VM_OBJECT_WLOCK(object);
|
||||
m = kmem_alloc_contig_pages(object, atop(offset), domain,
|
||||
pflags, npages, low, high, alignment, boundary, memattr);
|
||||
if (m == NULL) {
|
||||
VM_OBJECT_WUNLOCK(object);
|
||||
vmem_free(vmem, addr, size);
|
||||
vmem_free(vmem, addr, asize);
|
||||
return (0);
|
||||
}
|
||||
KASSERT(vm_page_domain(m) == domain,
|
||||
|
@ -332,6 +336,7 @@ kmem_alloc_contig_domain(int domain, vm_size_t size, int flags, vm_paddr_t low,
|
|||
tmp += PAGE_SIZE;
|
||||
}
|
||||
VM_OBJECT_WUNLOCK(object);
|
||||
kasan_mark((void *)addr, size, asize, KASAN_KMEM_REDZONE);
|
||||
return (addr);
|
||||
}
|
||||
|
||||
|
@ -407,21 +412,23 @@ kmem_malloc_domain(int domain, vm_size_t size, int flags)
|
|||
{
|
||||
vmem_t *arena;
|
||||
vm_offset_t addr;
|
||||
vm_size_t asize;
|
||||
int rv;
|
||||
|
||||
if (__predict_true((flags & M_EXEC) == 0))
|
||||
arena = vm_dom[domain].vmd_kernel_arena;
|
||||
else
|
||||
arena = vm_dom[domain].vmd_kernel_rwx_arena;
|
||||
size = round_page(size);
|
||||
if (vmem_alloc(arena, size, flags | M_BESTFIT, &addr))
|
||||
asize = round_page(size);
|
||||
if (vmem_alloc(arena, asize, flags | M_BESTFIT, &addr))
|
||||
return (0);
|
||||
|
||||
rv = kmem_back_domain(domain, kernel_object, addr, size, flags);
|
||||
rv = kmem_back_domain(domain, kernel_object, addr, asize, flags);
|
||||
if (rv != KERN_SUCCESS) {
|
||||
vmem_free(arena, addr, size);
|
||||
vmem_free(arena, addr, asize);
|
||||
return (0);
|
||||
}
|
||||
kasan_mark((void *)addr, size, asize, KASAN_KMEM_REDZONE);
|
||||
return (addr);
|
||||
}
|
||||
|
||||
|
@ -613,6 +620,7 @@ kmem_free(vm_offset_t addr, vm_size_t size)
|
|||
struct vmem *arena;
|
||||
|
||||
size = round_page(size);
|
||||
kasan_mark((void *)addr, size, size, 0);
|
||||
arena = _kmem_unback(kernel_object, addr, size);
|
||||
if (arena != NULL)
|
||||
vmem_free(arena, addr, size);
|
||||
|
|
Loading…
Reference in New Issue