Skip to content

Commit

Permalink
mm: vmalloc make lazy unmapping configurable
Browse files Browse the repository at this point in the history
Lazy unmapping in the vmalloc code has now opened the possibility for use
after free bugs to go undetected.  We can catch those by forcing an unmap
and flush (which is going to be slow, but that's what happens).

Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Nick Piggin authored and torvalds committed Jan 6, 2009
1 parent e97a630 commit cd52858
Showing 1 changed file with 24 additions and 0 deletions.
24 changes: 24 additions & 0 deletions mm/vmalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,27 @@ static void unmap_vmap_area(struct vmap_area *va)
vunmap_page_range(va->va_start, va->va_end);
}

static void vmap_debug_free_range(unsigned long start, unsigned long end)
{
/*
* Unmap page tables and force a TLB flush immediately if
* CONFIG_DEBUG_PAGEALLOC is set. This catches use after free
* bugs similarly to those in linear kernel virtual address
* space after a page has been freed.
*
* All the lazy freeing logic is still retained, in order to
* minimise intrusiveness of this debugging feature.
*
* This is going to be *slow* (linear kernel virtual address
* debugging doesn't do a broadcast TLB flush so it is a lot
* faster).
*/
#ifdef CONFIG_DEBUG_PAGEALLOC
vunmap_page_range(start, end);
flush_tlb_kernel_range(start, end);
#endif
}

/*
* lazy_max_pages is the maximum amount of virtual address space we gather up
* before attempting to purge with a TLB flush.
Expand Down Expand Up @@ -914,6 +935,7 @@ void vm_unmap_ram(const void *mem, unsigned int count)
BUG_ON(addr & (PAGE_SIZE-1));

debug_check_no_locks_freed(mem, size);
vmap_debug_free_range(addr, addr+size);

if (likely(count <= VMAP_MAX_ALLOC))
vb_free(mem, size);
Expand Down Expand Up @@ -1130,6 +1152,8 @@ struct vm_struct *remove_vm_area(const void *addr)
if (va && va->flags & VM_VM_AREA) {
struct vm_struct *vm = va->private;
struct vm_struct *tmp, **p;

vmap_debug_free_range(va->va_start, va->va_end);
free_unmap_vmap_area(va);
vm->size -= PAGE_SIZE;

Expand Down

0 comments on commit cd52858

Please sign in to comment.