diff options
Diffstat (limited to 'security/smack/smack_access.c')
-rw-r--r-- | security/smack/smack_access.c | 233 |
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 @@ | |||
19 | struct smack_known smack_known_huh = { | 19 | struct 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 | ||
25 | struct smack_known smack_known_hat = { | 24 | struct 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 | ||
31 | struct smack_known smack_known_star = { | 29 | struct 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 | ||
37 | struct smack_known smack_known_floor = { | 34 | struct 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 | ||
43 | struct smack_known smack_known_invalid = { | 39 | struct 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 | ||
49 | struct smack_known smack_known_web = { | 44 | struct 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 | ||
55 | LIST_HEAD(smack_known_list); | 49 | LIST_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 | ||
334 | static DEFINE_MUTEX(smack_known_lock); | 328 | DEFINE_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 | */ |
361 | void smk_parse_smack(const char *string, int len, char *smack) | 356 | char *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 | */ | ||
396 | int 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) | |||
390 | struct smack_known *smk_import_entry(const char *string, int len) | 433 | struct 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; | ||
486 | freeout: | ||
487 | kfree(smack); | ||
488 | unlockout: | ||
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 | */ |
480 | u32 smack_to_secid(const char *smack) | 549 | u32 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 | */ | ||
504 | char *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 | */ | ||
537 | int 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 | } |