aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorJames Morris <james.l.morris@oracle.com>2013-08-22 12:50:12 -0400
committerJames Morris <james.l.morris@oracle.com>2013-08-22 12:50:12 -0400
commit73203361468894c3c017bfbdd9ddcbb468039604 (patch)
treebfda3843b96c0056ef84d0957110833bb21f2b02 /security
parentf8eb8a1324e81927b2c64823b2fc38386efd3fef (diff)
parent10289b0f738e8b301969f2288c4942455f1b1e59 (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.h13
-rw-r--r--security/smack/smack_access.c29
-rw-r--r--security/smack/smack_lsm.c42
-rw-r--r--security/smack/smackfs.c180
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 */
54struct smack_known { 54struct 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);
222int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); 227int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
223char *smk_import(const char *, int); 228char *smk_import(const char *, int);
224struct smack_known *smk_import_entry(const char *, int); 229struct smack_known *smk_import_entry(const char *, int);
230void smk_insert_entry(struct smack_known *skp);
225struct smack_known *smk_find_entry(const char *); 231struct smack_known *smk_find_entry(const char *);
226u32 smack_to_secid(const char *); 232u32 smack_to_secid(const char *);
227 233
@@ -247,6 +253,9 @@ extern struct list_head smk_netlbladdr_list;
247 253
248extern struct security_operations smack_ops; 254extern struct security_operations smack_ops;
249 255
256#define SMACK_HASH_SLOTS 16
257extern 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
326DEFINE_MUTEX(smack_known_lock); 326DEFINE_MUTEX(smack_known_lock);
327 327
328struct 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 */
335void 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 */
335struct smack_known *smk_find_entry(const char *string) 354struct 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 */
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 */
@@ -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
521out_free_rule: 515 rc = cnt;
522 kfree(rule);
523out: 516out:
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,