diff options
author | Stephen Smalley <sds@tycho.nsa.gov> | 2007-11-26 11:12:53 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2007-12-05 08:24:09 -0500 |
commit | d313f948309ab22797316e789a7ff8fa358176b6 (patch) | |
tree | 7a6d4a54ea7448ce53cf23349eb8a64d7fd93151 | |
parent | 0955dc03aedfb6a5565445b3f2176255b784cc6a (diff) |
SELinux: detect dead booleans
Instead of using f_op to detect dead booleans, check the inode index
against the number of booleans and check the dentry name against the
boolean name for that index on reads and writes. This prevents
incorrect use of a boolean file opened prior to a policy reload while
allowing valid use of it as long as it still corresponds to the same
boolean in the policy.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r-- | security/selinux/selinuxfs.c | 43 |
1 files changed, 30 insertions, 13 deletions
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index ac6fe99bd32c..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 */ |
66 | static struct dentry *bool_dir = NULL; | 66 | static struct dentry *bool_dir = NULL; |
67 | static int bool_num = 0; | 67 | static int bool_num = 0; |
68 | static char **bool_pending_names; | ||
68 | static int *bool_pending_values = NULL; | 69 | static int *bool_pending_values = NULL; |
69 | 70 | ||
70 | /* global data for classes */ | 71 | /* global data for classes */ |
@@ -832,11 +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])) { |
843 | ret = -EINVAL; | ||
844 | goto out; | ||
845 | } | ||
840 | 846 | ||
841 | if (count > PAGE_SIZE) { | 847 | if (count > PAGE_SIZE) { |
842 | ret = -EINVAL; | 848 | ret = -EINVAL; |
@@ -847,15 +853,13 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, | |||
847 | goto out; | 853 | goto out; |
848 | } | 854 | } |
849 | 855 | ||
850 | inode = filep->f_path.dentry->d_inode; | 856 | cur_enforcing = security_get_bool_value(index); |
851 | cur_enforcing = security_get_bool_value(inode->i_ino&SEL_INO_MASK); | ||
852 | if (cur_enforcing < 0) { | 857 | if (cur_enforcing < 0) { |
853 | ret = cur_enforcing; | 858 | ret = cur_enforcing; |
854 | goto out; | 859 | goto out; |
855 | } | 860 | } |
856 | |||
857 | length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, | 861 | length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, |
858 | bool_pending_values[inode->i_ino&SEL_INO_MASK]); | 862 | bool_pending_values[index]); |
859 | ret = simple_read_from_buffer(buf, count, ppos, page, length); | 863 | ret = simple_read_from_buffer(buf, count, ppos, page, length); |
860 | out: | 864 | out: |
861 | mutex_unlock(&sel_mutex); | 865 | mutex_unlock(&sel_mutex); |
@@ -868,9 +872,11 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
868 | size_t count, loff_t *ppos) | 872 | size_t count, loff_t *ppos) |
869 | { | 873 | { |
870 | char *page = NULL; | 874 | char *page = NULL; |
871 | ssize_t length = -EFAULT; | 875 | ssize_t length; |
872 | int new_value; | 876 | int new_value; |
873 | 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; | ||
874 | 880 | ||
875 | mutex_lock(&sel_mutex); | 881 | mutex_lock(&sel_mutex); |
876 | 882 | ||
@@ -878,12 +884,19 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
878 | if (length) | 884 | if (length) |
879 | goto out; | 885 | goto out; |
880 | 886 | ||
887 | if (index >= bool_num || strcmp(name, bool_pending_names[index])) { | ||
888 | length = -EINVAL; | ||
889 | goto out; | ||
890 | } | ||
891 | |||
881 | if (count >= PAGE_SIZE) { | 892 | if (count >= PAGE_SIZE) { |
882 | length = -ENOMEM; | 893 | length = -ENOMEM; |
883 | goto out; | 894 | goto out; |
884 | } | 895 | } |
896 | |||
885 | if (*ppos != 0) { | 897 | if (*ppos != 0) { |
886 | /* No partial writes. */ | 898 | /* No partial writes. */ |
899 | length = -EINVAL; | ||
887 | goto out; | 900 | goto out; |
888 | } | 901 | } |
889 | page = (char*)get_zeroed_page(GFP_KERNEL); | 902 | page = (char*)get_zeroed_page(GFP_KERNEL); |
@@ -892,6 +905,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
892 | goto out; | 905 | goto out; |
893 | } | 906 | } |
894 | 907 | ||
908 | length = -EFAULT; | ||
895 | if (copy_from_user(page, buf, count)) | 909 | if (copy_from_user(page, buf, count)) |
896 | goto out; | 910 | goto out; |
897 | 911 | ||
@@ -902,8 +916,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
902 | if (new_value) | 916 | if (new_value) |
903 | new_value = 1; | 917 | new_value = 1; |
904 | 918 | ||
905 | inode = filep->f_path.dentry->d_inode; | 919 | bool_pending_values[index] = new_value; |
906 | bool_pending_values[inode->i_ino&SEL_INO_MASK] = new_value; | ||
907 | length = count; | 920 | length = count; |
908 | 921 | ||
909 | out: | 922 | out: |
@@ -923,7 +936,7 @@ static ssize_t sel_commit_bools_write(struct file *filep, | |||
923 | size_t count, loff_t *ppos) | 936 | size_t count, loff_t *ppos) |
924 | { | 937 | { |
925 | char *page = NULL; | 938 | char *page = NULL; |
926 | ssize_t length = -EFAULT; | 939 | ssize_t length; |
927 | int new_value; | 940 | int new_value; |
928 | 941 | ||
929 | mutex_lock(&sel_mutex); | 942 | mutex_lock(&sel_mutex); |
@@ -946,6 +959,7 @@ static ssize_t sel_commit_bools_write(struct file *filep, | |||
946 | goto out; | 959 | goto out; |
947 | } | 960 | } |
948 | 961 | ||
962 | length = -EFAULT; | ||
949 | if (copy_from_user(page, buf, count)) | 963 | if (copy_from_user(page, buf, count)) |
950 | goto out; | 964 | goto out; |
951 | 965 | ||
@@ -1010,7 +1024,9 @@ static int sel_make_bools(void) | |||
1010 | u32 sid; | 1024 | u32 sid; |
1011 | 1025 | ||
1012 | /* remove any existing files */ | 1026 | /* remove any existing files */ |
1027 | kfree(bool_pending_names); | ||
1013 | kfree(bool_pending_values); | 1028 | kfree(bool_pending_values); |
1029 | bool_pending_names = NULL; | ||
1014 | bool_pending_values = NULL; | 1030 | bool_pending_values = NULL; |
1015 | 1031 | ||
1016 | sel_remove_entries(dir); | 1032 | sel_remove_entries(dir); |
@@ -1052,16 +1068,17 @@ static int sel_make_bools(void) | |||
1052 | d_add(dentry, inode); | 1068 | d_add(dentry, inode); |
1053 | } | 1069 | } |
1054 | bool_num = num; | 1070 | bool_num = num; |
1071 | bool_pending_names = names; | ||
1055 | bool_pending_values = values; | 1072 | bool_pending_values = values; |
1056 | out: | 1073 | out: |
1057 | free_page((unsigned long)page); | 1074 | free_page((unsigned long)page); |
1075 | return ret; | ||
1076 | err: | ||
1058 | if (names) { | 1077 | if (names) { |
1059 | for (i = 0; i < num; i++) | 1078 | for (i = 0; i < num; i++) |
1060 | kfree(names[i]); | 1079 | kfree(names[i]); |
1061 | kfree(names); | 1080 | kfree(names); |
1062 | } | 1081 | } |
1063 | return ret; | ||
1064 | err: | ||
1065 | kfree(values); | 1082 | kfree(values); |
1066 | sel_remove_entries(dir); | 1083 | sel_remove_entries(dir); |
1067 | ret = -ENOMEM; | 1084 | ret = -ENOMEM; |