aboutsummaryrefslogtreecommitdiffstats
path: root/security/smack/smack_lsm.c
diff options
context:
space:
mode:
authorJarkko Sakkinen <ext-jarkko.2.sakkinen@nokia.com>2010-12-07 06:34:01 -0500
committerCasey Schaufler <casey@schaufler-ca.com>2010-12-07 17:04:02 -0500
commit5c6d1125f8dbd1bfef39e38fbc2837003be78a59 (patch)
tree368d34e800bc5478442679323270d776b79501e8 /security/smack/smack_lsm.c
parentfe27d4b012273640e033be80f143bdc54daa8e16 (diff)
Smack: Transmute labels on specified directories
In a situation where Smack access rules allow processes with multiple labels to write to a directory it is easy to get into a situation where the directory gets cluttered with files that the owner can't deal with because while they could be written to the directory a process at the label of the directory can't write them. This is generally the desired behavior, but when it isn't it is a real issue. This patch introduces a new attribute SMACK64TRANSMUTE that instructs Smack to create the file with the label of the directory under certain circumstances. A new access mode, "t" for transmute, is made available to Smack access rules, which are expanded from "rwxa" to "rwxat". If a file is created in a directory marked as transmutable and if access was granted to perform the operation by a rule that included the transmute mode, then the file gets the Smack label of the directory instead of the Smack label of the creating process. Note that this is equivalent to creating an empty file at the label of the directory and then having the other process write to it. The transmute scheme requires that both the access rule allows transmutation and that the directory be explicitly marked. Signed-off-by: Jarkko Sakkinen <ext-jarkko.2.sakkinen@nokia.com> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Diffstat (limited to 'security/smack/smack_lsm.c')
-rw-r--r--security/smack/smack_lsm.c74
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,
735static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, 758static 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
2411unlockandout: 2434unlockandout:
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;