aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/smack/smackfs.c167
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 */
375static int smk_parse_long_rule(const char *data, struct smack_parsed_rule *rule, 375static 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)
414free_out_a: 402 tok[i++] = NULL;
415 kfree(access1); 403
416free_out_o: 404 if (smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0))
417 kfree(object); 405 return -1;
418free_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;
512out: 516out:
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,