aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/xattr.h2
-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
5 files changed, 141 insertions, 43 deletions
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index 351c7901d74a..e6131ef98d8f 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -41,10 +41,12 @@
41#define XATTR_SMACK_IPIN "SMACK64IPIN" 41#define XATTR_SMACK_IPIN "SMACK64IPIN"
42#define XATTR_SMACK_IPOUT "SMACK64IPOUT" 42#define XATTR_SMACK_IPOUT "SMACK64IPOUT"
43#define XATTR_SMACK_EXEC "SMACK64EXEC" 43#define XATTR_SMACK_EXEC "SMACK64EXEC"
44#define XATTR_SMACK_TRANSMUTE "SMACK64TRANSMUTE"
44#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX 45#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
45#define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN 46#define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
46#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT 47#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
47#define XATTR_NAME_SMACKEXEC XATTR_SECURITY_PREFIX XATTR_SMACK_EXEC 48#define XATTR_NAME_SMACKEXEC XATTR_SECURITY_PREFIX XATTR_SMACK_EXEC
49#define XATTR_NAME_SMACKTRANSMUTE XATTR_SECURITY_PREFIX XATTR_SMACK_TRANSMUTE
48 50
49#define XATTR_CAPS_SUFFIX "capability" 51#define XATTR_CAPS_SUFFIX "capability"
50#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX 52#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
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)