aboutsummaryrefslogtreecommitdiffstats
path: root/security/smack/smack_access.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/smack/smack_access.c')
-rw-r--r--security/smack/smack_access.c233
1 files changed, 116 insertions, 117 deletions
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index c8115f7308f8..9f3705e92712 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -19,37 +19,31 @@
19struct smack_known smack_known_huh = { 19struct smack_known smack_known_huh = {
20 .smk_known = "?", 20 .smk_known = "?",
21 .smk_secid = 2, 21 .smk_secid = 2,
22 .smk_cipso = NULL,
23}; 22};
24 23
25struct smack_known smack_known_hat = { 24struct smack_known smack_known_hat = {
26 .smk_known = "^", 25 .smk_known = "^",
27 .smk_secid = 3, 26 .smk_secid = 3,
28 .smk_cipso = NULL,
29}; 27};
30 28
31struct smack_known smack_known_star = { 29struct smack_known smack_known_star = {
32 .smk_known = "*", 30 .smk_known = "*",
33 .smk_secid = 4, 31 .smk_secid = 4,
34 .smk_cipso = NULL,
35}; 32};
36 33
37struct smack_known smack_known_floor = { 34struct smack_known smack_known_floor = {
38 .smk_known = "_", 35 .smk_known = "_",
39 .smk_secid = 5, 36 .smk_secid = 5,
40 .smk_cipso = NULL,
41}; 37};
42 38
43struct smack_known smack_known_invalid = { 39struct smack_known smack_known_invalid = {
44 .smk_known = "", 40 .smk_known = "",
45 .smk_secid = 6, 41 .smk_secid = 6,
46 .smk_cipso = NULL,
47}; 42};
48 43
49struct smack_known smack_known_web = { 44struct smack_known smack_known_web = {
50 .smk_known = "@", 45 .smk_known = "@",
51 .smk_secid = 7, 46 .smk_secid = 7,
52 .smk_cipso = NULL,
53}; 47};
54 48
55LIST_HEAD(smack_known_list); 49LIST_HEAD(smack_known_list);
@@ -331,7 +325,7 @@ void smack_log(char *subject_label, char *object_label, int request,
331} 325}
332#endif 326#endif
333 327
334static DEFINE_MUTEX(smack_known_lock); 328DEFINE_MUTEX(smack_known_lock);
335 329
336/** 330/**
337 * smk_find_entry - find a label on the list, return the list entry 331 * smk_find_entry - find a label on the list, return the list entry
@@ -345,7 +339,7 @@ struct smack_known *smk_find_entry(const char *string)
345 struct smack_known *skp; 339 struct smack_known *skp;
346 340
347 list_for_each_entry_rcu(skp, &smack_known_list, list) { 341 list_for_each_entry_rcu(skp, &smack_known_list, list) {
348 if (strncmp(skp->smk_known, string, SMK_MAXLEN) == 0) 342 if (strcmp(skp->smk_known, string) == 0)
349 return skp; 343 return skp;
350 } 344 }
351 345
@@ -356,27 +350,76 @@ struct smack_known *smk_find_entry(const char *string)
356 * smk_parse_smack - parse smack label from a text string 350 * smk_parse_smack - parse smack label from a text string
357 * @string: a text string that might contain a Smack label 351 * @string: a text string that might contain a Smack label
358 * @len: the maximum size, or zero if it is NULL terminated. 352 * @len: the maximum size, or zero if it is NULL terminated.
359 * @smack: parsed smack label, or NULL if parse error 353 *
354 * Returns a pointer to the clean label, or NULL
360 */ 355 */
361void smk_parse_smack(const char *string, int len, char *smack) 356char *smk_parse_smack(const char *string, int len)
362{ 357{
363 int found; 358 char *smack;
364 int i; 359 int i;
365 360
366 if (len <= 0 || len > SMK_MAXLEN) 361 if (len <= 0)
367 len = SMK_MAXLEN; 362 len = strlen(string) + 1;
368 363
369 for (i = 0, found = 0; i < SMK_LABELLEN; i++) { 364 /*
370 if (found) 365 * Reserve a leading '-' as an indicator that
371 smack[i] = '\0'; 366 * this isn't a label, but an option to interfaces
372 else if (i >= len || string[i] > '~' || string[i] <= ' ' || 367 * including /smack/cipso and /smack/cipso2
373 string[i] == '/' || string[i] == '"' || 368 */
374 string[i] == '\\' || string[i] == '\'') { 369 if (string[0] == '-')
375 smack[i] = '\0'; 370 return NULL;
376 found = 1; 371
377 } else 372 for (i = 0; i < len; i++)
378 smack[i] = string[i]; 373 if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' ||
374 string[i] == '"' || string[i] == '\\' || string[i] == '\'')
375 break;
376
377 if (i == 0 || i >= SMK_LONGLABEL)
378 return NULL;
379
380 smack = kzalloc(i + 1, GFP_KERNEL);
381 if (smack != NULL) {
382 strncpy(smack, string, i + 1);
383 smack[i] = '\0';
379 } 384 }
385 return smack;
386}
387
388/**
389 * smk_netlbl_mls - convert a catset to netlabel mls categories
390 * @catset: the Smack categories
391 * @sap: where to put the netlabel categories
392 *
393 * Allocates and fills attr.mls
394 * Returns 0 on success, error code on failure.
395 */
396int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
397 int len)
398{
399 unsigned char *cp;
400 unsigned char m;
401 int cat;
402 int rc;
403 int byte;
404
405 sap->flags |= NETLBL_SECATTR_MLS_CAT;
406 sap->attr.mls.lvl = level;
407 sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
408 sap->attr.mls.cat->startbit = 0;
409
410 for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++)
411 for (m = 0x80; m != 0; m >>= 1, cat++) {
412 if ((m & *cp) == 0)
413 continue;
414 rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat,
415 cat, GFP_ATOMIC);
416 if (rc < 0) {
417 netlbl_secattr_catmap_free(sap->attr.mls.cat);
418 return rc;
419 }
420 }
421
422 return 0;
380} 423}
381 424
382/** 425/**
@@ -390,33 +433,59 @@ void smk_parse_smack(const char *string, int len, char *smack)
390struct smack_known *smk_import_entry(const char *string, int len) 433struct smack_known *smk_import_entry(const char *string, int len)
391{ 434{
392 struct smack_known *skp; 435 struct smack_known *skp;
393 char smack[SMK_LABELLEN]; 436 char *smack;
437 int slen;
438 int rc;
394 439
395 smk_parse_smack(string, len, smack); 440 smack = smk_parse_smack(string, len);
396 if (smack[0] == '\0') 441 if (smack == NULL)
397 return NULL; 442 return NULL;
398 443
399 mutex_lock(&smack_known_lock); 444 mutex_lock(&smack_known_lock);
400 445
401 skp = smk_find_entry(smack); 446 skp = smk_find_entry(smack);
447 if (skp != NULL)
448 goto freeout;
402 449
403 if (skp == NULL) { 450 skp = kzalloc(sizeof(*skp), GFP_KERNEL);
404 skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); 451 if (skp == NULL)
405 if (skp != NULL) { 452 goto freeout;
406 strncpy(skp->smk_known, smack, SMK_MAXLEN);
407 skp->smk_secid = smack_next_secid++;
408 skp->smk_cipso = NULL;
409 INIT_LIST_HEAD(&skp->smk_rules);
410 spin_lock_init(&skp->smk_cipsolock);
411 mutex_init(&skp->smk_rules_lock);
412 /*
413 * Make sure that the entry is actually
414 * filled before putting it on the list.
415 */
416 list_add_rcu(&skp->list, &smack_known_list);
417 }
418 }
419 453
454 skp->smk_known = smack;
455 skp->smk_secid = smack_next_secid++;
456 skp->smk_netlabel.domain = skp->smk_known;
457 skp->smk_netlabel.flags =
458 NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
459 /*
460 * If direct labeling works use it.
461 * Otherwise use mapped labeling.
462 */
463 slen = strlen(smack);
464 if (slen < SMK_CIPSOLEN)
465 rc = smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
466 &skp->smk_netlabel, slen);
467 else
468 rc = smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid,
469 &skp->smk_netlabel, sizeof(skp->smk_secid));
470
471 if (rc >= 0) {
472 INIT_LIST_HEAD(&skp->smk_rules);
473 mutex_init(&skp->smk_rules_lock);
474 /*
475 * Make sure that the entry is actually
476 * filled before putting it on the list.
477 */
478 list_add_rcu(&skp->list, &smack_known_list);
479 goto unlockout;
480 }
481 /*
482 * smk_netlbl_mls failed.
483 */
484 kfree(skp);
485 skp = NULL;
486freeout:
487 kfree(smack);
488unlockout:
420 mutex_unlock(&smack_known_lock); 489 mutex_unlock(&smack_known_lock);
421 490
422 return skp; 491 return skp;
@@ -479,79 +548,9 @@ char *smack_from_secid(const u32 secid)
479 */ 548 */
480u32 smack_to_secid(const char *smack) 549u32 smack_to_secid(const char *smack)
481{ 550{
482 struct smack_known *skp; 551 struct smack_known *skp = smk_find_entry(smack);
483 552
484 rcu_read_lock(); 553 if (skp == NULL)
485 list_for_each_entry_rcu(skp, &smack_known_list, list) { 554 return 0;
486 if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { 555 return skp->smk_secid;
487 rcu_read_unlock();
488 return skp->smk_secid;
489 }
490 }
491 rcu_read_unlock();
492 return 0;
493}
494
495/**
496 * smack_from_cipso - find the Smack label associated with a CIPSO option
497 * @level: Bell & LaPadula level from the network
498 * @cp: Bell & LaPadula categories from the network
499 *
500 * This is a simple lookup in the label table.
501 *
502 * Return the matching label from the label list or NULL.
503 */
504char *smack_from_cipso(u32 level, char *cp)
505{
506 struct smack_known *kp;
507 char *final = NULL;
508
509 rcu_read_lock();
510 list_for_each_entry(kp, &smack_known_list, list) {
511 if (kp->smk_cipso == NULL)
512 continue;
513
514 spin_lock_bh(&kp->smk_cipsolock);
515
516 if (kp->smk_cipso->smk_level == level &&
517 memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0)
518 final = kp->smk_known;
519
520 spin_unlock_bh(&kp->smk_cipsolock);
521
522 if (final != NULL)
523 break;
524 }
525 rcu_read_unlock();
526
527 return final;
528}
529
530/**
531 * smack_to_cipso - find the CIPSO option to go with a Smack label
532 * @smack: a pointer to the smack label in question
533 * @cp: where to put the result
534 *
535 * Returns zero if a value is available, non-zero otherwise.
536 */
537int smack_to_cipso(const char *smack, struct smack_cipso *cp)
538{
539 struct smack_known *kp;
540 int found = 0;
541
542 rcu_read_lock();
543 list_for_each_entry_rcu(kp, &smack_known_list, list) {
544 if (kp->smk_known == smack ||
545 strcmp(kp->smk_known, smack) == 0) {
546 found = 1;
547 break;
548 }
549 }
550 rcu_read_unlock();
551
552 if (found == 0 || kp->smk_cipso == NULL)
553 return -ENOENT;
554
555 memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
556 return 0;
557} 556}