diff options
-rw-r--r-- | security/safesetid/lsm.h | 1 | ||||
-rw-r--r-- | security/safesetid/securityfs.c | 35 |
2 files changed, 32 insertions, 4 deletions
diff --git a/security/safesetid/lsm.h b/security/safesetid/lsm.h index 4a34f558d964..db6d16e6bbc3 100644 --- a/security/safesetid/lsm.h +++ b/security/safesetid/lsm.h | |||
@@ -41,6 +41,7 @@ struct setuid_rule { | |||
41 | 41 | ||
42 | struct setuid_ruleset { | 42 | struct setuid_ruleset { |
43 | DECLARE_HASHTABLE(rules, SETID_HASH_BITS); | 43 | DECLARE_HASHTABLE(rules, SETID_HASH_BITS); |
44 | char *policy_str; | ||
44 | struct rcu_head rcu; | 45 | struct rcu_head rcu; |
45 | }; | 46 | }; |
46 | 47 | ||
diff --git a/security/safesetid/securityfs.c b/security/safesetid/securityfs.c index 250d59e046c1..997b403c6255 100644 --- a/security/safesetid/securityfs.c +++ b/security/safesetid/securityfs.c | |||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | #include "lsm.h" | 20 | #include "lsm.h" |
21 | 21 | ||
22 | static DEFINE_SPINLOCK(policy_update_lock); | 22 | static DEFINE_MUTEX(policy_update_lock); |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * In the case the input buffer contains one or more invalid UIDs, the kuid_t | 25 | * In the case the input buffer contains one or more invalid UIDs, the kuid_t |
@@ -67,6 +67,7 @@ static void __release_ruleset(struct rcu_head *rcu) | |||
67 | 67 | ||
68 | hash_for_each_safe(pol->rules, bucket, tmp, rule, next) | 68 | hash_for_each_safe(pol->rules, bucket, tmp, rule, next) |
69 | kfree(rule); | 69 | kfree(rule); |
70 | kfree(pol->policy_str); | ||
70 | kfree(pol); | 71 | kfree(pol); |
71 | } | 72 | } |
72 | 73 | ||
@@ -85,6 +86,7 @@ static ssize_t handle_policy_update(struct file *file, | |||
85 | pol = kmalloc(sizeof(struct setuid_ruleset), GFP_KERNEL); | 86 | pol = kmalloc(sizeof(struct setuid_ruleset), GFP_KERNEL); |
86 | if (!pol) | 87 | if (!pol) |
87 | return -ENOMEM; | 88 | return -ENOMEM; |
89 | pol->policy_str = NULL; | ||
88 | hash_init(pol->rules); | 90 | hash_init(pol->rules); |
89 | 91 | ||
90 | p = buf = memdup_user_nul(ubuf, len); | 92 | p = buf = memdup_user_nul(ubuf, len); |
@@ -92,6 +94,11 @@ static ssize_t handle_policy_update(struct file *file, | |||
92 | err = PTR_ERR(buf); | 94 | err = PTR_ERR(buf); |
93 | goto out_free_pol; | 95 | goto out_free_pol; |
94 | } | 96 | } |
97 | pol->policy_str = kstrdup(buf, GFP_KERNEL); | ||
98 | if (pol->policy_str == NULL) { | ||
99 | err = -ENOMEM; | ||
100 | goto out_free_buf; | ||
101 | } | ||
95 | 102 | ||
96 | /* policy lines, including the last one, end with \n */ | 103 | /* policy lines, including the last one, end with \n */ |
97 | while (*p != '\0') { | 104 | while (*p != '\0') { |
@@ -135,10 +142,10 @@ out_free_rule: | |||
135 | * What we really want here is an xchg() wrapper for RCU, but since that | 142 | * What we really want here is an xchg() wrapper for RCU, but since that |
136 | * doesn't currently exist, just use a spinlock for now. | 143 | * doesn't currently exist, just use a spinlock for now. |
137 | */ | 144 | */ |
138 | spin_lock(&policy_update_lock); | 145 | mutex_lock(&policy_update_lock); |
139 | rcu_swap_protected(safesetid_setuid_rules, pol, | 146 | rcu_swap_protected(safesetid_setuid_rules, pol, |
140 | lockdep_is_held(&policy_update_lock)); | 147 | lockdep_is_held(&policy_update_lock)); |
141 | spin_unlock(&policy_update_lock); | 148 | mutex_unlock(&policy_update_lock); |
142 | err = len; | 149 | err = len; |
143 | 150 | ||
144 | out_free_buf: | 151 | out_free_buf: |
@@ -162,7 +169,27 @@ static ssize_t safesetid_file_write(struct file *file, | |||
162 | return handle_policy_update(file, buf, len); | 169 | return handle_policy_update(file, buf, len); |
163 | } | 170 | } |
164 | 171 | ||
172 | static ssize_t safesetid_file_read(struct file *file, char __user *buf, | ||
173 | size_t len, loff_t *ppos) | ||
174 | { | ||
175 | ssize_t res = 0; | ||
176 | struct setuid_ruleset *pol; | ||
177 | const char *kbuf; | ||
178 | |||
179 | mutex_lock(&policy_update_lock); | ||
180 | pol = rcu_dereference_protected(safesetid_setuid_rules, | ||
181 | lockdep_is_held(&policy_update_lock)); | ||
182 | if (pol) { | ||
183 | kbuf = pol->policy_str; | ||
184 | res = simple_read_from_buffer(buf, len, ppos, | ||
185 | kbuf, strlen(kbuf)); | ||
186 | } | ||
187 | mutex_unlock(&policy_update_lock); | ||
188 | return res; | ||
189 | } | ||
190 | |||
165 | static const struct file_operations safesetid_file_fops = { | 191 | static const struct file_operations safesetid_file_fops = { |
192 | .read = safesetid_file_read, | ||
166 | .write = safesetid_file_write, | 193 | .write = safesetid_file_write, |
167 | }; | 194 | }; |
168 | 195 | ||
@@ -181,7 +208,7 @@ static int __init safesetid_init_securityfs(void) | |||
181 | goto error; | 208 | goto error; |
182 | } | 209 | } |
183 | 210 | ||
184 | policy_file = securityfs_create_file("whitelist_policy", 0200, | 211 | policy_file = securityfs_create_file("whitelist_policy", 0600, |
185 | policy_dir, NULL, &safesetid_file_fops); | 212 | policy_dir, NULL, &safesetid_file_fops); |
186 | if (IS_ERR(policy_file)) { | 213 | if (IS_ERR(policy_file)) { |
187 | ret = PTR_ERR(policy_file); | 214 | ret = PTR_ERR(policy_file); |