aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-12-05 12:26:52 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-12-05 12:26:52 -0500
commitad658cec232771b11e95bb5f0d639d48f898a1f2 (patch)
tree7ef4ed87cbba8d8395f67c21af5c167d5de0293a
parent2a1292b36ba106b9b7f030d3fa130f5f634fd8f0 (diff)
parent5a211a5deabcafdc764817d5b4510c767d317ddc (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6: VM/Security: add security hook to do_brk Security: round mmap hint address above mmap_min_addr security: protect from stack expantion into low vm addresses Security: allow capable check to permit mmap or low vm space SELinux: detect dead booleans SELinux: do not clear f_op when removing entries
-rw-r--r--include/linux/mm.h16
-rw-r--r--mm/mmap.c11
-rw-r--r--mm/nommu.c3
-rw-r--r--security/dummy.c2
-rw-r--r--security/selinux/selinuxfs.c65
5 files changed, 57 insertions, 40 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 520238cbae5d..1b7b95c67aca 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -12,6 +12,7 @@
12#include <linux/prio_tree.h> 12#include <linux/prio_tree.h>
13#include <linux/debug_locks.h> 13#include <linux/debug_locks.h>
14#include <linux/mm_types.h> 14#include <linux/mm_types.h>
15#include <linux/security.h>
15 16
16struct mempolicy; 17struct mempolicy;
17struct anon_vma; 18struct anon_vma;
@@ -513,6 +514,21 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
513} 514}
514 515
515/* 516/*
517 * If a hint addr is less than mmap_min_addr change hint to be as
518 * low as possible but still greater than mmap_min_addr
519 */
520static inline unsigned long round_hint_to_min(unsigned long hint)
521{
522#ifdef CONFIG_SECURITY
523 hint &= PAGE_MASK;
524 if (((void *)hint != NULL) &&
525 (hint < mmap_min_addr))
526 return PAGE_ALIGN(mmap_min_addr);
527#endif
528 return hint;
529}
530
531/*
516 * Some inline functions in vmstat.h depend on page_zone() 532 * Some inline functions in vmstat.h depend on page_zone()
517 */ 533 */
518#include <linux/vmstat.h> 534#include <linux/vmstat.h>
diff --git a/mm/mmap.c b/mm/mmap.c
index acfc13f23ca0..15678aa6ec73 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -912,6 +912,9 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
912 if (!len) 912 if (!len)
913 return -EINVAL; 913 return -EINVAL;
914 914
915 if (!(flags & MAP_FIXED))
916 addr = round_hint_to_min(addr);
917
915 error = arch_mmap_check(addr, len, flags); 918 error = arch_mmap_check(addr, len, flags);
916 if (error) 919 if (error)
917 return error; 920 return error;
@@ -1615,6 +1618,12 @@ static inline int expand_downwards(struct vm_area_struct *vma,
1615 */ 1618 */
1616 if (unlikely(anon_vma_prepare(vma))) 1619 if (unlikely(anon_vma_prepare(vma)))
1617 return -ENOMEM; 1620 return -ENOMEM;
1621
1622 address &= PAGE_MASK;
1623 error = security_file_mmap(0, 0, 0, 0, address, 1);
1624 if (error)
1625 return error;
1626
1618 anon_vma_lock(vma); 1627 anon_vma_lock(vma);
1619 1628
1620 /* 1629 /*
@@ -1622,8 +1631,6 @@ static inline int expand_downwards(struct vm_area_struct *vma,
1622 * is required to hold the mmap_sem in read mode. We need the 1631 * is required to hold the mmap_sem in read mode. We need the
1623 * anon_vma lock to serialize against concurrent expand_stacks. 1632 * anon_vma lock to serialize against concurrent expand_stacks.
1624 */ 1633 */
1625 address &= PAGE_MASK;
1626 error = 0;
1627 1634
1628 /* Somebody else might have raced and expanded it already */ 1635 /* Somebody else might have raced and expanded it already */
1629 if (address < vma->vm_start) { 1636 if (address < vma->vm_start) {
diff --git a/mm/nommu.c b/mm/nommu.c
index 35622c590925..b989cb928a7c 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -829,6 +829,9 @@ unsigned long do_mmap_pgoff(struct file *file,
829 void *result; 829 void *result;
830 int ret; 830 int ret;
831 831
832 if (!(flags & MAP_FIXED))
833 addr = round_hint_to_min(addr);
834
832 /* decide whether we should attempt the mapping, and if so what sort of 835 /* decide whether we should attempt the mapping, and if so what sort of
833 * mapping */ 836 * mapping */
834 ret = validate_mmap_request(file, addr, len, prot, flags, pgoff, 837 ret = validate_mmap_request(file, addr, len, prot, flags, pgoff,
diff --git a/security/dummy.c b/security/dummy.c
index 6d895ade73de..3ccfbbe973b6 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -426,7 +426,7 @@ static int dummy_file_mmap (struct file *file, unsigned long reqprot,
426 unsigned long addr, 426 unsigned long addr,
427 unsigned long addr_only) 427 unsigned long addr_only)
428{ 428{
429 if (addr < mmap_min_addr) 429 if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO))
430 return -EACCES; 430 return -EACCES;
431 return 0; 431 return 0;
432} 432}
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index f5f3e6da5da7..2fa483f26113 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -65,6 +65,7 @@ static DEFINE_MUTEX(sel_mutex);
65/* global data for booleans */ 65/* global data for booleans */
66static struct dentry *bool_dir = NULL; 66static struct dentry *bool_dir = NULL;
67static int bool_num = 0; 67static int bool_num = 0;
68static char **bool_pending_names;
68static int *bool_pending_values = NULL; 69static int *bool_pending_values = NULL;
69 70
70/* global data for classes */ 71/* global data for classes */
@@ -832,15 +833,16 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
832 ssize_t length; 833 ssize_t length;
833 ssize_t ret; 834 ssize_t ret;
834 int cur_enforcing; 835 int cur_enforcing;
835 struct inode *inode; 836 struct inode *inode = filep->f_path.dentry->d_inode;
837 unsigned index = inode->i_ino & SEL_INO_MASK;
838 const char *name = filep->f_path.dentry->d_name.name;
836 839
837 mutex_lock(&sel_mutex); 840 mutex_lock(&sel_mutex);
838 841
839 ret = -EFAULT; 842 if (index >= bool_num || strcmp(name, bool_pending_names[index])) {
840 843 ret = -EINVAL;
841 /* check to see if this file has been deleted */
842 if (!filep->f_op)
843 goto out; 844 goto out;
845 }
844 846
845 if (count > PAGE_SIZE) { 847 if (count > PAGE_SIZE) {
846 ret = -EINVAL; 848 ret = -EINVAL;
@@ -851,15 +853,13 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
851 goto out; 853 goto out;
852 } 854 }
853 855
854 inode = filep->f_path.dentry->d_inode; 856 cur_enforcing = security_get_bool_value(index);
855 cur_enforcing = security_get_bool_value(inode->i_ino&SEL_INO_MASK);
856 if (cur_enforcing < 0) { 857 if (cur_enforcing < 0) {
857 ret = cur_enforcing; 858 ret = cur_enforcing;
858 goto out; 859 goto out;
859 } 860 }
860
861 length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, 861 length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
862 bool_pending_values[inode->i_ino&SEL_INO_MASK]); 862 bool_pending_values[index]);
863 ret = simple_read_from_buffer(buf, count, ppos, page, length); 863 ret = simple_read_from_buffer(buf, count, ppos, page, length);
864out: 864out:
865 mutex_unlock(&sel_mutex); 865 mutex_unlock(&sel_mutex);
@@ -872,9 +872,11 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
872 size_t count, loff_t *ppos) 872 size_t count, loff_t *ppos)
873{ 873{
874 char *page = NULL; 874 char *page = NULL;
875 ssize_t length = -EFAULT; 875 ssize_t length;
876 int new_value; 876 int new_value;
877 struct inode *inode; 877 struct inode *inode = filep->f_path.dentry->d_inode;
878 unsigned index = inode->i_ino & SEL_INO_MASK;
879 const char *name = filep->f_path.dentry->d_name.name;
878 880
879 mutex_lock(&sel_mutex); 881 mutex_lock(&sel_mutex);
880 882
@@ -882,16 +884,19 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
882 if (length) 884 if (length)
883 goto out; 885 goto out;
884 886
885 /* check to see if this file has been deleted */ 887 if (index >= bool_num || strcmp(name, bool_pending_names[index])) {
886 if (!filep->f_op) 888 length = -EINVAL;
887 goto out; 889 goto out;
890 }
888 891
889 if (count >= PAGE_SIZE) { 892 if (count >= PAGE_SIZE) {
890 length = -ENOMEM; 893 length = -ENOMEM;
891 goto out; 894 goto out;
892 } 895 }
896
893 if (*ppos != 0) { 897 if (*ppos != 0) {
894 /* No partial writes. */ 898 /* No partial writes. */
899 length = -EINVAL;
895 goto out; 900 goto out;
896 } 901 }
897 page = (char*)get_zeroed_page(GFP_KERNEL); 902 page = (char*)get_zeroed_page(GFP_KERNEL);
@@ -900,6 +905,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
900 goto out; 905 goto out;
901 } 906 }
902 907
908 length = -EFAULT;
903 if (copy_from_user(page, buf, count)) 909 if (copy_from_user(page, buf, count))
904 goto out; 910 goto out;
905 911
@@ -910,8 +916,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
910 if (new_value) 916 if (new_value)
911 new_value = 1; 917 new_value = 1;
912 918
913 inode = filep->f_path.dentry->d_inode; 919 bool_pending_values[index] = new_value;
914 bool_pending_values[inode->i_ino&SEL_INO_MASK] = new_value;
915 length = count; 920 length = count;
916 921
917out: 922out:
@@ -931,7 +936,7 @@ static ssize_t sel_commit_bools_write(struct file *filep,
931 size_t count, loff_t *ppos) 936 size_t count, loff_t *ppos)
932{ 937{
933 char *page = NULL; 938 char *page = NULL;
934 ssize_t length = -EFAULT; 939 ssize_t length;
935 int new_value; 940 int new_value;
936 941
937 mutex_lock(&sel_mutex); 942 mutex_lock(&sel_mutex);
@@ -940,10 +945,6 @@ static ssize_t sel_commit_bools_write(struct file *filep,
940 if (length) 945 if (length)
941 goto out; 946 goto out;
942 947
943 /* check to see if this file has been deleted */
944 if (!filep->f_op)
945 goto out;
946
947 if (count >= PAGE_SIZE) { 948 if (count >= PAGE_SIZE) {
948 length = -ENOMEM; 949 length = -ENOMEM;
949 goto out; 950 goto out;
@@ -958,6 +959,7 @@ static ssize_t sel_commit_bools_write(struct file *filep,
958 goto out; 959 goto out;
959 } 960 }
960 961
962 length = -EFAULT;
961 if (copy_from_user(page, buf, count)) 963 if (copy_from_user(page, buf, count))
962 goto out; 964 goto out;
963 965
@@ -982,11 +984,9 @@ static const struct file_operations sel_commit_bools_ops = {
982 .write = sel_commit_bools_write, 984 .write = sel_commit_bools_write,
983}; 985};
984 986
985/* partial revoke() from fs/proc/generic.c proc_kill_inodes */
986static void sel_remove_entries(struct dentry *de) 987static void sel_remove_entries(struct dentry *de)
987{ 988{
988 struct list_head *p, *node; 989 struct list_head *node;
989 struct super_block *sb = de->d_sb;
990 990
991 spin_lock(&dcache_lock); 991 spin_lock(&dcache_lock);
992 node = de->d_subdirs.next; 992 node = de->d_subdirs.next;
@@ -1006,18 +1006,6 @@ static void sel_remove_entries(struct dentry *de)
1006 } 1006 }
1007 1007
1008 spin_unlock(&dcache_lock); 1008 spin_unlock(&dcache_lock);
1009
1010 file_list_lock();
1011 list_for_each(p, &sb->s_files) {
1012 struct file * filp = list_entry(p, struct file, f_u.fu_list);
1013 struct dentry * dentry = filp->f_path.dentry;
1014
1015 if (dentry->d_parent != de) {
1016 continue;
1017 }
1018 filp->f_op = NULL;
1019 }
1020 file_list_unlock();
1021} 1009}
1022 1010
1023#define BOOL_DIR_NAME "booleans" 1011#define BOOL_DIR_NAME "booleans"
@@ -1036,7 +1024,9 @@ static int sel_make_bools(void)
1036 u32 sid; 1024 u32 sid;
1037 1025
1038 /* remove any existing files */ 1026 /* remove any existing files */
1027 kfree(bool_pending_names);
1039 kfree(bool_pending_values); 1028 kfree(bool_pending_values);
1029 bool_pending_names = NULL;
1040 bool_pending_values = NULL; 1030 bool_pending_values = NULL;
1041 1031
1042 sel_remove_entries(dir); 1032 sel_remove_entries(dir);
@@ -1078,16 +1068,17 @@ static int sel_make_bools(void)
1078 d_add(dentry, inode); 1068 d_add(dentry, inode);
1079 } 1069 }
1080 bool_num = num; 1070 bool_num = num;
1071 bool_pending_names = names;
1081 bool_pending_values = values; 1072 bool_pending_values = values;
1082out: 1073out:
1083 free_page((unsigned long)page); 1074 free_page((unsigned long)page);
1075 return ret;
1076err:
1084 if (names) { 1077 if (names) {
1085 for (i = 0; i < num; i++) 1078 for (i = 0; i < num; i++)
1086 kfree(names[i]); 1079 kfree(names[i]);
1087 kfree(names); 1080 kfree(names);
1088 } 1081 }
1089 return ret;
1090err:
1091 kfree(values); 1082 kfree(values);
1092 sel_remove_entries(dir); 1083 sel_remove_entries(dir);
1093 ret = -ENOMEM; 1084 ret = -ENOMEM;