kasan: hide invalid free check implementation
[linux-2.6-microblaze.git] / mm / mmap.c
index d91ecb0..dc72060 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1808,6 +1808,17 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
                if (error)
                        goto unmap_and_free_vma;
 
+               /* Can addr have changed??
+                *
+                * Answer: Yes, several device drivers can do it in their
+                *         f_op->mmap method. -DaveM
+                * Bug: If addr is changed, prev, rb_link, rb_parent should
+                *      be updated for vma_link()
+                */
+               WARN_ON_ONCE(addr != vma->vm_start);
+
+               addr = vma->vm_start;
+
                /* If vm_flags changed after call_mmap(), we should try merge vma again
                 * as we may succeed this time.
                 */
@@ -1822,25 +1833,12 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
                                fput(vma->vm_file);
                                vm_area_free(vma);
                                vma = merge;
-                               /* Update vm_flags and possible addr to pick up the change. We don't
-                                * warn here if addr changed as the vma is not linked by vma_link().
-                                */
-                               addr = vma->vm_start;
+                               /* Update vm_flags to pick up the change. */
                                vm_flags = vma->vm_flags;
                                goto unmap_writable;
                        }
                }
 
-               /* Can addr have changed??
-                *
-                * Answer: Yes, several device drivers can do it in their
-                *         f_op->mmap method. -DaveM
-                * Bug: If addr is changed, prev, rb_link, rb_parent should
-                *      be updated for vma_link()
-                */
-               WARN_ON_ONCE(addr != vma->vm_start);
-
-               addr = vma->vm_start;
                vm_flags = vma->vm_flags;
        } else if (vm_flags & VM_SHARED) {
                error = shmem_zero_setup(vma);
@@ -1899,8 +1897,8 @@ out:
        return addr;
 
 unmap_and_free_vma:
+       fput(vma->vm_file);
        vma->vm_file = NULL;
-       fput(file);
 
        /* Undo any partial mapping done by a device driver. */
        unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end);
@@ -2733,8 +2731,8 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma,
        struct vm_area_struct *new;
        int err;
 
-       if (vma->vm_ops && vma->vm_ops->split) {
-               err = vma->vm_ops->split(vma, addr);
+       if (vma->vm_ops && vma->vm_ops->may_split) {
+               err = vma->vm_ops->may_split(vma, addr);
                if (err)
                        return err;
        }
@@ -3407,10 +3405,14 @@ static const char *special_mapping_name(struct vm_area_struct *vma)
        return ((struct vm_special_mapping *)vma->vm_private_data)->name;
 }
 
-static int special_mapping_mremap(struct vm_area_struct *new_vma)
+static int special_mapping_mremap(struct vm_area_struct *new_vma,
+                                 unsigned long flags)
 {
        struct vm_special_mapping *sm = new_vma->vm_private_data;
 
+       if (flags & MREMAP_DONTUNMAP)
+               return -EINVAL;
+
        if (WARN_ON_ONCE(current->mm != new_vma->vm_mm))
                return -EFAULT;
 
@@ -3420,6 +3422,17 @@ static int special_mapping_mremap(struct vm_area_struct *new_vma)
        return 0;
 }
 
+static int special_mapping_split(struct vm_area_struct *vma, unsigned long addr)
+{
+       /*
+        * Forbid splitting special mappings - kernel has expectations over
+        * the number of pages in mapping. Together with VM_DONTEXPAND
+        * the size of vma should stay the same over the special mapping's
+        * lifetime.
+        */
+       return -EINVAL;
+}
+
 static const struct vm_operations_struct special_mapping_vmops = {
        .close = special_mapping_close,
        .fault = special_mapping_fault,
@@ -3427,6 +3440,7 @@ static const struct vm_operations_struct special_mapping_vmops = {
        .name = special_mapping_name,
        /* vDSO code relies that VVAR can't be accessed remotely */
        .access = NULL,
+       .may_split = special_mapping_split,
 };
 
 static const struct vm_operations_struct legacy_special_mapping_vmops = {