diff options
Diffstat (limited to 'security/smack/smack_lsm.c')
-rw-r--r-- | security/smack/smack_lsm.c | 74 |
1 files changed, 50 insertions, 24 deletions
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 7e19afe0e738..05dc4da2e25f 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -3,12 +3,14 @@ | |||
3 | * | 3 | * |
4 | * This file contains the smack hook function implementations. | 4 | * This file contains the smack hook function implementations. |
5 | * | 5 | * |
6 | * Author: | 6 | * Authors: |
7 | * Casey Schaufler <casey@schaufler-ca.com> | 7 | * Casey Schaufler <casey@schaufler-ca.com> |
8 | * Jarkko Sakkinen <ext-jarkko.2.sakkinen@nokia.com> | ||
8 | * | 9 | * |
9 | * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com> | 10 | * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com> |
10 | * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. | 11 | * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. |
11 | * Paul Moore <paul.moore@hp.com> | 12 | * Paul Moore <paul.moore@hp.com> |
13 | * Copyright (C) 2010 Nokia Corporation | ||
12 | * | 14 | * |
13 | * This program is free software; you can redistribute it and/or modify | 15 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License version 2, | 16 | * it under the terms of the GNU General Public License version 2, |
@@ -35,6 +37,9 @@ | |||
35 | 37 | ||
36 | #define task_security(task) (task_cred_xxx((task), security)) | 38 | #define task_security(task) (task_cred_xxx((task), security)) |
37 | 39 | ||
40 | #define TRANS_TRUE "TRUE" | ||
41 | #define TRANS_TRUE_SIZE 4 | ||
42 | |||
38 | /** | 43 | /** |
39 | * smk_fetch - Fetch the smack label from a file. | 44 | * smk_fetch - Fetch the smack label from a file. |
40 | * @ip: a pointer to the inode | 45 | * @ip: a pointer to the inode |
@@ -468,6 +473,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, | |||
468 | char **name, void **value, size_t *len) | 473 | char **name, void **value, size_t *len) |
469 | { | 474 | { |
470 | char *isp = smk_of_inode(inode); | 475 | char *isp = smk_of_inode(inode); |
476 | char *dsp = smk_of_inode(dir); | ||
477 | u32 may; | ||
471 | 478 | ||
472 | if (name) { | 479 | if (name) { |
473 | *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL); | 480 | *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL); |
@@ -476,6 +483,16 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, | |||
476 | } | 483 | } |
477 | 484 | ||
478 | if (value) { | 485 | if (value) { |
486 | may = smk_access_entry(smk_of_current(), dsp); | ||
487 | |||
488 | /* | ||
489 | * If the access rule allows transmutation and | ||
490 | * the directory requests transmutation then | ||
491 | * by all means transmute. | ||
492 | */ | ||
493 | if (((may & MAY_TRANSMUTE) != 0) && smk_inode_transmutable(dir)) | ||
494 | isp = dsp; | ||
495 | |||
479 | *value = kstrdup(isp, GFP_KERNEL); | 496 | *value = kstrdup(isp, GFP_KERNEL); |
480 | if (*value == NULL) | 497 | if (*value == NULL) |
481 | return -ENOMEM; | 498 | return -ENOMEM; |
@@ -709,6 +726,12 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, | |||
709 | if (size == 0 || size >= SMK_LABELLEN || | 726 | if (size == 0 || size >= SMK_LABELLEN || |
710 | smk_import(value, size) == NULL) | 727 | smk_import(value, size) == NULL) |
711 | rc = -EINVAL; | 728 | rc = -EINVAL; |
729 | } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { | ||
730 | if (!capable(CAP_MAC_ADMIN)) | ||
731 | rc = -EPERM; | ||
732 | if (size != TRANS_TRUE_SIZE || | ||
733 | strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0) | ||
734 | rc = -EINVAL; | ||
712 | } else | 735 | } else |
713 | rc = cap_inode_setxattr(dentry, name, value, size, flags); | 736 | rc = cap_inode_setxattr(dentry, name, value, size, flags); |
714 | 737 | ||
@@ -735,35 +758,23 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, | |||
735 | static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, | 758 | static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, |
736 | const void *value, size_t size, int flags) | 759 | const void *value, size_t size, int flags) |
737 | { | 760 | { |
738 | struct inode_smack *isp; | ||
739 | char *nsp; | 761 | char *nsp; |
740 | 762 | struct inode_smack *isp = dentry->d_inode->i_security; | |
741 | /* | ||
742 | * Not SMACK or SMACKEXEC | ||
743 | */ | ||
744 | if (strcmp(name, XATTR_NAME_SMACK) && | ||
745 | strcmp(name, XATTR_NAME_SMACKEXEC)) | ||
746 | return; | ||
747 | |||
748 | isp = dentry->d_inode->i_security; | ||
749 | |||
750 | /* | ||
751 | * No locking is done here. This is a pointer | ||
752 | * assignment. | ||
753 | */ | ||
754 | nsp = smk_import(value, size); | ||
755 | 763 | ||
756 | if (strcmp(name, XATTR_NAME_SMACK) == 0) { | 764 | if (strcmp(name, XATTR_NAME_SMACK) == 0) { |
765 | nsp = smk_import(value, size); | ||
757 | if (nsp != NULL) | 766 | if (nsp != NULL) |
758 | isp->smk_inode = nsp; | 767 | isp->smk_inode = nsp; |
759 | else | 768 | else |
760 | isp->smk_inode = smack_known_invalid.smk_known; | 769 | isp->smk_inode = smack_known_invalid.smk_known; |
761 | } else { | 770 | } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { |
771 | nsp = smk_import(value, size); | ||
762 | if (nsp != NULL) | 772 | if (nsp != NULL) |
763 | isp->smk_task = nsp; | 773 | isp->smk_task = nsp; |
764 | else | 774 | else |
765 | isp->smk_task = smack_known_invalid.smk_known; | 775 | isp->smk_task = smack_known_invalid.smk_known; |
766 | } | 776 | } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) |
777 | isp->smk_flags |= SMK_INODE_TRANSMUTE; | ||
767 | 778 | ||
768 | return; | 779 | return; |
769 | } | 780 | } |
@@ -803,7 +814,8 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) | |||
803 | if (strcmp(name, XATTR_NAME_SMACK) == 0 || | 814 | if (strcmp(name, XATTR_NAME_SMACK) == 0 || |
804 | strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || | 815 | strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || |
805 | strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || | 816 | strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || |
806 | strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { | 817 | strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || |
818 | strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { | ||
807 | if (!capable(CAP_MAC_ADMIN)) | 819 | if (!capable(CAP_MAC_ADMIN)) |
808 | rc = -EPERM; | 820 | rc = -EPERM; |
809 | } else | 821 | } else |
@@ -2274,6 +2286,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
2274 | char *csp = smk_of_current(); | 2286 | char *csp = smk_of_current(); |
2275 | char *fetched; | 2287 | char *fetched; |
2276 | char *final; | 2288 | char *final; |
2289 | char trattr[TRANS_TRUE_SIZE]; | ||
2290 | int transflag = 0; | ||
2277 | struct dentry *dp; | 2291 | struct dentry *dp; |
2278 | 2292 | ||
2279 | if (inode == NULL) | 2293 | if (inode == NULL) |
@@ -2392,10 +2406,19 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
2392 | */ | 2406 | */ |
2393 | dp = dget(opt_dentry); | 2407 | dp = dget(opt_dentry); |
2394 | fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp); | 2408 | fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp); |
2395 | if (fetched != NULL) | 2409 | if (fetched != NULL) { |
2396 | final = fetched; | 2410 | final = fetched; |
2397 | isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, | 2411 | if (S_ISDIR(inode->i_mode)) { |
2398 | dp); | 2412 | trattr[0] = '\0'; |
2413 | inode->i_op->getxattr(dp, | ||
2414 | XATTR_NAME_SMACKTRANSMUTE, | ||
2415 | trattr, TRANS_TRUE_SIZE); | ||
2416 | if (strncmp(trattr, TRANS_TRUE, | ||
2417 | TRANS_TRUE_SIZE) == 0) | ||
2418 | transflag = SMK_INODE_TRANSMUTE; | ||
2419 | } | ||
2420 | } | ||
2421 | isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); | ||
2399 | 2422 | ||
2400 | dput(dp); | 2423 | dput(dp); |
2401 | break; | 2424 | break; |
@@ -2406,7 +2429,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
2406 | else | 2429 | else |
2407 | isp->smk_inode = final; | 2430 | isp->smk_inode = final; |
2408 | 2431 | ||
2409 | isp->smk_flags |= SMK_INODE_INSTANT; | 2432 | isp->smk_flags |= (SMK_INODE_INSTANT | transflag); |
2410 | 2433 | ||
2411 | unlockandout: | 2434 | unlockandout: |
2412 | mutex_unlock(&isp->smk_lock); | 2435 | mutex_unlock(&isp->smk_lock); |
@@ -2456,6 +2479,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, | |||
2456 | void *value, size_t size) | 2479 | void *value, size_t size) |
2457 | { | 2480 | { |
2458 | struct task_smack *tsp; | 2481 | struct task_smack *tsp; |
2482 | struct task_smack *oldtsp; | ||
2459 | struct cred *new; | 2483 | struct cred *new; |
2460 | char *newsmack; | 2484 | char *newsmack; |
2461 | 2485 | ||
@@ -2485,6 +2509,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, | |||
2485 | if (newsmack == smack_known_web.smk_known) | 2509 | if (newsmack == smack_known_web.smk_known) |
2486 | return -EPERM; | 2510 | return -EPERM; |
2487 | 2511 | ||
2512 | oldtsp = p->cred->security; | ||
2488 | new = prepare_creds(); | 2513 | new = prepare_creds(); |
2489 | if (new == NULL) | 2514 | if (new == NULL) |
2490 | return -ENOMEM; | 2515 | return -ENOMEM; |
@@ -2494,6 +2519,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, | |||
2494 | return -ENOMEM; | 2519 | return -ENOMEM; |
2495 | } | 2520 | } |
2496 | tsp->smk_task = newsmack; | 2521 | tsp->smk_task = newsmack; |
2522 | tsp->smk_forked = oldtsp->smk_forked; | ||
2497 | new->security = tsp; | 2523 | new->security = tsp; |
2498 | commit_creds(new); | 2524 | commit_creds(new); |
2499 | return size; | 2525 | return size; |