diff options
author | James Morris <james.l.morris@oracle.com> | 2013-08-22 12:50:12 -0400 |
---|---|---|
committer | James Morris <james.l.morris@oracle.com> | 2013-08-22 12:50:12 -0400 |
commit | 73203361468894c3c017bfbdd9ddcbb468039604 (patch) | |
tree | bfda3843b96c0056ef84d0957110833bb21f2b02 /security | |
parent | f8eb8a1324e81927b2c64823b2fc38386efd3fef (diff) | |
parent | 10289b0f738e8b301969f2288c4942455f1b1e59 (diff) |
Merge branch 'smack-for-3.12' of git://git.gitorious.org/smack-next/kernel into ra-next
Diffstat (limited to 'security')
-rw-r--r-- | security/smack/smack.h | 13 | ||||
-rw-r--r-- | security/smack/smack_access.c | 29 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 42 | ||||
-rw-r--r-- | security/smack/smackfs.c | 180 |
4 files changed, 150 insertions, 114 deletions
diff --git a/security/smack/smack.h b/security/smack/smack.h index 339614c76e63..076b8e8a51ab 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -53,6 +53,7 @@ | |||
53 | */ | 53 | */ |
54 | struct smack_known { | 54 | struct smack_known { |
55 | struct list_head list; | 55 | struct list_head list; |
56 | struct hlist_node smk_hashed; | ||
56 | char *smk_known; | 57 | char *smk_known; |
57 | u32 smk_secid; | 58 | u32 smk_secid; |
58 | struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */ | 59 | struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */ |
@@ -167,9 +168,13 @@ struct smk_port_label { | |||
167 | #define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */ | 168 | #define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */ |
168 | #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ | 169 | #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ |
169 | #define SMACK_CIPSO_MAPPED_DEFAULT 251 /* Also arbitrary */ | 170 | #define SMACK_CIPSO_MAPPED_DEFAULT 251 /* Also arbitrary */ |
170 | #define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */ | ||
171 | #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ | 171 | #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ |
172 | #define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */ | 172 | /* |
173 | * CIPSO 2.2 standard is 239, but Smack wants to use the | ||
174 | * categories in a structured way that limits the value to | ||
175 | * the bits in 23 bytes, hence the unusual number. | ||
176 | */ | ||
177 | #define SMACK_CIPSO_MAXCATNUM 184 /* 23 * 8 */ | ||
173 | 178 | ||
174 | /* | 179 | /* |
175 | * Flag for transmute access | 180 | * Flag for transmute access |
@@ -222,6 +227,7 @@ char *smk_parse_smack(const char *string, int len); | |||
222 | int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); | 227 | int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); |
223 | char *smk_import(const char *, int); | 228 | char *smk_import(const char *, int); |
224 | struct smack_known *smk_import_entry(const char *, int); | 229 | struct smack_known *smk_import_entry(const char *, int); |
230 | void smk_insert_entry(struct smack_known *skp); | ||
225 | struct smack_known *smk_find_entry(const char *); | 231 | struct smack_known *smk_find_entry(const char *); |
226 | u32 smack_to_secid(const char *); | 232 | u32 smack_to_secid(const char *); |
227 | 233 | ||
@@ -247,6 +253,9 @@ extern struct list_head smk_netlbladdr_list; | |||
247 | 253 | ||
248 | extern struct security_operations smack_ops; | 254 | extern struct security_operations smack_ops; |
249 | 255 | ||
256 | #define SMACK_HASH_SLOTS 16 | ||
257 | extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; | ||
258 | |||
250 | /* | 259 | /* |
251 | * Is the directory transmuting? | 260 | * Is the directory transmuting? |
252 | */ | 261 | */ |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 6a0377f38620..b3b59b1e93d6 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -325,6 +325,25 @@ void smack_log(char *subject_label, char *object_label, int request, | |||
325 | 325 | ||
326 | DEFINE_MUTEX(smack_known_lock); | 326 | DEFINE_MUTEX(smack_known_lock); |
327 | 327 | ||
328 | struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; | ||
329 | |||
330 | /** | ||
331 | * smk_insert_entry - insert a smack label into a hash map, | ||
332 | * | ||
333 | * this function must be called under smack_known_lock | ||
334 | */ | ||
335 | void smk_insert_entry(struct smack_known *skp) | ||
336 | { | ||
337 | unsigned int hash; | ||
338 | struct hlist_head *head; | ||
339 | |||
340 | hash = full_name_hash(skp->smk_known, strlen(skp->smk_known)); | ||
341 | head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)]; | ||
342 | |||
343 | hlist_add_head_rcu(&skp->smk_hashed, head); | ||
344 | list_add_rcu(&skp->list, &smack_known_list); | ||
345 | } | ||
346 | |||
328 | /** | 347 | /** |
329 | * smk_find_entry - find a label on the list, return the list entry | 348 | * smk_find_entry - find a label on the list, return the list entry |
330 | * @string: a text string that might be a Smack label | 349 | * @string: a text string that might be a Smack label |
@@ -334,12 +353,16 @@ DEFINE_MUTEX(smack_known_lock); | |||
334 | */ | 353 | */ |
335 | struct smack_known *smk_find_entry(const char *string) | 354 | struct smack_known *smk_find_entry(const char *string) |
336 | { | 355 | { |
356 | unsigned int hash; | ||
357 | struct hlist_head *head; | ||
337 | struct smack_known *skp; | 358 | struct smack_known *skp; |
338 | 359 | ||
339 | list_for_each_entry_rcu(skp, &smack_known_list, list) { | 360 | hash = full_name_hash(string, strlen(string)); |
361 | head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)]; | ||
362 | |||
363 | hlist_for_each_entry_rcu(skp, head, smk_hashed) | ||
340 | if (strcmp(skp->smk_known, string) == 0) | 364 | if (strcmp(skp->smk_known, string) == 0) |
341 | return skp; | 365 | return skp; |
342 | } | ||
343 | 366 | ||
344 | return NULL; | 367 | return NULL; |
345 | } | 368 | } |
@@ -475,7 +498,7 @@ struct smack_known *smk_import_entry(const char *string, int len) | |||
475 | * Make sure that the entry is actually | 498 | * Make sure that the entry is actually |
476 | * filled before putting it on the list. | 499 | * filled before putting it on the list. |
477 | */ | 500 | */ |
478 | list_add_rcu(&skp->list, &smack_known_list); | 501 | smk_insert_entry(skp); |
479 | goto unlockout; | 502 | goto unlockout; |
480 | } | 503 | } |
481 | /* | 504 | /* |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index a113a779f00c..19de5e237683 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -3063,6 +3063,8 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, | |||
3063 | { | 3063 | { |
3064 | struct smack_known *skp; | 3064 | struct smack_known *skp; |
3065 | int found = 0; | 3065 | int found = 0; |
3066 | int acat; | ||
3067 | int kcat; | ||
3066 | 3068 | ||
3067 | if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { | 3069 | if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { |
3068 | /* | 3070 | /* |
@@ -3079,12 +3081,28 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, | |||
3079 | list_for_each_entry(skp, &smack_known_list, list) { | 3081 | list_for_each_entry(skp, &smack_known_list, list) { |
3080 | if (sap->attr.mls.lvl != skp->smk_netlabel.attr.mls.lvl) | 3082 | if (sap->attr.mls.lvl != skp->smk_netlabel.attr.mls.lvl) |
3081 | continue; | 3083 | continue; |
3082 | if (memcmp(sap->attr.mls.cat, | 3084 | /* |
3083 | skp->smk_netlabel.attr.mls.cat, | 3085 | * Compare the catsets. Use the netlbl APIs. |
3084 | SMK_CIPSOLEN) != 0) | 3086 | */ |
3085 | continue; | 3087 | if ((sap->flags & NETLBL_SECATTR_MLS_CAT) == 0) { |
3086 | found = 1; | 3088 | if ((skp->smk_netlabel.flags & |
3087 | break; | 3089 | NETLBL_SECATTR_MLS_CAT) == 0) |
3090 | found = 1; | ||
3091 | break; | ||
3092 | } | ||
3093 | for (acat = -1, kcat = -1; acat == kcat; ) { | ||
3094 | acat = netlbl_secattr_catmap_walk( | ||
3095 | sap->attr.mls.cat, acat + 1); | ||
3096 | kcat = netlbl_secattr_catmap_walk( | ||
3097 | skp->smk_netlabel.attr.mls.cat, | ||
3098 | kcat + 1); | ||
3099 | if (acat < 0 || kcat < 0) | ||
3100 | break; | ||
3101 | } | ||
3102 | if (acat == kcat) { | ||
3103 | found = 1; | ||
3104 | break; | ||
3105 | } | ||
3088 | } | 3106 | } |
3089 | rcu_read_unlock(); | 3107 | rcu_read_unlock(); |
3090 | 3108 | ||
@@ -3876,12 +3894,12 @@ static __init void init_smack_known_list(void) | |||
3876 | /* | 3894 | /* |
3877 | * Create the known labels list | 3895 | * Create the known labels list |
3878 | */ | 3896 | */ |
3879 | list_add(&smack_known_huh.list, &smack_known_list); | 3897 | smk_insert_entry(&smack_known_huh); |
3880 | list_add(&smack_known_hat.list, &smack_known_list); | 3898 | smk_insert_entry(&smack_known_hat); |
3881 | list_add(&smack_known_star.list, &smack_known_list); | 3899 | smk_insert_entry(&smack_known_star); |
3882 | list_add(&smack_known_floor.list, &smack_known_list); | 3900 | smk_insert_entry(&smack_known_floor); |
3883 | list_add(&smack_known_invalid.list, &smack_known_list); | 3901 | smk_insert_entry(&smack_known_invalid); |
3884 | list_add(&smack_known_web.list, &smack_known_list); | 3902 | smk_insert_entry(&smack_known_web); |
3885 | } | 3903 | } |
3886 | 3904 | ||
3887 | /** | 3905 | /** |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index ab167037b2dd..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 */ |
@@ -447,11 +434,12 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, | |||
447 | struct list_head *rule_list, | 434 | struct list_head *rule_list, |
448 | struct mutex *rule_lock, int format) | 435 | struct mutex *rule_lock, int format) |
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,47 +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 | rule = kzalloc(sizeof(*rule), GFP_KERNEL); | 473 | /* |
483 | if (rule == NULL) { | 474 | * In case of parsing only part of user buf, |
484 | rc = -ENOMEM; | 475 | * avoid having partial rule at the data buffer |
485 | goto out; | 476 | */ |
477 | if (trunc) { | ||
478 | while (count > 0 && (data[count - 1] != '\n')) | ||
479 | --count; | ||
480 | if (count == 0) { | ||
481 | rc = -EINVAL; | ||
482 | goto out; | ||
483 | } | ||
486 | } | 484 | } |
487 | 485 | ||
488 | if (format == SMK_LONG_FMT) { | 486 | data[count] = '\0'; |
489 | /* | 487 | tokens = (format == SMK_CHANGE_FMT ? 4 : 3); |
490 | * Be sure the data string is terminated. | 488 | while (cnt < count) { |
491 | */ | 489 | if (format == SMK_FIXED24_FMT) { |
492 | data[count] = '\0'; | 490 | rc = smk_parse_rule(data, &rule, 1); |
493 | if (smk_parse_long_rule(data, rule, 1, 0)) | 491 | if (rc != 0) { |
494 | goto out_free_rule; | 492 | rc = -EINVAL; |
495 | } else if (format == SMK_CHANGE_FMT) { | 493 | goto out; |
496 | data[count] = '\0'; | 494 | } |
497 | if (smk_parse_long_rule(data, rule, 1, 1)) | 495 | cnt = count; |
498 | goto out_free_rule; | 496 | } else { |
499 | } else { | 497 | rc = smk_parse_long_rule(data + cnt, &rule, 1, tokens); |
500 | /* | 498 | if (rc <= 0) { |
501 | * More on the minor hack for backward compatibility | 499 | rc = -EINVAL; |
502 | */ | 500 | goto out; |
503 | if (count == (SMK_OLOADLEN)) | 501 | } |
504 | data[SMK_OLOADLEN] = '-'; | 502 | cnt += rc; |
505 | if (smk_parse_rule(data, rule, 1)) | 503 | } |
506 | goto out_free_rule; | ||
507 | } | ||
508 | 504 | ||
509 | if (rule_list == NULL) { | 505 | if (rule_list == NULL) |
510 | load = 1; | 506 | rc = smk_set_access(&rule, &rule.smk_subject->smk_rules, |
511 | rule_list = &rule->smk_subject->smk_rules; | 507 | &rule.smk_subject->smk_rules_lock, 1); |
512 | rule_lock = &rule->smk_subject->smk_rules_lock; | 508 | else |
513 | } | 509 | rc = smk_set_access(&rule, rule_list, rule_lock, 0); |
514 | 510 | ||
515 | rc = smk_set_access(rule, rule_list, rule_lock, load); | 511 | if (rc) |
516 | if (rc == 0) { | 512 | goto out; |
517 | rc = count; | ||
518 | goto out; | ||
519 | } | 513 | } |
520 | 514 | ||
521 | out_free_rule: | 515 | rc = cnt; |
522 | kfree(rule); | ||
523 | out: | 516 | out: |
524 | kfree(data); | 517 | kfree(data); |
525 | return rc; | 518 | return rc; |
@@ -901,7 +894,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, | |||
901 | for (i = 0; i < catlen; i++) { | 894 | for (i = 0; i < catlen; i++) { |
902 | rule += SMK_DIGITLEN; | 895 | rule += SMK_DIGITLEN; |
903 | ret = sscanf(rule, "%u", &cat); | 896 | ret = sscanf(rule, "%u", &cat); |
904 | if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL) | 897 | if (ret != 1 || cat > SMACK_CIPSO_MAXCATNUM) |
905 | goto out; | 898 | goto out; |
906 | 899 | ||
907 | smack_catset_bit(cat, mapcatset); | 900 | smack_catset_bit(cat, mapcatset); |
@@ -1840,7 +1833,6 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, | |||
1840 | { | 1833 | { |
1841 | struct smack_parsed_rule rule; | 1834 | struct smack_parsed_rule rule; |
1842 | char *data; | 1835 | char *data; |
1843 | char *cod; | ||
1844 | int res; | 1836 | int res; |
1845 | 1837 | ||
1846 | data = simple_transaction_get(file, buf, count); | 1838 | data = simple_transaction_get(file, buf, count); |
@@ -1853,18 +1845,12 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, | |||
1853 | res = smk_parse_rule(data, &rule, 0); | 1845 | res = smk_parse_rule(data, &rule, 0); |
1854 | } else { | 1846 | } else { |
1855 | /* | 1847 | /* |
1856 | * Copy the data to make sure the string is terminated. | 1848 | * simple_transaction_get() returns null-terminated data |
1857 | */ | 1849 | */ |
1858 | cod = kzalloc(count + 1, GFP_KERNEL); | 1850 | res = smk_parse_long_rule(data, &rule, 0, 3); |
1859 | if (cod == NULL) | ||
1860 | return -ENOMEM; | ||
1861 | memcpy(cod, data, count); | ||
1862 | cod[count] = '\0'; | ||
1863 | res = smk_parse_long_rule(cod, &rule, 0, 0); | ||
1864 | kfree(cod); | ||
1865 | } | 1851 | } |
1866 | 1852 | ||
1867 | if (res) | 1853 | if (res < 0) |
1868 | return -EINVAL; | 1854 | return -EINVAL; |
1869 | 1855 | ||
1870 | res = smk_access(rule.smk_subject, rule.smk_object, | 1856 | res = smk_access(rule.smk_subject, rule.smk_object, |