Merge branch 'kvm-amd-pmu-fixes' into HEAD
[linux-2.6-microblaze.git] / mm / vmalloc.c
index 99e0f3e..0b17498 100644 (file)
@@ -74,7 +74,7 @@ static const bool vmap_allow_huge = false;
 
 bool is_vmalloc_addr(const void *x)
 {
-       unsigned long addr = (unsigned long)x;
+       unsigned long addr = (unsigned long)kasan_reset_tag(x);
 
        return addr >= VMALLOC_START && addr < VMALLOC_END;
 }
@@ -631,7 +631,7 @@ int is_vmalloc_or_module_addr(const void *x)
         * just put it in the vmalloc space.
         */
 #if defined(CONFIG_MODULES) && defined(MODULES_VADDR)
-       unsigned long addr = (unsigned long)x;
+       unsigned long addr = (unsigned long)kasan_reset_tag(x);
        if (addr >= MODULES_VADDR && addr < MODULES_END)
                return 1;
 #endif
@@ -795,6 +795,8 @@ static struct vmap_area *find_vmap_area_exceed_addr(unsigned long addr)
        struct vmap_area *va = NULL;
        struct rb_node *n = vmap_area_root.rb_node;
 
+       addr = (unsigned long)kasan_reset_tag((void *)addr);
+
        while (n) {
                struct vmap_area *tmp;
 
@@ -816,6 +818,8 @@ static struct vmap_area *__find_vmap_area(unsigned long addr)
 {
        struct rb_node *n = vmap_area_root.rb_node;
 
+       addr = (unsigned long)kasan_reset_tag((void *)addr);
+
        while (n) {
                struct vmap_area *va;
 
@@ -1667,17 +1671,6 @@ static DEFINE_MUTEX(vmap_purge_lock);
 /* for per-CPU blocks */
 static void purge_fragmented_blocks_allcpus(void);
 
-#ifdef CONFIG_X86_64
-/*
- * called before a call to iounmap() if the caller wants vm_area_struct's
- * immediately freed.
- */
-void set_iounmap_nonlazy(void)
-{
-       atomic_long_set(&vmap_lazy_nr, lazy_max_pages()+1);
-}
-#endif /* CONFIG_X86_64 */
-
 /*
  * Purges all lazily-freed vmap areas.
  */
@@ -2166,7 +2159,7 @@ EXPORT_SYMBOL_GPL(vm_unmap_aliases);
 void vm_unmap_ram(const void *mem, unsigned int count)
 {
        unsigned long size = (unsigned long)count << PAGE_SHIFT;
-       unsigned long addr = (unsigned long)mem;
+       unsigned long addr = (unsigned long)kasan_reset_tag(mem);
        struct vmap_area *va;
 
        might_sleep();
@@ -2227,14 +2220,19 @@ void *vm_map_ram(struct page **pages, unsigned int count, int node)
                mem = (void *)addr;
        }
 
-       kasan_unpoison_vmalloc(mem, size);
-
        if (vmap_pages_range(addr, addr + size, PAGE_KERNEL,
                                pages, PAGE_SHIFT) < 0) {
                vm_unmap_ram(mem, count);
                return NULL;
        }
 
+       /*
+        * Mark the pages as accessible, now that they are mapped.
+        * With hardware tag-based KASAN, marking is skipped for
+        * non-VM_ALLOC mappings, see __kasan_unpoison_vmalloc().
+        */
+       mem = kasan_unpoison_vmalloc(mem, size, KASAN_VMALLOC_PROT_NORMAL);
+
        return mem;
 }
 EXPORT_SYMBOL(vm_map_ram);
@@ -2460,10 +2458,20 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,
                return NULL;
        }
 
-       kasan_unpoison_vmalloc((void *)va->va_start, requested_size);
-
        setup_vmalloc_vm(area, va, flags, caller);
 
+       /*
+        * Mark pages for non-VM_ALLOC mappings as accessible. Do it now as a
+        * best-effort approach, as they can be mapped outside of vmalloc code.
+        * For VM_ALLOC mappings, the pages are marked as accessible after
+        * getting mapped in __vmalloc_node_range().
+        * With hardware tag-based KASAN, marking is skipped for
+        * non-VM_ALLOC mappings, see __kasan_unpoison_vmalloc().
+        */
+       if (!(flags & VM_ALLOC))
+               area->addr = kasan_unpoison_vmalloc(area->addr, requested_size,
+                                                   KASAN_VMALLOC_PROT_NORMAL);
+
        return area;
 }
 
@@ -2547,7 +2555,7 @@ struct vm_struct *remove_vm_area(const void *addr)
                va->vm = NULL;
                spin_unlock(&vmap_area_lock);
 
