]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
take security_mmap_file() outside of ->mmap_sem
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 30 May 2012 21:11:23 +0000 (17:11 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 1 Jun 2012 14:37:01 +0000 (10:37 -0400)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
include/linux/security.h
ipc/shm.c
mm/mmap.c
mm/nommu.c
security/security.c

index f1bae0963ddc0bc886d5c210d67db3df71d70461..4e5a73cdbbef18463920022626931d02c0540eb9 100644 (file)
@@ -1745,8 +1745,8 @@ int security_file_permission(struct file *file, int mask);
 int security_file_alloc(struct file *file);
 void security_file_free(struct file *file);
 int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-int security_mmap_file(struct file *file, unsigned long reqprot,
-                       unsigned long prot, unsigned long flags);
+int security_mmap_file(struct file *file, unsigned long prot,
+                       unsigned long flags);
 int security_mmap_addr(unsigned long addr);
 int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
                           unsigned long prot);
@@ -2183,8 +2183,7 @@ static inline int security_file_ioctl(struct file *file, unsigned int cmd,
        return 0;
 }
 
-static inline int security_mmap_file(struct file *file, unsigned long reqprot,
-                                    unsigned long prot,
+static inline int security_mmap_file(struct file *file, unsigned long prot,
                                     unsigned long flags)
 {
        return 0;
index 406c5b208193373b979ce82bffe6617250ea64ed..e3a8063b1768eb4d01f68b9e061b2b629acbb6f9 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -1036,6 +1036,10 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
        sfd->file = shp->shm_file;
        sfd->vm_ops = NULL;
 
+       err = security_mmap_file(file, prot, flags);
+       if (err)
+               goto out_fput;
+
        down_write(&current->mm->mmap_sem);
        if (addr && !(shmflg & SHM_REMAP)) {
                err = -EINVAL;
@@ -1058,6 +1062,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
 invalid:
        up_write(&current->mm->mmap_sem);
 
+out_fput:
        fput(file);
 
 out_nattch:
index 49283da9a2ae483d4a5a9fd734903d3ec46d4f8a..34b280f4238daf8356a7631d693bb738c18be3fd 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -979,7 +979,6 @@ static unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
        struct inode *inode;
        vm_flags_t vm_flags;
        int error;
-       unsigned long reqprot = prot;
 
        /*
         * Does the application expect PROT_READ to imply PROT_EXEC?
@@ -1105,10 +1104,6 @@ static unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
        if (error)
                return error;
 
-       error = security_mmap_file(file, reqprot, prot, flags);
-       if (error)
-               return error;
-
        return mmap_region(file, addr, len, flags, vm_flags, pgoff);
 }
 
@@ -1130,9 +1125,12 @@ unsigned long vm_mmap(struct file *file, unsigned long addr,
        unsigned long ret;
        struct mm_struct *mm = current->mm;
 
-       down_write(&mm->mmap_sem);
-       ret = do_mmap(file, addr, len, prot, flag, offset);
-       up_write(&mm->mmap_sem);
+       ret = security_mmap_file(file, prot, flag);
+       if (!ret) {
+               down_write(&mm->mmap_sem);
+               ret = do_mmap(file, addr, len, prot, flag, offset);
+               up_write(&mm->mmap_sem);
+       }
        return ret;
 }
 EXPORT_SYMBOL(vm_mmap);
@@ -1168,9 +1166,12 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len,
 
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
-       down_write(&current->mm->mmap_sem);
-       retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
+       retval = security_mmap_file(file, prot, flags);
+       if (!retval) {
+               down_write(&current->mm->mmap_sem);
+               retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+               up_write(&current->mm->mmap_sem);
+       }
 
        if (file)
                fput(file);
index acfe419785dbca380512f7f350bb6b4e5a485e85..8cbfd623b04a2b4a3f3302034f6b1baf780bb120 100644 (file)
@@ -889,7 +889,6 @@ static int validate_mmap_request(struct file *file,
                                 unsigned long *_capabilities)
 {
        unsigned long capabilities, rlen;
-       unsigned long reqprot = prot;
        int ret;
 
        /* do the simple checks first */
@@ -1048,9 +1047,6 @@ static int validate_mmap_request(struct file *file,
 
        /* allow the security API to have its say */
        ret = security_mmap_addr(addr);
-       if (ret < 0)
-               return ret;
-       ret = security_mmap_file(file, reqprot, prot, flags);
        if (ret < 0)
                return ret;
 
@@ -1492,9 +1488,12 @@ unsigned long vm_mmap(struct file *file, unsigned long addr,
        unsigned long ret;
        struct mm_struct *mm = current->mm;
 
-       down_write(&mm->mmap_sem);
-       ret = do_mmap(file, addr, len, prot, flag, offset);
-       up_write(&mm->mmap_sem);
+       ret = security_mmap_file(file, prot, flag);
+       if (!ret) {
+               down_write(&mm->mmap_sem);
+               ret = do_mmap(file, addr, len, prot, flag, offset);
+               up_write(&mm->mmap_sem);
+       }
        return ret;
 }
 EXPORT_SYMBOL(vm_mmap);
@@ -1515,9 +1514,12 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len,
 
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
-       down_write(&current->mm->mmap_sem);
-       retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
+       ret = security_mmap_file(file, prot, flags);
+       if (!ret) {
+               down_write(&current->mm->mmap_sem);
+               retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+               up_write(&current->mm->mmap_sem);
+       }
 
        if (file)
                fput(file);
index d91c66d3956bc6106fe33e52fceeac81013cd5e3..3b11b3b72fe2f0af5f561fbbff4dcadb60a4a59a 100644 (file)
@@ -20,6 +20,9 @@
 #include <linux/ima.h>
 #include <linux/evm.h>
 #include <linux/fsnotify.h>
+#include <linux/mman.h>
+#include <linux/mount.h>
+#include <linux/personality.h>
 #include <net/flow.h>
 
 #define MAX_LSM_EVM_XATTR      2
@@ -657,11 +660,35 @@ int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        return security_ops->file_ioctl(file, cmd, arg);
 }
 
-int security_mmap_file(struct file *file, unsigned long reqprot,
-                       unsigned long prot, unsigned long flags)
+int security_mmap_file(struct file *file, unsigned long prot,
+                       unsigned long flags)
 {
+       unsigned long reqprot = prot;
        int ret;
-
+       /*
+        * Does the application expect PROT_READ to imply PROT_EXEC?
+        *
+        * (the exception is when the underlying filesystem is noexec
+        *  mounted, in which case we dont add PROT_EXEC.)
+        */
+       if (!(reqprot & PROT_READ))
+               goto out;
+       if (!(current->personality & READ_IMPLIES_EXEC))
+               goto out;
+       if (!file) {
+               prot |= PROT_EXEC;
+       } else if (!(file->f_path.mnt->mnt_flags & MNT_NOEXEC)) {
+#ifndef CONFIG_MMU
+               unsigned long caps = 0;
+               struct address_space *mapping = file->f_mapping;
+               if (mapping && mapping->backing_dev_info)
+                       caps = mapping->backing_dev_info->capabilities;
+               if (!(caps & BDI_CAP_EXEC_MAP))
+                       goto out;
+#endif
+               prot |= PROT_EXEC;
+       }
+out:
        ret = security_ops->mmap_file(file, reqprot, prot, flags);
        if (ret)
                return ret;