aboutsummaryrefslogtreecommitdiffstats
path: root/security/smack
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
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')
-rw-r--r--security/smack/smack.h17
-rw-r--r--security/smack/smack_access.c54
-rw-r--r--security/smack/smack_lsm.c74
-rw-r--r--security/smack/smackfs.c37
4 files changed, 139 insertions, 43 deletions
diff --git a/security/smack/smack.h b/security/smack/smack.h
index a2e2cdfab4ef..129c4eb8ffb1 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -62,6 +62,7 @@ struct task_smack {
62}; 62};
63 63
64#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ 64#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
65#define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */
65 66
66/* 67/*
67 * A label access rule. 68 * A label access rule.
@@ -167,6 +168,10 @@ struct smack_known {
167#define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */ 168#define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */
168 169
169/* 170/*
171 * Flag for transmute access
172 */
173#define MAY_TRANSMUTE 64
174/*
170 * Just to make the common cases easier to deal with 175 * Just to make the common cases easier to deal with
171 */ 176 */
172#define MAY_ANY (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) 177#define MAY_ANY (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
@@ -197,6 +202,7 @@ struct inode_smack *new_inode_smack(char *);
197/* 202/*
198 * These functions are in smack_access.c 203 * These functions are in smack_access.c
199 */ 204 */
205int smk_access_entry(char *, char *);
200int smk_access(char *, char *, int, struct smk_audit_info *); 206int smk_access(char *, char *, int, struct smk_audit_info *);
201int smk_curacc(char *, u32, struct smk_audit_info *); 207int smk_curacc(char *, u32, struct smk_audit_info *);
202int smack_to_cipso(const char *, struct smack_cipso *); 208int smack_to_cipso(const char *, struct smack_cipso *);
@@ -240,6 +246,15 @@ static inline void smack_catset_bit(int cat, char *catsetp)
240} 246}
241 247
242/* 248/*
249 * Is the directory transmuting?
250 */
251static inline int smk_inode_transmutable(const struct inode *isp)
252{
253 struct inode_smack *sip = isp->i_security;
254 return (sip->smk_flags & SMK_INODE_TRANSMUTE) != 0;
255}
256
257/*
243 * Present a pointer to the smack label in an inode blob. 258 * Present a pointer to the smack label in an inode blob.
244 */ 259 */
245static inline char *smk_of_inode(const struct inode *isp) 260static inline char *smk_of_inode(const struct inode *isp)
@@ -265,7 +280,7 @@ static inline char *smk_of_forked(const struct task_smack *tsp)
265} 280}
266 281
267/* 282/*
268 * Present a pointer to the smack label in the curren task blob. 283 * Present a pointer to the smack label in the current task blob.
269 */ 284 */
270static inline char *smk_of_current(void) 285static inline char *smk_of_current(void)
271{ 286{
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 42becbc1ce33..7ba8478f599e 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -67,6 +67,46 @@ static u32 smack_next_secid = 10;
67int log_policy = SMACK_AUDIT_DENIED; 67int log_policy = SMACK_AUDIT_DENIED;
68 68
69/** 69/**
70 * smk_access_entry - look up matching access rule
71 * @subject_label: a pointer to the subject's Smack label
72 * @object_label: a pointer to the object's Smack label
73 *
74 * This function looks up the subject/object pair in the
75 * access rule list and returns pointer to the matching rule if found,
76 * NULL otherwise.
77 *
78 * NOTE:
79 * Even though Smack labels are usually shared on smack_list
80 * labels that come in off the network can't be imported
81 * and added to the list for locking reasons.
82 *
83 * Therefore, it is necessary to check the contents of the labels,
84 * not just the pointer values. Of course, in most cases the labels
85 * will be on the list, so checking the pointers may be a worthwhile
86 * optimization.
87 */
88int smk_access_entry(char *subject_label, char *object_label)
89{
90 u32 may = MAY_NOT;
91 struct smack_rule *srp;
92
93 rcu_read_lock();
94 list_for_each_entry_rcu(srp, &smack_rule_list, list) {
95 if (srp->smk_subject == subject_label ||
96 strcmp(srp->smk_subject, subject_label) == 0) {
97 if (srp->smk_object == object_label ||
98 strcmp(srp->smk_object, object_label) == 0) {
99 may = srp->smk_access;
100 break;
101 }
102 }
103 }
104 rcu_read_unlock();
105
106 return may;
107}
108
109/**
70 * smk_access - determine if a subject has a specific access to an object 110 * smk_access - determine if a subject has a specific access to an object
71 * @subject_label: a pointer to the subject's Smack label 111 * @subject_label: a pointer to the subject's Smack label
72 * @object_label: a pointer to the object's Smack label 112 * @object_label: a pointer to the object's Smack label
@@ -90,7 +130,6 @@ int smk_access(char *subject_label, char *object_label, int request,
90 struct smk_audit_info *a) 130 struct smk_audit_info *a)
91{ 131{
92 u32 may = MAY_NOT; 132 u32 may = MAY_NOT;
93 struct smack_rule *srp;
94 int rc = 0; 133 int rc = 0;
95 134
96 /* 135 /*
@@ -144,18 +183,7 @@ int smk_access(char *subject_label, char *object_label, int request,
144 * access (e.g. read is included in readwrite) it's 183 * access (e.g. read is included in readwrite) it's
145 * good. 184 * good.
146 */ 185 */
147 rcu_read_lock(); 186 may = smk_access_entry(subject_label, object_label);
148 list_for_each_entry_rcu(srp, &smack_rule_list, list) {
149 if (srp->smk_subject == subject_label ||
150 strcmp(srp->smk_subject, subject_label) == 0) {
151 if (srp->smk_object == object_label ||
152 strcmp(srp->smk_object, object_label) == 0) {
153 may = srp->smk_access;
154 break;
155 }
156 }
157 }
158 rcu_read_unlock();
159 /* 187 /*
160 * This is a bit map operation. 188 * This is a bit map operation.
161 */ 189 */
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;
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 01a0be93d8d0..362d5eda948b 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -109,9 +109,12 @@ const char *smack_cipso_option = SMACK_CIPSO_OPTION;
109 * SMK_ACCESSLEN: Maximum length for a rule access field 109 * SMK_ACCESSLEN: Maximum length for a rule access field
110 * SMK_LOADLEN: Smack rule length 110 * SMK_LOADLEN: Smack rule length
111 */ 111 */
112#define SMK_ACCESS "rwxa" 112#define SMK_OACCESS "rwxa"
113#define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1) 113#define SMK_ACCESS "rwxat"
114#define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) 114#define SMK_OACCESSLEN (sizeof(SMK_OACCESS) - 1)
115#define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1)
116#define SMK_OLOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_OACCESSLEN)
117#define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN)
115 118
116/** 119/**
117 * smk_netlabel_audit_set - fill a netlbl_audit struct 120 * smk_netlabel_audit_set - fill a netlbl_audit struct
@@ -175,6 +178,8 @@ static int load_seq_show(struct seq_file *s, void *v)
175 seq_putc(s, 'x'); 178 seq_putc(s, 'x');
176 if (srp->smk_access & MAY_APPEND) 179 if (srp->smk_access & MAY_APPEND)
177 seq_putc(s, 'a'); 180 seq_putc(s, 'a');
181 if (srp->smk_access & MAY_TRANSMUTE)
182 seq_putc(s, 't');
178 if (srp->smk_access == 0) 183 if (srp->smk_access == 0)
179 seq_putc(s, '-'); 184 seq_putc(s, '-');
180 185
@@ -273,10 +278,15 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
273 if (!capable(CAP_MAC_ADMIN)) 278 if (!capable(CAP_MAC_ADMIN))
274 return -EPERM; 279 return -EPERM;
275 280
276 if (*ppos != 0 || count != SMK_LOADLEN) 281 if (*ppos != 0)
282 return -EINVAL;
283 /*
284 * Minor hack for backward compatability
285 */
286 if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN)
277 return -EINVAL; 287 return -EINVAL;
278 288
279 data = kzalloc(count, GFP_KERNEL); 289 data = kzalloc(SMK_LOADLEN, GFP_KERNEL);
280 if (data == NULL) 290 if (data == NULL)
281 return -ENOMEM; 291 return -ENOMEM;
282 292
@@ -285,6 +295,12 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
285 goto out; 295 goto out;
286 } 296 }
287 297
298 /*
299 * More on the minor hack for backward compatability
300 */
301 if (count == (SMK_OLOADLEN))
302 data[SMK_OLOADLEN] = '-';
303
288 rule = kzalloc(sizeof(*rule), GFP_KERNEL); 304 rule = kzalloc(sizeof(*rule), GFP_KERNEL);
289 if (rule == NULL) { 305 if (rule == NULL) {
290 rc = -ENOMEM; 306 rc = -ENOMEM;
@@ -345,6 +361,17 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
345 goto out_free_rule; 361 goto out_free_rule;
346 } 362 }
347 363
364 switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) {
365 case '-':
366 break;
367 case 't':
368 case 'T':
369 rule->smk_access |= MAY_TRANSMUTE;
370 break;
371 default:
372 goto out_free_rule;
373 }
374
348 rc = smk_set_access(rule); 375 rc = smk_set_access(rule);
349 376
350 if (!rc) 377 if (!rc)