-               kasan_free_shadow(vm);
+               kasan_free_module_shadow(vm);
                free_unmap_vmap_area(va);
 
                return vm;
@@ -3071,7 +3079,8 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,
                        const void *caller)
 {
        struct vm_struct *area;
-       void *addr;
+       void *ret;
+       kasan_vmalloc_flags_t kasan_flags = KASAN_VMALLOC_NONE;
        unsigned long real_size = size;
        unsigned long real_align = align;
        unsigned int shift = PAGE_SHIFT;
@@ -3124,10 +3133,50 @@ again:
                goto fail;
        }
 
-       addr = __vmalloc_area_node(area, gfp_mask, prot, shift, node);
-       if (!addr)
+       /*
+        * Prepare arguments for __vmalloc_area_node() and
+        * kasan_unpoison_vmalloc().
+        */
+       if (pgprot_val(prot) == pgprot_val(PAGE_KERNEL)) {
+               if (kasan_hw_tags_enabled()) {
+                       /*
+                        * Modify protection bits to allow tagging.
+                        * This must be done before mapping.
+                        */
+                       prot = arch_vmap_pgprot_tagged(prot);
+
+                       /*
+                        * Skip page_alloc poisoning and zeroing for physical
+                        * pages backing VM_ALLOC mapping. Memory is instead
+                        * poisoned and zeroed by kasan_unpoison_vmalloc().
+                        */
+                       gfp_mask |= __GFP_SKIP_KASAN_UNPOISON | __GFP_SKIP_ZERO;
+               }
+
+               /* Take note that the mapping is PAGE_KERNEL. */
+               kasan_flags |= KASAN_VMALLOC_PROT_NORMAL;
+       }
+
+       /* Allocate physical pages and map them into vmalloc space. */
+       ret = __vmalloc_area_node(area, gfp_mask, prot, shift, node);
+       if (!ret)
                goto fail;
 
+       /*
+        * Mark the pages as accessible, now that they are mapped.
+        * The init condition should match the one in post_alloc_hook()
+        * (except for the should_skip_init() check) to make sure that memory
+        * is initialized under the same conditions regardless of the enabled
+        * KASAN mode.
+        * Tag-based KASAN modes only assign tags to normal non-executable
+        * allocations, see __kasan_unpoison_vmalloc().
+        */
+       kasan_flags |= KASAN_VMALLOC_VM_ALLOC;
+       if (!want_init_on_free() && want_init_on_alloc(gfp_mask))
+               kasan_flags |= KASAN_VMALLOC_INIT;
+       /* KASAN_VMALLOC_PROT_NORMAL already set if required. */
+       area->addr = kasan_unpoison_vmalloc(area->addr, real_size, kasan_flags);
+
        /*
         * In this function, newly allocated vm_struct has VM_UNINITIALIZED
         * flag. It means that vm_struct is not fully initialized.
@@ -3139,7 +3188,7 @@ again:
        if (!(vm_flags & VM_DEFER_KMEMLEAK))
                kmemleak_vmalloc(area, size, gfp_mask);
 
-       return addr;
+       return area->addr;
 
 fail:
        if (shift > PAGE_SHIFT) {
@@ -3424,6 +3473,8 @@ long vread(char *buf, char *addr, unsigned long count)
        unsigned long buflen = count;
        unsigned long n;
 
+       addr = kasan_reset_tag(addr);
+
        /* Don't allow overflow */
        if ((unsigned long) addr + count < count)
                count = -(unsigned long) addr;
@@ -3809,9 +3860,6 @@ retry:
        for (area = 0; area < nr_vms; area++) {
                if (kasan_populate_vmalloc(vas[area]->va_start, sizes[area]))
                        goto err_free_shadow;
-
-               kasan_unpoison_vmalloc((void *)vas[area]->va_start,
-                                      sizes[area]);
        }
 
        /* insert all vm's */
@@ -3824,6 +3872,16 @@ retry:
        }
        spin_unlock(&vmap_area_lock);
 
+       /*
+        * Mark allocated areas as accessible. Do it now as a best-effort
+        * approach, as they can be mapped outside of vmalloc code.
+        * With hardware tag-based KASAN, marking is skipped for
+        * non-VM_ALLOC mappings, see __kasan_unpoison_vmalloc().
+        */
+       for (area = 0; area < nr_vms; area++)
+               vms[area]->addr = kasan_unpoison_vmalloc(vms[area]->addr,
+                               vms[area]->size, KASAN_VMALLOC_PROT_NORMAL);
+
        kfree(vas);
        return vms;