Take mmap lock in cacheflush syscall
authorJann Horn <jannh@google.com>
Fri, 19 Feb 2021 06:59:35 +0000 (14:59 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 4 Mar 2021 10:38:16 +0000 (11:38 +0100)
[ Upstream commit c26958cb5a0d9053d1358258827638773f3d36ed ]

We need to take the mmap lock around find_vma() and subsequent use of the
VMA. Otherwise, we can race with concurrent operations like munmap(), which
can lead to use-after-free accesses to freed VMAs.

Fixes: 1000197d8013 ("nios2: System calls handling")
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
arch/nios2/kernel/sys_nios2.c

index cd390ec..b1ca856 100644 (file)
@@ -22,6 +22,7 @@ asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len,
                                unsigned int op)
 {
        struct vm_area_struct *vma;
+       struct mm_struct *mm = current->mm;
 
        if (len == 0)
                return 0;
@@ -34,16 +35,22 @@ asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len,
        if (addr + len < addr)
                return -EFAULT;
 
+       if (mmap_read_lock_killable(mm))
+               return -EINTR;
+
        /*
         * Verify that the specified address region actually belongs
         * to this process.
         */
-       vma = find_vma(current->mm, addr);
-       if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
+       vma = find_vma(mm, addr);
+       if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) {
+               mmap_read_unlock(mm);
                return -EFAULT;
+       }
 
        flush_cache_range(vma, addr, addr + len);
 
+       mmap_read_unlock(mm);
        return 0;
 }