OSDN Git Service

crypto: talitos - HMAC SNOOP NO AFEU mode requires SW icv checking.
[android-x86/kernel.git] / mm / vmalloc.c
index f2481cb..dd66f1f 100644 (file)
@@ -244,11 +244,21 @@ struct page *vmalloc_to_page(const void *vmalloc_addr)
         */
        VIRTUAL_BUG_ON(!is_vmalloc_or_module_addr(vmalloc_addr));
 
+       /*
+        * Don't dereference bad PUD or PMD (below) entries. This will also
+        * identify huge mappings, which we may encounter on architectures
+        * that define CONFIG_HAVE_ARCH_HUGE_VMAP=y. Such regions will be
+        * identified as vmalloc addresses by is_vmalloc_addr(), but are
+        * not [unambiguously] associated with a struct page, so there is
+        * no correct value to return for them.
+        */
        if (!pgd_none(*pgd)) {
                pud_t *pud = pud_offset(pgd, addr);
-               if (!pud_none(*pud)) {
+               WARN_ON_ONCE(pud_bad(*pud));
+               if (!pud_none(*pud) && !pud_bad(*pud)) {
                        pmd_t *pmd = pmd_offset(pud, addr);
-                       if (!pmd_none(*pmd)) {
+                       WARN_ON_ONCE(pmd_bad(*pmd));
+                       if (!pmd_none(*pmd) && !pmd_bad(*pmd)) {
                                pte_t *ptep, pte;
 
                                ptep = pte_offset_map(pmd, addr);
@@ -449,7 +459,11 @@ nocache:
        }
 
 found:
-       if (addr + size > vend)
+       /*
+        * Check also calculated address against the vstart,
+        * because it can be 0 because of big align request.
+        */
+       if (addr + size > vend || addr < vstart)
                goto overflow;
 
        va->va_start = addr;
@@ -1484,7 +1498,7 @@ static void __vunmap(const void *addr, int deallocate_pages)
                        addr))
                return;
 
-       area = remove_vm_area(addr);
+       area = find_vmap_area((unsigned long)addr)->vm;
        if (unlikely(!area)) {
                WARN(1, KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n",
                                addr);
@@ -1494,6 +1508,7 @@ static void __vunmap(const void *addr, int deallocate_pages)
        debug_check_no_locks_freed(addr, get_vm_area_size(area));
        debug_check_no_obj_freed(addr, get_vm_area_size(area));
 
+       remove_vm_area(addr);
        if (deallocate_pages) {
                int i;
 
@@ -1693,6 +1708,12 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,
                return NULL;
 
        /*
+        * First make sure the mappings are removed from all page-tables
+        * before they are freed.
+        */
+       vmalloc_sync_all();
+
+       /*
         * In this function, newly allocated vm_struct has VM_UNINITIALIZED
         * flag. It means that vm_struct is not fully initialized.
         * Now, it is fully initialized, so remove this flag here.
@@ -2180,7 +2201,7 @@ int remap_vmalloc_range_partial(struct vm_area_struct *vma, unsigned long uaddr,
        if (!(area->flags & VM_USERMAP))
                return -EINVAL;
 
-       if (kaddr + size > area->addr + area->size)
+       if (kaddr + size > area->addr + get_vm_area_size(area))
                return -EINVAL;
 
        do {
@@ -2228,6 +2249,9 @@ EXPORT_SYMBOL(remap_vmalloc_range);
 /*
  * Implement a stub for vmalloc_sync_all() if the architecture chose not to
  * have one.
+ *
+ * The purpose of this function is to make sure the vmalloc area
+ * mappings are identical in all page-tables in the system.
  */
 void __weak vmalloc_sync_all(void)
 {