diff options
author | Jarkko Sakkinen <jarkko.sakkinen@intel.com> | 2011-09-08 03:12:01 -0400 |
---|---|---|
committer | Casey Schaufler <cschaufler@cschaufler-intel.(none)> | 2011-10-12 17:21:32 -0400 |
commit | 828716c28fe4aa232ea280ea8ed6fb103eefb6ac (patch) | |
tree | f75377cf3e770a9a67feb64fb8bef867735a975b /security | |
parent | 545a7260343bbaf11c7f1a4b8c3d9660bb9266e5 (diff) |
Smack: check permissions from user space (v2)
Adds a new file into SmackFS called 'access'. Wanted
Smack permission is written into /smack/access.
After that result can be read from the opened file.
If access applies result contains 1 and otherwise
0. File access is protected from race conditions
by using simple_transaction_get()/set() API.
Fixes from the previous version:
- Removed smack.h changes, refactoring left-over
from previous version.
- Removed #include <linux/smack.h>, refactoring
left-over from previous version.
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@intel.com>
Signed-off-by: Casey Schaufler <cschaufler@cschaufler-intel.(none)>
Diffstat (limited to 'security')
-rw-r--r-- | security/smack/smackfs.c | 180 |
1 files changed, 117 insertions, 63 deletions
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index f93460156dce..f4c28eeba1b1 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -44,6 +44,7 @@ enum smk_inos { | |||
44 | SMK_ONLYCAP = 9, /* the only "capable" label */ | 44 | SMK_ONLYCAP = 9, /* the only "capable" label */ |
45 | SMK_LOGGING = 10, /* logging */ | 45 | SMK_LOGGING = 10, /* logging */ |
46 | SMK_LOAD_SELF = 11, /* task specific rules */ | 46 | SMK_LOAD_SELF = 11, /* task specific rules */ |
47 | SMK_ACCESSES = 12, /* access policy */ | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | /* | 50 | /* |
@@ -176,71 +177,19 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list, | |||
176 | } | 177 | } |
177 | 178 | ||
178 | /** | 179 | /** |
179 | * smk_write_load_list - write() for any /smack/load | 180 | * smk_parse_rule - parse subject, object and access type |
180 | * @file: file pointer, not actually used | 181 | * @data: string to be parsed whose size is SMK_LOADLEN |
181 | * @buf: where to get the data from | 182 | * @rule: parsed entities are stored in here |
182 | * @count: bytes sent | ||
183 | * @ppos: where to start - must be 0 | ||
184 | * @rule_list: the list of rules to write to | ||
185 | * @rule_lock: lock for the rule list | ||
186 | * | ||
187 | * Get one smack access rule from above. | ||
188 | * The format is exactly: | ||
189 | * char subject[SMK_LABELLEN] | ||
190 | * char object[SMK_LABELLEN] | ||
191 | * char access[SMK_ACCESSLEN] | ||
192 | * | ||
193 | * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes. | ||
194 | */ | 183 | */ |
195 | static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | 184 | static int smk_parse_rule(const char *data, struct smack_rule *rule) |
196 | size_t count, loff_t *ppos, | ||
197 | struct list_head *rule_list, | ||
198 | struct mutex *rule_lock) | ||
199 | { | 185 | { |
200 | struct smack_rule *rule; | ||
201 | char *data; | ||
202 | int rc = -EINVAL; | ||
203 | |||
204 | /* | ||
205 | * No partial writes. | ||
206 | * Enough data must be present. | ||
207 | */ | ||
208 | if (*ppos != 0) | ||
209 | return -EINVAL; | ||
210 | /* | ||
211 | * Minor hack for backward compatibility | ||
212 | */ | ||
213 | if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN) | ||
214 | return -EINVAL; | ||
215 | |||
216 | data = kzalloc(SMK_LOADLEN, GFP_KERNEL); | ||
217 | if (data == NULL) | ||
218 | return -ENOMEM; | ||
219 | |||
220 | if (copy_from_user(data, buf, count) != 0) { | ||
221 | rc = -EFAULT; | ||
222 | goto out; | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * More on the minor hack for backward compatibility | ||
227 | */ | ||
228 | if (count == (SMK_OLOADLEN)) | ||
229 | data[SMK_OLOADLEN] = '-'; | ||
230 | |||
231 | rule = kzalloc(sizeof(*rule), GFP_KERNEL); | ||
232 | if (rule == NULL) { | ||
233 | rc = -ENOMEM; | ||
234 | goto out; | ||
235 | } | ||
236 | |||
237 | rule->smk_subject = smk_import(data, 0); | 186 | rule->smk_subject = smk_import(data, 0); |
238 | if (rule->smk_subject == NULL) | 187 | if (rule->smk_subject == NULL) |
239 | goto out_free_rule; | 188 | return -1; |
240 | 189 | ||
241 | rule->smk_object = smk_import(data + SMK_LABELLEN, 0); | 190 | rule->smk_object = smk_import(data + SMK_LABELLEN, 0); |
242 | if (rule->smk_object == NULL) | 191 | if (rule->smk_object == NULL) |
243 | goto out_free_rule; | 192 | return -1; |
244 | 193 | ||
245 | rule->smk_access = 0; | 194 | rule->smk_access = 0; |
246 | 195 | ||
@@ -252,7 +201,7 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
252 | rule->smk_access |= MAY_READ; | 201 | rule->smk_access |= MAY_READ; |
253 | break; | 202 | break; |
254 | default: | 203 | default: |
255 | goto out_free_rule; | 204 | return -1; |
256 | } | 205 | } |
257 | 206 | ||
258 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { | 207 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { |
@@ -263,7 +212,7 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
263 | rule->smk_access |= MAY_WRITE; | 212 | rule->smk_access |= MAY_WRITE; |
264 | break; | 213 | break; |
265 | default: | 214 | default: |
266 | goto out_free_rule; | 215 | return -1; |
267 | } | 216 | } |
268 | 217 | ||
269 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { | 218 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { |
@@ -274,7 +223,7 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
274 | rule->smk_access |= MAY_EXEC; | 223 | rule->smk_access |= MAY_EXEC; |
275 | break; | 224 | break; |
276 | default: | 225 | default: |
277 | goto out_free_rule; | 226 | return -1; |
278 | } | 227 | } |
279 | 228 | ||
280 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { | 229 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { |
@@ -285,7 +234,7 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
285 | rule->smk_access |= MAY_APPEND; | 234 | rule->smk_access |= MAY_APPEND; |
286 | break; | 235 | break; |
287 | default: | 236 | default: |
288 | goto out_free_rule; | 237 | return -1; |
289 | } | 238 | } |
290 | 239 | ||
291 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) { | 240 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) { |
@@ -296,9 +245,74 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
296 | rule->smk_access |= MAY_TRANSMUTE; | 245 | rule->smk_access |= MAY_TRANSMUTE; |
297 | break; | 246 | break; |
298 | default: | 247 | default: |
299 | goto out_free_rule; | 248 | return -1; |
300 | } | 249 | } |
301 | 250 | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * smk_write_load_list - write() for any /smack/load | ||
256 | * @file: file pointer, not actually used | ||
257 | * @buf: where to get the data from | ||
258 | * @count: bytes sent | ||
259 | * @ppos: where to start - must be 0 | ||
260 | * @rule_list: the list of rules to write to | ||
261 | * @rule_lock: lock for the rule list | ||
262 | * | ||
263 | * Get one smack access rule from above. | ||
264 | * The format is exactly: | ||
265 | * char subject[SMK_LABELLEN] | ||
266 | * char object[SMK_LABELLEN] | ||
267 | * char access[SMK_ACCESSLEN] | ||
268 | * | ||
269 | * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes. | ||
270 | */ | ||
271 | static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | ||
272 | size_t count, loff_t *ppos, | ||
273 | struct list_head *rule_list, | ||
274 | struct mutex *rule_lock) | ||
275 | { | ||
276 | struct smack_rule *rule; | ||
277 | char *data; | ||
278 | int rc = -EINVAL; | ||
279 | |||
280 | /* | ||
281 | * No partial writes. | ||
282 | * Enough data must be present. | ||
283 | */ | ||
284 | if (*ppos != 0) | ||
285 | return -EINVAL; | ||
286 | /* | ||
287 | * Minor hack for backward compatibility | ||
288 | */ | ||
289 | if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN) | ||
290 | return -EINVAL; | ||
291 | |||
292 | data = kzalloc(SMK_LOADLEN, GFP_KERNEL); | ||
293 | if (data == NULL) | ||
294 | return -ENOMEM; | ||
295 | |||
296 | if (copy_from_user(data, buf, count) != 0) { | ||
297 | rc = -EFAULT; | ||
298 | goto out; | ||
299 | } | ||
300 | |||
301 | /* | ||
302 | * More on the minor hack for backward compatibility | ||
303 | */ | ||
304 | if (count == (SMK_OLOADLEN)) | ||
305 | data[SMK_OLOADLEN] = '-'; | ||
306 | |||
307 | rule = kzalloc(sizeof(*rule), GFP_KERNEL); | ||
308 | if (rule == NULL) { | ||
309 | rc = -ENOMEM; | ||
310 | goto out; | ||
311 | } | ||
312 | |||
313 | if (smk_parse_rule(data, rule)) | ||
314 | goto out_free_rule; | ||
315 | |||
302 | rc = count; | 316 | rc = count; |
303 | /* | 317 | /* |
304 | * smk_set_access returns true if there was already a rule | 318 | * smk_set_access returns true if there was already a rule |
@@ -1425,6 +1439,44 @@ static const struct file_operations smk_load_self_ops = { | |||
1425 | .write = smk_write_load_self, | 1439 | .write = smk_write_load_self, |
1426 | .release = seq_release, | 1440 | .release = seq_release, |
1427 | }; | 1441 | }; |
1442 | |||
1443 | /** | ||
1444 | * smk_write_access - handle access check transaction | ||
1445 | * @file: file pointer | ||
1446 | * @buf: data from user space | ||
1447 | * @count: bytes sent | ||
1448 | * @ppos: where to start - must be 0 | ||
1449 | */ | ||
1450 | static ssize_t smk_write_access(struct file *file, const char __user *buf, | ||
1451 | size_t count, loff_t *ppos) | ||
1452 | { | ||
1453 | struct smack_rule rule; | ||
1454 | char *data; | ||
1455 | |||
1456 | if (!capable(CAP_MAC_ADMIN)) | ||
1457 | return -EPERM; | ||
1458 | |||
1459 | data = simple_transaction_get(file, buf, count); | ||
1460 | if (IS_ERR(data)) | ||
1461 | return PTR_ERR(data); | ||
1462 | |||
1463 | if (count < SMK_LOADLEN || smk_parse_rule(data, &rule)) | ||
1464 | return -EINVAL; | ||
1465 | |||
1466 | data[0] = smk_access(rule.smk_subject, rule.smk_object, | ||
1467 | rule.smk_access, NULL) == 0; | ||
1468 | |||
1469 | simple_transaction_set(file, 1); | ||
1470 | return SMK_LOADLEN; | ||
1471 | } | ||
1472 | |||
1473 | static const struct file_operations smk_access_ops = { | ||
1474 | .write = smk_write_access, | ||
1475 | .read = simple_transaction_read, | ||
1476 | .release = simple_transaction_release, | ||
1477 | .llseek = generic_file_llseek, | ||
1478 | }; | ||
1479 | |||
1428 | /** | 1480 | /** |
1429 | * smk_fill_super - fill the /smackfs superblock | 1481 | * smk_fill_super - fill the /smackfs superblock |
1430 | * @sb: the empty superblock | 1482 | * @sb: the empty superblock |
@@ -1459,6 +1511,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
1459 | "logging", &smk_logging_ops, S_IRUGO|S_IWUSR}, | 1511 | "logging", &smk_logging_ops, S_IRUGO|S_IWUSR}, |
1460 | [SMK_LOAD_SELF] = { | 1512 | [SMK_LOAD_SELF] = { |
1461 | "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO}, | 1513 | "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO}, |
1514 | [SMK_ACCESSES] = { | ||
1515 | "access", &smk_access_ops, S_IRUGO|S_IWUSR}, | ||
1462 | /* last one */ | 1516 | /* last one */ |
1463 | {""} | 1517 | {""} |
1464 | }; | 1518 | }; |