diff options
-rw-r--r-- | include/linux/security.h | 7 | ||||
-rw-r--r-- | ipc/shm.c | 5 | ||||
-rw-r--r-- | mm/mmap.c | 23 | ||||
-rw-r--r-- | mm/nommu.c | 22 | ||||
-rw-r--r-- | security/security.c | 33 |
5 files changed, 62 insertions, 28 deletions
diff --git a/include/linux/security.h b/include/linux/security.h index f1bae0963ddc..4e5a73cdbbef 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -1745,8 +1745,8 @@ int security_file_permission(struct file *file, int mask); | |||
1745 | int security_file_alloc(struct file *file); | 1745 | int security_file_alloc(struct file *file); |
1746 | void security_file_free(struct file *file); | 1746 | void security_file_free(struct file *file); |
1747 | int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg); | 1747 | int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg); |
1748 | int security_mmap_file(struct file *file, unsigned long reqprot, | 1748 | int security_mmap_file(struct file *file, unsigned long prot, |
1749 | unsigned long prot, unsigned long flags); | 1749 | unsigned long flags); |
1750 | int security_mmap_addr(unsigned long addr); | 1750 | int security_mmap_addr(unsigned long addr); |
1751 | int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, | 1751 | int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, |
1752 | unsigned long prot); | 1752 | unsigned long prot); |
@@ -2183,8 +2183,7 @@ static inline int security_file_ioctl(struct file *file, unsigned int cmd, | |||
2183 | return 0; | 2183 | return 0; |
2184 | } | 2184 | } |
2185 | 2185 | ||
2186 | static inline int security_mmap_file(struct file *file, unsigned long reqprot, | 2186 | static inline int security_mmap_file(struct file *file, unsigned long prot, |
2187 | unsigned long prot, | ||
2188 | unsigned long flags) | 2187 | unsigned long flags) |
2189 | { | 2188 | { |
2190 | return 0; | 2189 | return 0; |
@@ -1036,6 +1036,10 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) | |||
1036 | sfd->file = shp->shm_file; | 1036 | sfd->file = shp->shm_file; |
1037 | sfd->vm_ops = NULL; | 1037 | sfd->vm_ops = NULL; |
1038 | 1038 | ||
1039 | err = security_mmap_file(file, prot, flags); | ||
1040 | if (err) | ||
1041 | goto out_fput; | ||
1042 | |||
1039 | down_write(¤t->mm->mmap_sem); | 1043 | down_write(¤t->mm->mmap_sem); |
1040 | if (addr && !(shmflg & SHM_REMAP)) { | 1044 | if (addr && !(shmflg & SHM_REMAP)) { |
1041 | err = -EINVAL; | 1045 | err = -EINVAL; |
@@ -1058,6 +1062,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) | |||
1058 | invalid: | 1062 | invalid: |
1059 | up_write(¤t->mm->mmap_sem); | 1063 | up_write(¤t->mm->mmap_sem); |
1060 | 1064 | ||
1065 | out_fput: | ||
1061 | fput(file); | 1066 | fput(file); |
1062 | 1067 | ||
1063 | out_nattch: | 1068 | out_nattch: |
@@ -979,7 +979,6 @@ static unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, | |||
979 | struct inode *inode; | 979 | struct inode *inode; |
980 | vm_flags_t vm_flags; | 980 | vm_flags_t vm_flags; |
981 | int error; | 981 | int error; |
982 | unsigned long reqprot = prot; | ||
983 | 982 | ||
984 | /* | 983 | /* |
985 | * Does the application expect PROT_READ to imply PROT_EXEC? | 984 | * 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, | |||
1105 | if (error) | 1104 | if (error) |
1106 | return error; | 1105 | return error; |
1107 | 1106 | ||
1108 | error = security_mmap_file(file, reqprot, prot, flags); | ||
1109 | if (error) | ||
1110 | return error; | ||
1111 | |||
1112 | return mmap_region(file, addr, len, flags, vm_flags, pgoff); | 1107 | return mmap_region(file, addr, len, flags, vm_flags, pgoff); |
1113 | } | 1108 | } |
1114 | 1109 | ||
@@ -1130,9 +1125,12 @@ unsigned long vm_mmap(struct file *file, unsigned long addr, | |||
1130 | unsigned long ret; | 1125 | unsigned long ret; |
1131 | struct mm_struct *mm = current->mm; | 1126 | struct mm_struct *mm = current->mm; |
1132 | 1127 | ||
1133 | down_write(&mm->mmap_sem); | 1128 | ret = security_mmap_file(file, prot, flag); |
1134 | ret = do_mmap(file, addr, len, prot, flag, offset); | 1129 | if (!ret) { |
1135 | up_write(&mm->mmap_sem); | 1130 | down_write(&mm->mmap_sem); |
1131 | ret = do_mmap(file, addr, len, prot, flag, offset); | ||
1132 | up_write(&mm->mmap_sem); | ||
1133 | } | ||
1136 | return ret; | 1134 | return ret; |
1137 | } | 1135 | } |
1138 | EXPORT_SYMBOL(vm_mmap); | 1136 | EXPORT_SYMBOL(vm_mmap); |
@@ -1168,9 +1166,12 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, | |||
1168 | 1166 | ||
1169 | flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); | 1167 | flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); |
1170 | 1168 | ||
1171 | down_write(¤t->mm->mmap_sem); | 1169 | retval = security_mmap_file(file, prot, flags); |
1172 | retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); | 1170 | if (!retval) { |
1173 | up_write(¤t->mm->mmap_sem); | 1171 | down_write(¤t->mm->mmap_sem); |
1172 | retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); | ||
1173 | up_write(¤t->mm->mmap_sem); | ||
1174 | } | ||
1174 | 1175 | ||
1175 | if (file) | 1176 | if (file) |
1176 | fput(file); | 1177 | fput(file); |
diff --git a/mm/nommu.c b/mm/nommu.c index acfe419785db..8cbfd623b04a 100644 --- a/mm/nommu.c +++ b/mm/nommu.c | |||
@@ -889,7 +889,6 @@ static int validate_mmap_request(struct file *file, | |||
889 | unsigned long *_capabilities) | 889 | unsigned long *_capabilities) |
890 | { | 890 | { |
891 | unsigned long capabilities, rlen; | 891 | unsigned long capabilities, rlen; |
892 | unsigned long reqprot = prot; | ||
893 | int ret; | 892 | int ret; |
894 | 893 | ||
895 | /* do the simple checks first */ | 894 | /* do the simple checks first */ |
@@ -1050,9 +1049,6 @@ static int validate_mmap_request(struct file *file, | |||
1050 | ret = security_mmap_addr(addr); | 1049 | ret = security_mmap_addr(addr); |
1051 | if (ret < 0) | 1050 | if (ret < 0) |
1052 | return ret; | 1051 | return ret; |
1053 | ret = security_mmap_file(file, reqprot, prot, flags); | ||
1054 | if (ret < 0) | ||
1055 | return ret; | ||
1056 | 1052 | ||
1057 | /* looks okay */ | 1053 | /* looks okay */ |
1058 | *_capabilities = capabilities; | 1054 | *_capabilities = capabilities; |
@@ -1492,9 +1488,12 @@ unsigned long vm_mmap(struct file *file, unsigned long addr, | |||
1492 | unsigned long ret; | 1488 | unsigned long ret; |
1493 | struct mm_struct *mm = current->mm; | 1489 | struct mm_struct *mm = current->mm; |
1494 | 1490 | ||
1495 | down_write(&mm->mmap_sem); | 1491 | ret = security_mmap_file(file, prot, flag); |
1496 | ret = do_mmap(file, addr, len, prot, flag, offset); | 1492 | if (!ret) { |
1497 | up_write(&mm->mmap_sem); | 1493 | down_write(&mm->mmap_sem); |
1494 | ret = do_mmap(file, addr, len, prot, flag, offset); | ||
1495 | up_write(&mm->mmap_sem); | ||
1496 | } | ||
1498 | return ret; | 1497 | return ret; |
1499 | } | 1498 | } |
1500 | EXPORT_SYMBOL(vm_mmap); | 1499 | EXPORT_SYMBOL(vm_mmap); |
@@ -1515,9 +1514,12 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, | |||
1515 | 1514 | ||
1516 | flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); | 1515 | flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); |
1517 | 1516 | ||
1518 | down_write(¤t->mm->mmap_sem); | 1517 | ret = security_mmap_file(file, prot, flags); |
1519 | retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); | 1518 | if (!ret) { |
1520 | up_write(¤t->mm->mmap_sem); | 1519 | down_write(¤t->mm->mmap_sem); |
1520 | retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); | ||
1521 | up_write(¤t->mm->mmap_sem); | ||
1522 | } | ||
1521 | 1523 | ||
1522 | if (file) | 1524 | if (file) |
1523 | fput(file); | 1525 | fput(file); |
diff --git a/security/security.c b/security/security.c index d91c66d3956b..3b11b3b72fe2 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -20,6 +20,9 @@ | |||
20 | #include <linux/ima.h> | 20 | #include <linux/ima.h> |
21 | #include <linux/evm.h> | 21 | #include <linux/evm.h> |
22 | #include <linux/fsnotify.h> | 22 | #include <linux/fsnotify.h> |
23 | #include <linux/mman.h> | ||
24 | #include <linux/mount.h> | ||
25 | #include <linux/personality.h> | ||
23 | #include <net/flow.h> | 26 | #include <net/flow.h> |
24 | 27 | ||
25 | #define MAX_LSM_EVM_XATTR 2 | 28 | #define MAX_LSM_EVM_XATTR 2 |
@@ -657,11 +660,35 @@ int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
657 | return security_ops->file_ioctl(file, cmd, arg); | 660 | return security_ops->file_ioctl(file, cmd, arg); |
658 | } | 661 | } |
659 | 662 | ||
660 | int security_mmap_file(struct file *file, unsigned long reqprot, | 663 | int security_mmap_file(struct file *file, unsigned long prot, |
661 | unsigned long prot, unsigned long flags) | 664 | unsigned long flags) |
662 | { | 665 | { |
666 | unsigned long reqprot = prot; | ||
663 | int ret; | 667 | int ret; |
664 | 668 | /* | |
669 | * Does the application expect PROT_READ to imply PROT_EXEC? | ||
670 | * | ||
671 | * (the exception is when the underlying filesystem is noexec | ||
672 | * mounted, in which case we dont add PROT_EXEC.) | ||
673 | */ | ||
674 | if (!(reqprot & PROT_READ)) | ||
675 | goto out; | ||
676 | if (!(current->personality & READ_IMPLIES_EXEC)) | ||
677 | goto out; | ||
678 | if (!file) { | ||
679 | prot |= PROT_EXEC; | ||
680 | } else if (!(file->f_path.mnt->mnt_flags & MNT_NOEXEC)) { | ||
681 | #ifndef CONFIG_MMU | ||
682 | unsigned long caps = 0; | ||
683 | struct address_space *mapping = file->f_mapping; | ||
684 | if (mapping && mapping->backing_dev_info) | ||
685 | caps = mapping->backing_dev_info->capabilities; | ||
686 | if (!(caps & BDI_CAP_EXEC_MAP)) | ||
687 | goto out; | ||
688 | #endif | ||
689 | prot |= PROT_EXEC; | ||
690 | } | ||
691 | out: | ||
665 | ret = security_ops->mmap_file(file, reqprot, prot, flags); | 692 | ret = security_ops->mmap_file(file, reqprot, prot, flags); |
666 | if (ret) | 693 | if (ret) |
667 | return ret; | 694 | return ret; |