Skip to content

Commit cd52858

Browse files
Nick Piggintorvalds
authored andcommitted
mm: vmalloc make lazy unmapping configurable
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>
1 parent e97a630 commit cd52858

File tree

1 file changed

+24
-0
lines changed

1 file changed

+24
-0
lines changed

mm/vmalloc.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,27 @@ static void unmap_vmap_area(struct vmap_area *va)
434434
vunmap_page_range(va->va_start, va->va_end);
435435
}
436436

437+
static void vmap_debug_free_range(unsigned long start, unsigned long end)
438+
{
439+
/*
440+
* Unmap page tables and force a TLB flush immediately if
441+
* CONFIG_DEBUG_PAGEALLOC is set. This catches use after free
442+
* bugs similarly to those in linear kernel virtual address
443+
* space after a page has been freed.
444+
*
445+
* All the lazy freeing logic is still retained, in order to
446+
* minimise intrusiveness of this debugging feature.
447+
*
448+
* This is going to be *slow* (linear kernel virtual address
449+
* debugging doesn't do a broadcast TLB flush so it is a lot
450+
* faster).
451+
*/
452+
#ifdef CONFIG_DEBUG_PAGEALLOC
453+
vunmap_page_range(start, end);
454+
flush_tlb_kernel_range(start, end);
455+
#endif
456+
}
457+
437458
/*
438459
* lazy_max_pages is the maximum amount of virtual address space we gather up
439460
* before attempting to purge with a TLB flush.
@@ -914,6 +935,7 @@ void vm_unmap_ram(const void *mem, unsigned int count)
914935
BUG_ON(addr & (PAGE_SIZE-1));
915936

916937
debug_check_no_locks_freed(mem, size);
938+
vmap_debug_free_range(addr, addr+size);
917939

918940
if (likely(count <= VMAP_MAX_ALLOC))
919941
vb_free(mem, size);
@@ -1130,6 +1152,8 @@ struct vm_struct *remove_vm_area(const void *addr)
11301152
if (va && va->flags & VM_VM_AREA) {
11311153
struct vm_struct *vm = va->private;
11321154
struct vm_struct *tmp, **p;
1155+
1156+
vmap_debug_free_range(va->va_start, va->va_end);
11331157
free_unmap_vmap_area(va);
11341158
vm->size -= PAGE_SIZE;
11351159

0 commit comments

Comments
 (0)