mm: Introduce arch_validate_flags()
authorCatalin Marinas <catalin.marinas@arm.com>
Mon, 25 Nov 2019 17:27:06 +0000 (17:27 +0000)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 4 Sep 2020 11:46:07 +0000 (12:46 +0100)
Similarly to arch_validate_prot() called from do_mprotect_pkey(), an
architecture may need to sanity-check the new vm_flags.

Define a dummy function always returning true. In addition to
do_mprotect_pkey(), also invoke it from mmap_region() prior to updating
vma->vm_page_prot to allow the architecture code to veto potentially
inconsistent vm_flags.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Andrew Morton <akpm@linux-foundation.org>
include/linux/mman.h
mm/mmap.c
mm/mprotect.c

index 6fa15c9b12af3afc789419819955a0ac9e5fb65f..629cefc4ecba671682408ccdfe53a0a0726dcebd 100644 (file)
@@ -108,6 +108,19 @@ static inline bool arch_validate_prot(unsigned long prot, unsigned long addr)
 #define arch_validate_prot arch_validate_prot
 #endif
 
+#ifndef arch_validate_flags
+/*
+ * This is called from mmap() and mprotect() with the updated vma->vm_flags.
+ *
+ * Returns true if the VM_* flags are valid.
+ */
+static inline bool arch_validate_flags(unsigned long flags)
+{
+       return true;
+}
+#define arch_validate_flags arch_validate_flags
+#endif
+
 /*
  * Optimisation macro.  It is equivalent to:
  *      (x & bit1) ? bit2 : 0
index 40248d84ad5fbd486a65a6c45bdf4413e8e6789c..eed30b096667d117a2f8d9ef910729aaa02f1f73 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1812,6 +1812,15 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
                vma_set_anonymous(vma);
        }
 
+       /* Allow architectures to sanity-check the vm_flags */
+       if (!arch_validate_flags(vma->vm_flags)) {
+               error = -EINVAL;
+               if (file)
+                       goto unmap_and_free_vma;
+               else
+                       goto free_vma;
+       }
+
        vma_link(mm, vma, prev, rb_link, rb_parent);
        /* Once vma denies write, undo our temporary denial count */
        if (file) {
index ce8b8a5eacbb62b5185b49c5e829a292886930eb..56c02beb60414129b898416a244f8404cc546e9a 100644 (file)
@@ -603,6 +603,12 @@ static int do_mprotect_pkey(unsigned long start, size_t len,
                        goto out;
                }
 
+               /* Allow architectures to sanity-check the new flags */
+               if (!arch_validate_flags(newflags)) {
+                       error = -EINVAL;
+                       goto out;
+               }
+
                error = security_file_mprotect(vma, reqprot, prot);
                if (error)
                        goto out;