diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/smack/smackfs.c | 167 |
1 files changed, 82 insertions, 85 deletions
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index a07e93f00a0f..80f4b4a45725 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -368,56 +368,43 @@ static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule, | |||
368 | * @data: string to be parsed, null terminated | 368 | * @data: string to be parsed, null terminated |
369 | * @rule: Will be filled with Smack parsed rule | 369 | * @rule: Will be filled with Smack parsed rule |
370 | * @import: if non-zero, import labels | 370 | * @import: if non-zero, import labels |
371 | * @change: if non-zero, data is from /smack/change-rule | 371 | * @tokens: numer of substrings expected in data |
372 | * | 372 | * |
373 | * Returns 0 on success, -1 on failure | 373 | * Returns number of processed bytes on success, -1 on failure. |
374 | */ | 374 | */ |
375 | static int smk_parse_long_rule(const char *data, struct smack_parsed_rule *rule, | 375 | static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule, |
376 | int import, int change) | 376 | int import, int tokens) |
377 | { | 377 | { |
378 | char *subject; | 378 | ssize_t cnt = 0; |
379 | char *object; | 379 | char *tok[4]; |
380 | char *access1; | 380 | int i; |
381 | char *access2; | ||
382 | int datalen; | ||
383 | int rc = -1; | ||
384 | 381 | ||
385 | /* This is inefficient */ | 382 | /* |
386 | datalen = strlen(data); | 383 | * Parsing the rule in-place, filling all white-spaces with '\0' |
384 | */ | ||
385 | for (i = 0; i < tokens; ++i) { | ||
386 | while (isspace(data[cnt])) | ||
387 | data[cnt++] = '\0'; | ||
387 | 388 | ||
388 | /* Our first element can be 64 + \0 with no spaces */ | 389 | if (data[cnt] == '\0') |
389 | subject = kzalloc(datalen + 1, GFP_KERNEL); | 390 | /* Unexpected end of data */ |
390 | if (subject == NULL) | 391 | return -1; |
391 | return -1; | 392 | |
392 | object = kzalloc(datalen, GFP_KERNEL); | 393 | tok[i] = data + cnt; |
393 | if (object == NULL) | 394 | |
394 | goto free_out_s; | 395 | while (data[cnt] && !isspace(data[cnt])) |
395 | access1 = kzalloc(datalen, GFP_KERNEL); | 396 | ++cnt; |
396 | if (access1 == NULL) | ||
397 | goto free_out_o; | ||
398 | access2 = kzalloc(datalen, GFP_KERNEL); | ||
399 | if (access2 == NULL) | ||
400 | goto free_out_a; | ||
401 | |||
402 | if (change) { | ||
403 | if (sscanf(data, "%s %s %s %s", | ||
404 | subject, object, access1, access2) == 4) | ||
405 | rc = smk_fill_rule(subject, object, access1, access2, | ||
406 | rule, import, 0); | ||
407 | } else { | ||
408 | if (sscanf(data, "%s %s %s", subject, object, access1) == 3) | ||
409 | rc = smk_fill_rule(subject, object, access1, NULL, | ||
410 | rule, import, 0); | ||
411 | } | 397 | } |
398 | while (isspace(data[cnt])) | ||
399 | data[cnt++] = '\0'; | ||
412 | 400 | ||
413 | kfree(access2); | 401 | while (i < 4) |
414 | free_out_a: | 402 | tok[i++] = NULL; |
415 | kfree(access1); | 403 | |
416 | free_out_o: | 404 | if (smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0)) |
417 | kfree(object); | 405 | return -1; |
418 | free_out_s: | 406 | |
419 | kfree(subject); | 407 | return cnt; |
420 | return rc; | ||
421 | } | 408 | } |
422 | 409 | ||
423 | #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ | 410 | #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ |
@@ -449,9 +436,10 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, | |||
449 | { | 436 | { |
450 | struct smack_parsed_rule rule; | 437 | struct smack_parsed_rule rule; |
451 | char *data; | 438 | char *data; |
452 | int datalen; | 439 | int rc; |
453 | int rc = -EINVAL; | 440 | int trunc = 0; |
454 | int load = 0; | 441 | int tokens; |
442 | ssize_t cnt = 0; | ||
455 | 443 | ||
456 | /* | 444 | /* |
457 | * No partial writes. | 445 | * No partial writes. |
@@ -466,11 +454,14 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, | |||
466 | */ | 454 | */ |
467 | if (count != SMK_OLOADLEN && count != SMK_LOADLEN) | 455 | if (count != SMK_OLOADLEN && count != SMK_LOADLEN) |
468 | return -EINVAL; | 456 | return -EINVAL; |
469 | datalen = SMK_LOADLEN; | 457 | } else { |
470 | } else | 458 | if (count >= PAGE_SIZE) { |
471 | datalen = count + 1; | 459 | count = PAGE_SIZE - 1; |
460 | trunc = 1; | ||
461 | } | ||
462 | } | ||
472 | 463 | ||
473 | data = kzalloc(datalen, GFP_KERNEL); | 464 | data = kmalloc(count + 1, GFP_KERNEL); |
474 | if (data == NULL) | 465 | if (data == NULL) |
475 | return -ENOMEM; | 466 | return -ENOMEM; |
476 | 467 | ||
@@ -479,36 +470,49 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, | |||
479 | goto out; | 470 | goto out; |
480 | } | 471 | } |
481 | 472 | ||
482 | if (format == SMK_LONG_FMT) { | 473 | /* |
483 | /* | 474 | * In case of parsing only part of user buf, |
484 | * Be sure the data string is terminated. | 475 | * avoid having partial rule at the data buffer |
485 | */ | 476 | */ |
486 | data[count] = '\0'; | 477 | if (trunc) { |
487 | if (smk_parse_long_rule(data, &rule, 1, 0)) | 478 | while (count > 0 && (data[count - 1] != '\n')) |
488 | goto out; | 479 | --count; |
489 | } else if (format == SMK_CHANGE_FMT) { | 480 | if (count == 0) { |
490 | data[count] = '\0'; | 481 | rc = -EINVAL; |
491 | if (smk_parse_long_rule(data, &rule, 1, 1)) | ||
492 | goto out; | ||
493 | } else { | ||
494 | /* | ||
495 | * More on the minor hack for backward compatibility | ||
496 | */ | ||
497 | if (count == (SMK_OLOADLEN)) | ||
498 | data[SMK_OLOADLEN] = '-'; | ||
499 | if (smk_parse_rule(data, &rule, 1)) | ||
500 | goto out; | 482 | goto out; |
483 | } | ||
501 | } | 484 | } |
502 | 485 | ||
503 | if (rule_list == NULL) { | 486 | data[count] = '\0'; |
504 | load = 1; | 487 | tokens = (format == SMK_CHANGE_FMT ? 4 : 3); |
505 | rule_list = &rule.smk_subject->smk_rules; | 488 | while (cnt < count) { |
506 | rule_lock = &rule.smk_subject->smk_rules_lock; | 489 | if (format == SMK_FIXED24_FMT) { |
490 | rc = smk_parse_rule(data, &rule, 1); | ||
491 | if (rc != 0) { | ||
492 | rc = -EINVAL; | ||
493 | goto out; | ||
494 | } | ||
495 | cnt = count; | ||
496 | } else { | ||
497 | rc = smk_parse_long_rule(data + cnt, &rule, 1, tokens); | ||
498 | if (rc <= 0) { | ||
499 | rc = -EINVAL; | ||
500 | goto out; | ||
501 | } | ||
502 | cnt += rc; | ||
503 | } | ||
504 | |||
505 | if (rule_list == NULL) | ||
506 | rc = smk_set_access(&rule, &rule.smk_subject->smk_rules, | ||
507 | &rule.smk_subject->smk_rules_lock, 1); | ||
508 | else | ||
509 | rc = smk_set_access(&rule, rule_list, rule_lock, 0); | ||
510 | |||
511 | if (rc) | ||
512 | goto out; | ||
507 | } | 513 | } |
508 | 514 | ||
509 | rc = smk_set_access(&rule, rule_list, rule_lock, load); | 515 | rc = cnt; |
510 | if (rc == 0) | ||
511 | rc = count; | ||
512 | out: | 516 | out: |
513 | kfree(data); | 517 | kfree(data); |
514 | return rc; | 518 | return rc; |
@@ -1829,7 +1833,6 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, | |||
1829 | { | 1833 | { |
1830 | struct smack_parsed_rule rule; | 1834 | struct smack_parsed_rule rule; |
1831 | char *data; | 1835 | char *data; |
1832 | char *cod; | ||
1833 | int res; | 1836 | int res; |
1834 | 1837 | ||
1835 | data = simple_transaction_get(file, buf, count); | 1838 | data = simple_transaction_get(file, buf, count); |
@@ -1842,18 +1845,12 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, | |||
1842 | res = smk_parse_rule(data, &rule, 0); | 1845 | res = smk_parse_rule(data, &rule, 0); |
1843 | } else { | 1846 | } else { |
1844 | /* | 1847 | /* |
1845 | * Copy the data to make sure the string is terminated. | 1848 | * simple_transaction_get() returns null-terminated data |
1846 | */ | 1849 | */ |
1847 | cod = kzalloc(count + 1, GFP_KERNEL); | 1850 | res = smk_parse_long_rule(data, &rule, 0, 3); |
1848 | if (cod == NULL) | ||
1849 | return -ENOMEM; | ||
1850 | memcpy(cod, data, count); | ||
1851 | cod[count] = '\0'; | ||
1852 | res = smk_parse_long_rule(cod, &rule, 0, 0); | ||
1853 | kfree(cod); | ||
1854 | } | 1851 | } |
1855 | 1852 | ||
1856 | if (res) | 1853 | if (res < 0) |
1857 | return -EINVAL; | 1854 | return -EINVAL; |
1858 | 1855 | ||
1859 | res = smk_access(rule.smk_subject, rule.smk_object, | 1856 | res = smk_access(rule.smk_subject, rule.smk_object, |