diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-30 19:27:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-30 19:27:51 -0400 |
commit | 2e1deaad1e48453cea782854ab87df3f78c121c2 (patch) | |
tree | da0fe592dcc9ef6b0c4cd104a67af3c1d9e4c5d5 /security | |
parent | 50528fabeb25f9883e2845f5147f5e00a1c57cf7 (diff) | |
parent | b7ae9f064bec903bd4a9f257a35da4d1e9bbcc99 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem update from James Morris:
"Just some minor updates across the subsystem"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
ima: eliminate passing d_name.name to process_measurement()
TPM: Retry SaveState command in suspend path
tpm/tpm_i2c_infineon: Add small comment about return value of __i2c_transfer
tpm/tpm_i2c_infineon.c: Add OF attributes type and name to the of_device_id table entries
tpm_i2c_stm_st33: Remove duplicate inclusion of header files
tpm: Add support for new Infineon I2C TPM (SLB 9645 TT 1.2 I2C)
char/tpm: Convert struct i2c_msg initialization to C99 format
drivers/char/tpm/tpm_ppi: use strlcpy instead of strncpy
tpm/tpm_i2c_stm_st33: formatting and white space changes
Smack: include magic.h in smackfs.c
selinux: make security_sb_clone_mnt_opts return an error on context mismatch
seccomp: allow BPF_XOR based ALU instructions.
Fix NULL pointer dereference in smack_inode_unlink() and smack_inode_rmdir()
Smack: add support for modification of existing rules
smack: SMACK_MAGIC to include/uapi/linux/magic.h
Smack: add missing support for transmute bit in smack_str_from_perm()
Smack: prevent revoke-subject from failing when unseen label is written to it
tomoyo: use DEFINE_SRCU() to define tomoyo_ss
tomoyo: use DEFINE_SRCU() to define tomoyo_ss
Diffstat (limited to 'security')
-rw-r--r-- | security/capability.c | 3 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 14 | ||||
-rw-r--r-- | security/security.c | 4 | ||||
-rw-r--r-- | security/selinux/hooks.c | 39 | ||||
-rw-r--r-- | security/smack/smack.h | 5 | ||||
-rw-r--r-- | security/smack/smack_access.c | 2 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 4 | ||||
-rw-r--r-- | security/smack/smackfs.c | 254 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 5 |
9 files changed, 222 insertions, 108 deletions
diff --git a/security/capability.c b/security/capability.c index 6783c3e6c88e..1728d4e375db 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -98,9 +98,10 @@ static int cap_sb_set_mnt_opts(struct super_block *sb, | |||
98 | return 0; | 98 | return 0; |
99 | } | 99 | } |
100 | 100 | ||
101 | static void cap_sb_clone_mnt_opts(const struct super_block *oldsb, | 101 | static int cap_sb_clone_mnt_opts(const struct super_block *oldsb, |
102 | struct super_block *newsb) | 102 | struct super_block *newsb) |
103 | { | 103 | { |
104 | return 0; | ||
104 | } | 105 | } |
105 | 106 | ||
106 | static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts) | 107 | static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts) |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 3b3b7e6bf8da..6c491a63128e 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -189,11 +189,9 @@ static int process_measurement(struct file *file, const char *filename, | |||
189 | if (rc != 0) | 189 | if (rc != 0) |
190 | goto out_digsig; | 190 | goto out_digsig; |
191 | 191 | ||
192 | if (function != BPRM_CHECK) | 192 | pathname = !filename ? ima_d_path(&file->f_path, &pathbuf) : filename; |
193 | pathname = ima_d_path(&file->f_path, &pathbuf); | ||
194 | |||
195 | if (!pathname) | 193 | if (!pathname) |
196 | pathname = filename; | 194 | pathname = (const char *)file->f_dentry->d_name.name; |
197 | 195 | ||
198 | if (action & IMA_MEASURE) | 196 | if (action & IMA_MEASURE) |
199 | ima_store_measurement(iint, file, pathname); | 197 | ima_store_measurement(iint, file, pathname); |
@@ -226,8 +224,7 @@ out: | |||
226 | int ima_file_mmap(struct file *file, unsigned long prot) | 224 | int ima_file_mmap(struct file *file, unsigned long prot) |
227 | { | 225 | { |
228 | if (file && (prot & PROT_EXEC)) | 226 | if (file && (prot & PROT_EXEC)) |
229 | return process_measurement(file, file->f_dentry->d_name.name, | 227 | return process_measurement(file, NULL, MAY_EXEC, MMAP_CHECK); |
230 | MAY_EXEC, MMAP_CHECK); | ||
231 | return 0; | 228 | return 0; |
232 | } | 229 | } |
233 | 230 | ||
@@ -265,7 +262,7 @@ int ima_bprm_check(struct linux_binprm *bprm) | |||
265 | int ima_file_check(struct file *file, int mask) | 262 | int ima_file_check(struct file *file, int mask) |
266 | { | 263 | { |
267 | ima_rdwr_violation_check(file); | 264 | ima_rdwr_violation_check(file); |
268 | return process_measurement(file, file->f_dentry->d_name.name, | 265 | return process_measurement(file, NULL, |
269 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), | 266 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), |
270 | FILE_CHECK); | 267 | FILE_CHECK); |
271 | } | 268 | } |
@@ -290,8 +287,7 @@ int ima_module_check(struct file *file) | |||
290 | #endif | 287 | #endif |
291 | return 0; /* We rely on module signature checking */ | 288 | return 0; /* We rely on module signature checking */ |
292 | } | 289 | } |
293 | return process_measurement(file, file->f_dentry->d_name.name, | 290 | return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK); |
294 | MAY_EXEC, MODULE_CHECK); | ||
295 | } | 291 | } |
296 | 292 | ||
297 | static int __init init_ima(void) | 293 | static int __init init_ima(void) |
diff --git a/security/security.c b/security/security.c index 03f248b84e9f..a3dce87d1aef 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -299,10 +299,10 @@ int security_sb_set_mnt_opts(struct super_block *sb, | |||
299 | } | 299 | } |
300 | EXPORT_SYMBOL(security_sb_set_mnt_opts); | 300 | EXPORT_SYMBOL(security_sb_set_mnt_opts); |
301 | 301 | ||
302 | void security_sb_clone_mnt_opts(const struct super_block *oldsb, | 302 | int security_sb_clone_mnt_opts(const struct super_block *oldsb, |
303 | struct super_block *newsb) | 303 | struct super_block *newsb) |
304 | { | 304 | { |
305 | security_ops->sb_clone_mnt_opts(oldsb, newsb); | 305 | return security_ops->sb_clone_mnt_opts(oldsb, newsb); |
306 | } | 306 | } |
307 | EXPORT_SYMBOL(security_sb_clone_mnt_opts); | 307 | EXPORT_SYMBOL(security_sb_clone_mnt_opts); |
308 | 308 | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7171a957b933..feb2f42c5a07 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -751,7 +751,37 @@ out_double_mount: | |||
751 | goto out; | 751 | goto out; |
752 | } | 752 | } |
753 | 753 | ||
754 | static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | 754 | static int selinux_cmp_sb_context(const struct super_block *oldsb, |
755 | const struct super_block *newsb) | ||
756 | { | ||
757 | struct superblock_security_struct *old = oldsb->s_security; | ||
758 | struct superblock_security_struct *new = newsb->s_security; | ||
759 | char oldflags = old->flags & SE_MNTMASK; | ||
760 | char newflags = new->flags & SE_MNTMASK; | ||
761 | |||
762 | if (oldflags != newflags) | ||
763 | goto mismatch; | ||
764 | if ((oldflags & FSCONTEXT_MNT) && old->sid != new->sid) | ||
765 | goto mismatch; | ||
766 | if ((oldflags & CONTEXT_MNT) && old->mntpoint_sid != new->mntpoint_sid) | ||
767 | goto mismatch; | ||
768 | if ((oldflags & DEFCONTEXT_MNT) && old->def_sid != new->def_sid) | ||
769 | goto mismatch; | ||
770 | if (oldflags & ROOTCONTEXT_MNT) { | ||
771 | struct inode_security_struct *oldroot = oldsb->s_root->d_inode->i_security; | ||
772 | struct inode_security_struct *newroot = newsb->s_root->d_inode->i_security; | ||
773 | if (oldroot->sid != newroot->sid) | ||
774 | goto mismatch; | ||
775 | } | ||
776 | return 0; | ||
777 | mismatch: | ||
778 | printk(KERN_WARNING "SELinux: mount invalid. Same superblock, " | ||
779 | "different security settings for (dev %s, " | ||
780 | "type %s)\n", newsb->s_id, newsb->s_type->name); | ||
781 | return -EBUSY; | ||
782 | } | ||
783 | |||
784 | static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | ||
755 | struct super_block *newsb) | 785 | struct super_block *newsb) |
756 | { | 786 | { |
757 | const struct superblock_security_struct *oldsbsec = oldsb->s_security; | 787 | const struct superblock_security_struct *oldsbsec = oldsb->s_security; |
@@ -766,14 +796,14 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | |||
766 | * mount options. thus we can safely deal with this superblock later | 796 | * mount options. thus we can safely deal with this superblock later |
767 | */ | 797 | */ |
768 | if (!ss_initialized) | 798 | if (!ss_initialized) |
769 | return; | 799 | return 0; |
770 | 800 | ||
771 | /* how can we clone if the old one wasn't set up?? */ | 801 | /* how can we clone if the old one wasn't set up?? */ |
772 | BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED)); | 802 | BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED)); |
773 | 803 | ||
774 | /* if fs is reusing a sb, just let its options stand... */ | 804 | /* if fs is reusing a sb, make sure that the contexts match */ |
775 | if (newsbsec->flags & SE_SBINITIALIZED) | 805 | if (newsbsec->flags & SE_SBINITIALIZED) |
776 | return; | 806 | return selinux_cmp_sb_context(oldsb, newsb); |
777 | 807 | ||
778 | mutex_lock(&newsbsec->lock); | 808 | mutex_lock(&newsbsec->lock); |
779 | 809 | ||
@@ -806,6 +836,7 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | |||
806 | 836 | ||
807 | sb_finish_set_opts(newsb); | 837 | sb_finish_set_opts(newsb); |
808 | mutex_unlock(&newsbsec->lock); | 838 | mutex_unlock(&newsbsec->lock); |
839 | return 0; | ||
809 | } | 840 | } |
810 | 841 | ||
811 | static int selinux_parse_opts_str(char *options, | 842 | static int selinux_parse_opts_str(char *options, |
diff --git a/security/smack/smack.h b/security/smack/smack.h index 99b36124f712..8ad30955e15d 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -149,11 +149,6 @@ struct smack_known { | |||
149 | #define SMACK_CIPSO_SOCKET 1 | 149 | #define SMACK_CIPSO_SOCKET 1 |
150 | 150 | ||
151 | /* | 151 | /* |
152 | * smackfs magic number | ||
153 | */ | ||
154 | #define SMACK_MAGIC 0x43415d53 /* "SMAC" */ | ||
155 | |||
156 | /* | ||
157 | * CIPSO defaults. | 152 | * CIPSO defaults. |
158 | */ | 153 | */ |
159 | #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ | 154 | #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index db14689a21e0..2e397a88d410 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -252,6 +252,8 @@ static inline void smack_str_from_perm(char *string, int access) | |||
252 | string[i++] = 'x'; | 252 | string[i++] = 'x'; |
253 | if (access & MAY_APPEND) | 253 | if (access & MAY_APPEND) |
254 | string[i++] = 'a'; | 254 | string[i++] = 'a'; |
255 | if (access & MAY_TRANSMUTE) | ||
256 | string[i++] = 't'; | ||
255 | string[i] = '\0'; | 257 | string[i] = '\0'; |
256 | } | 258 | } |
257 | /** | 259 | /** |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index fa64740abb59..d52c780bdb78 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -654,7 +654,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) | |||
654 | /* | 654 | /* |
655 | * You also need write access to the containing directory | 655 | * You also need write access to the containing directory |
656 | */ | 656 | */ |
657 | smk_ad_setfield_u_fs_path_dentry(&ad, NULL); | 657 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); |
658 | smk_ad_setfield_u_fs_inode(&ad, dir); | 658 | smk_ad_setfield_u_fs_inode(&ad, dir); |
659 | rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); | 659 | rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); |
660 | } | 660 | } |
@@ -685,7 +685,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) | |||
685 | /* | 685 | /* |
686 | * You also need write access to the containing directory | 686 | * You also need write access to the containing directory |
687 | */ | 687 | */ |
688 | smk_ad_setfield_u_fs_path_dentry(&ad, NULL); | 688 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); |
689 | smk_ad_setfield_u_fs_inode(&ad, dir); | 689 | smk_ad_setfield_u_fs_inode(&ad, dir); |
690 | rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); | 690 | rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); |
691 | } | 691 | } |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 76a5dca46404..53a08b85bda4 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/seq_file.h> | 26 | #include <linux/seq_file.h> |
27 | #include <linux/ctype.h> | 27 | #include <linux/ctype.h> |
28 | #include <linux/audit.h> | 28 | #include <linux/audit.h> |
29 | #include <linux/magic.h> | ||
29 | #include "smack.h" | 30 | #include "smack.h" |
30 | 31 | ||
31 | /* | 32 | /* |
@@ -50,12 +51,12 @@ enum smk_inos { | |||
50 | SMK_ACCESS2 = 16, /* make an access check with long labels */ | 51 | SMK_ACCESS2 = 16, /* make an access check with long labels */ |
51 | SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ | 52 | SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ |
52 | SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */ | 53 | SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */ |
54 | SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */ | ||
53 | }; | 55 | }; |
54 | 56 | ||
55 | /* | 57 | /* |
56 | * List locks | 58 | * List locks |
57 | */ | 59 | */ |
58 | static DEFINE_MUTEX(smack_list_lock); | ||
59 | static DEFINE_MUTEX(smack_cipso_lock); | 60 | static DEFINE_MUTEX(smack_cipso_lock); |
60 | static DEFINE_MUTEX(smack_ambient_lock); | 61 | static DEFINE_MUTEX(smack_ambient_lock); |
61 | static DEFINE_MUTEX(smk_netlbladdr_lock); | 62 | static DEFINE_MUTEX(smk_netlbladdr_lock); |
@@ -110,6 +111,13 @@ struct smack_master_list { | |||
110 | 111 | ||
111 | LIST_HEAD(smack_rule_list); | 112 | LIST_HEAD(smack_rule_list); |
112 | 113 | ||
114 | struct smack_parsed_rule { | ||
115 | char *smk_subject; | ||
116 | char *smk_object; | ||
117 | int smk_access1; | ||
118 | int smk_access2; | ||
119 | }; | ||
120 | |||
113 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; | 121 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; |
114 | 122 | ||
115 | const char *smack_cipso_option = SMACK_CIPSO_OPTION; | 123 | const char *smack_cipso_option = SMACK_CIPSO_OPTION; |
@@ -167,25 +175,28 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap) | |||
167 | #define SMK_NETLBLADDRMIN 9 | 175 | #define SMK_NETLBLADDRMIN 9 |
168 | 176 | ||
169 | /** | 177 | /** |
170 | * smk_set_access - add a rule to the rule list | 178 | * smk_set_access - add a rule to the rule list or replace an old rule |
171 | * @srp: the new rule to add | 179 | * @srp: the rule to add or replace |
172 | * @rule_list: the list of rules | 180 | * @rule_list: the list of rules |
173 | * @rule_lock: the rule list lock | 181 | * @rule_lock: the rule list lock |
182 | * @global: if non-zero, indicates a global rule | ||
174 | * | 183 | * |
175 | * Looks through the current subject/object/access list for | 184 | * Looks through the current subject/object/access list for |
176 | * the subject/object pair and replaces the access that was | 185 | * the subject/object pair and replaces the access that was |
177 | * there. If the pair isn't found add it with the specified | 186 | * there. If the pair isn't found add it with the specified |
178 | * access. | 187 | * access. |
179 | * | 188 | * |
180 | * Returns 1 if a rule was found to exist already, 0 if it is new | ||
181 | * Returns 0 if nothing goes wrong or -ENOMEM if it fails | 189 | * Returns 0 if nothing goes wrong or -ENOMEM if it fails |
182 | * during the allocation of the new pair to add. | 190 | * during the allocation of the new pair to add. |
183 | */ | 191 | */ |
184 | static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list, | 192 | static int smk_set_access(struct smack_parsed_rule *srp, |
185 | struct mutex *rule_lock) | 193 | struct list_head *rule_list, |
194 | struct mutex *rule_lock, int global) | ||
186 | { | 195 | { |
187 | struct smack_rule *sp; | 196 | struct smack_rule *sp; |
197 | struct smack_master_list *smlp; | ||
188 | int found = 0; | 198 | int found = 0; |
199 | int rc = 0; | ||
189 | 200 | ||
190 | mutex_lock(rule_lock); | 201 | mutex_lock(rule_lock); |
191 | 202 | ||
@@ -197,23 +208,89 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list, | |||
197 | if (sp->smk_object == srp->smk_object && | 208 | if (sp->smk_object == srp->smk_object && |
198 | sp->smk_subject == srp->smk_subject) { | 209 | sp->smk_subject == srp->smk_subject) { |
199 | found = 1; | 210 | found = 1; |
200 | sp->smk_access = srp->smk_access; | 211 | sp->smk_access |= srp->smk_access1; |
212 | sp->smk_access &= ~srp->smk_access2; | ||
201 | break; | 213 | break; |
202 | } | 214 | } |
203 | } | 215 | } |
204 | if (found == 0) | ||
205 | list_add_rcu(&srp->list, rule_list); | ||
206 | 216 | ||
217 | if (found == 0) { | ||
218 | sp = kzalloc(sizeof(*sp), GFP_KERNEL); | ||
219 | if (sp == NULL) { | ||
220 | rc = -ENOMEM; | ||
221 | goto out; | ||
222 | } | ||
223 | |||
224 | sp->smk_subject = srp->smk_subject; | ||
225 | sp->smk_object = srp->smk_object; | ||
226 | sp->smk_access = srp->smk_access1 & ~srp->smk_access2; | ||
227 | |||
228 | list_add_rcu(&sp->list, rule_list); | ||
229 | /* | ||
230 | * If this is a global as opposed to self and a new rule | ||
231 | * it needs to get added for reporting. | ||
232 | */ | ||
233 | if (global) { | ||
234 | smlp = kzalloc(sizeof(*smlp), GFP_KERNEL); | ||
235 | if (smlp != NULL) { | ||
236 | smlp->smk_rule = sp; | ||
237 | list_add_rcu(&smlp->list, &smack_rule_list); | ||
238 | } else | ||
239 | rc = -ENOMEM; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | out: | ||
207 | mutex_unlock(rule_lock); | 244 | mutex_unlock(rule_lock); |
245 | return rc; | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * smk_perm_from_str - parse smack accesses from a text string | ||
250 | * @string: a text string that contains a Smack accesses code | ||
251 | * | ||
252 | * Returns an integer with respective bits set for specified accesses. | ||
253 | */ | ||
254 | static int smk_perm_from_str(const char *string) | ||
255 | { | ||
256 | int perm = 0; | ||
257 | const char *cp; | ||
208 | 258 | ||
209 | return found; | 259 | for (cp = string; ; cp++) |
260 | switch (*cp) { | ||
261 | case '-': | ||
262 | break; | ||
263 | case 'r': | ||
264 | case 'R': | ||
265 | perm |= MAY_READ; | ||
266 | break; | ||
267 | case 'w': | ||
268 | case 'W': | ||
269 | perm |= MAY_WRITE; | ||
270 | break; | ||
271 | case 'x': | ||
272 | case 'X': | ||
273 | perm |= MAY_EXEC; | ||
274 | break; | ||
275 | case 'a': | ||
276 | case 'A': | ||
277 | perm |= MAY_APPEND; | ||
278 | break; | ||
279 | case 't': | ||
280 | case 'T': | ||
281 | perm |= MAY_TRANSMUTE; | ||
282 | break; | ||
283 | default: | ||
284 | return perm; | ||
285 | } | ||
210 | } | 286 | } |
211 | 287 | ||
212 | /** | 288 | /** |
213 | * smk_fill_rule - Fill Smack rule from strings | 289 | * smk_fill_rule - Fill Smack rule from strings |
214 | * @subject: subject label string | 290 | * @subject: subject label string |
215 | * @object: object label string | 291 | * @object: object label string |
216 | * @access: access string | 292 | * @access1: access string |
293 | * @access2: string with permissions to be removed | ||
217 | * @rule: Smack rule | 294 | * @rule: Smack rule |
218 | * @import: if non-zero, import labels | 295 | * @import: if non-zero, import labels |
219 | * @len: label length limit | 296 | * @len: label length limit |
@@ -221,8 +298,9 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list, | |||
221 | * Returns 0 on success, -1 on failure | 298 | * Returns 0 on success, -1 on failure |
222 | */ | 299 | */ |
223 | static int smk_fill_rule(const char *subject, const char *object, | 300 | static int smk_fill_rule(const char *subject, const char *object, |
224 | const char *access, struct smack_rule *rule, | 301 | const char *access1, const char *access2, |
225 | int import, int len) | 302 | struct smack_parsed_rule *rule, int import, |
303 | int len) | ||
226 | { | 304 | { |
227 | const char *cp; | 305 | const char *cp; |
228 | struct smack_known *skp; | 306 | struct smack_known *skp; |
@@ -255,36 +333,11 @@ static int smk_fill_rule(const char *subject, const char *object, | |||
255 | rule->smk_object = skp->smk_known; | 333 | rule->smk_object = skp->smk_known; |
256 | } | 334 | } |
257 | 335 | ||
258 | rule->smk_access = 0; | 336 | rule->smk_access1 = smk_perm_from_str(access1); |
259 | 337 | if (access2) | |
260 | for (cp = access; *cp != '\0'; cp++) { | 338 | rule->smk_access2 = smk_perm_from_str(access2); |
261 | switch (*cp) { | 339 | else |
262 | case '-': | 340 | rule->smk_access2 = ~rule->smk_access1; |
263 | break; | ||
264 | case 'r': | ||
265 | case 'R': | ||
266 | rule->smk_access |= MAY_READ; | ||
267 | break; | ||
268 | case 'w': | ||
269 | case 'W': | ||
270 | rule->smk_access |= MAY_WRITE; | ||
271 | break; | ||
272 | case 'x': | ||
273 | case 'X': | ||
274 | rule->smk_access |= MAY_EXEC; | ||
275 | break; | ||
276 | case 'a': | ||
277 | case 'A': | ||
278 | rule->smk_access |= MAY_APPEND; | ||
279 | break; | ||
280 | case 't': | ||
281 | case 'T': | ||
282 | rule->smk_access |= MAY_TRANSMUTE; | ||
283 | break; | ||
284 | default: | ||
285 | return 0; | ||
286 | } | ||
287 | } | ||
288 | 341 | ||
289 | return 0; | 342 | return 0; |
290 | } | 343 | } |
@@ -297,30 +350,33 @@ static int smk_fill_rule(const char *subject, const char *object, | |||
297 | * | 350 | * |
298 | * Returns 0 on success, -1 on errors. | 351 | * Returns 0 on success, -1 on errors. |
299 | */ | 352 | */ |
300 | static int smk_parse_rule(const char *data, struct smack_rule *rule, int import) | 353 | static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule, |
354 | int import) | ||
301 | { | 355 | { |
302 | int rc; | 356 | int rc; |
303 | 357 | ||
304 | rc = smk_fill_rule(data, data + SMK_LABELLEN, | 358 | rc = smk_fill_rule(data, data + SMK_LABELLEN, |
305 | data + SMK_LABELLEN + SMK_LABELLEN, rule, import, | 359 | data + SMK_LABELLEN + SMK_LABELLEN, NULL, rule, |
306 | SMK_LABELLEN); | 360 | import, SMK_LABELLEN); |
307 | return rc; | 361 | return rc; |
308 | } | 362 | } |
309 | 363 | ||
310 | /** | 364 | /** |
311 | * smk_parse_long_rule - parse Smack rule from rule string | 365 | * smk_parse_long_rule - parse Smack rule from rule string |
312 | * @data: string to be parsed, null terminated | 366 | * @data: string to be parsed, null terminated |
313 | * @rule: Smack rule | 367 | * @rule: Will be filled with Smack parsed rule |
314 | * @import: if non-zero, import labels | 368 | * @import: if non-zero, import labels |
369 | * @change: if non-zero, data is from /smack/change-rule | ||
315 | * | 370 | * |
316 | * Returns 0 on success, -1 on failure | 371 | * Returns 0 on success, -1 on failure |
317 | */ | 372 | */ |
318 | static int smk_parse_long_rule(const char *data, struct smack_rule *rule, | 373 | static int smk_parse_long_rule(const char *data, struct smack_parsed_rule *rule, |
319 | int import) | 374 | int import, int change) |
320 | { | 375 | { |
321 | char *subject; | 376 | char *subject; |
322 | char *object; | 377 | char *object; |
323 | char *access; | 378 | char *access1; |
379 | char *access2; | ||
324 | int datalen; | 380 | int datalen; |
325 | int rc = -1; | 381 | int rc = -1; |
326 | 382 | ||
@@ -334,14 +390,27 @@ static int smk_parse_long_rule(const char *data, struct smack_rule *rule, | |||
334 | object = kzalloc(datalen, GFP_KERNEL); | 390 | object = kzalloc(datalen, GFP_KERNEL); |
335 | if (object == NULL) | 391 | if (object == NULL) |
336 | goto free_out_s; | 392 | goto free_out_s; |
337 | access = kzalloc(datalen, GFP_KERNEL); | 393 | access1 = kzalloc(datalen, GFP_KERNEL); |
338 | if (access == NULL) | 394 | if (access1 == NULL) |
339 | goto free_out_o; | 395 | goto free_out_o; |
396 | access2 = kzalloc(datalen, GFP_KERNEL); | ||
397 | if (access2 == NULL) | ||
398 | goto free_out_a; | ||
399 | |||
400 | if (change) { | ||
401 | if (sscanf(data, "%s %s %s %s", | ||
402 | subject, object, access1, access2) == 4) | ||
403 | rc = smk_fill_rule(subject, object, access1, access2, | ||
404 | rule, import, 0); | ||
405 | } else { | ||
406 | if (sscanf(data, "%s %s %s", subject, object, access1) == 3) | ||
407 | rc = smk_fill_rule(subject, object, access1, NULL, | ||
408 | rule, import, 0); | ||
409 | } | ||
340 | 410 | ||
341 | if (sscanf(data, "%s %s %s", subject, object, access) == 3) | 411 | kfree(access2); |
342 | rc = smk_fill_rule(subject, object, access, rule, import, 0); | 412 | free_out_a: |
343 | 413 | kfree(access1); | |
344 | kfree(access); | ||
345 | free_out_o: | 414 | free_out_o: |
346 | kfree(object); | 415 | kfree(object); |
347 | free_out_s: | 416 | free_out_s: |
@@ -351,6 +420,7 @@ free_out_s: | |||
351 | 420 | ||
352 | #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ | 421 | #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ |
353 | #define SMK_LONG_FMT 1 /* Variable long label format */ | 422 | #define SMK_LONG_FMT 1 /* Variable long label format */ |
423 | #define SMK_CHANGE_FMT 2 /* Rule modification format */ | ||
354 | /** | 424 | /** |
355 | * smk_write_rules_list - write() for any /smack rule file | 425 | * smk_write_rules_list - write() for any /smack rule file |
356 | * @file: file pointer, not actually used | 426 | * @file: file pointer, not actually used |
@@ -359,22 +429,24 @@ free_out_s: | |||
359 | * @ppos: where to start - must be 0 | 429 | * @ppos: where to start - must be 0 |
360 | * @rule_list: the list of rules to write to | 430 | * @rule_list: the list of rules to write to |
361 | * @rule_lock: lock for the rule list | 431 | * @rule_lock: lock for the rule list |
362 | * @format: /smack/load or /smack/load2 format. | 432 | * @format: /smack/load or /smack/load2 or /smack/change-rule format. |
363 | * | 433 | * |
364 | * Get one smack access rule from above. | 434 | * Get one smack access rule from above. |
365 | * The format for SMK_LONG_FMT is: | 435 | * The format for SMK_LONG_FMT is: |
366 | * "subject<whitespace>object<whitespace>access[<whitespace>...]" | 436 | * "subject<whitespace>object<whitespace>access[<whitespace>...]" |
367 | * The format for SMK_FIXED24_FMT is exactly: | 437 | * The format for SMK_FIXED24_FMT is exactly: |
368 | * "subject object rwxat" | 438 | * "subject object rwxat" |
439 | * The format for SMK_CHANGE_FMT is: | ||
440 | * "subject<whitespace>object<whitespace> | ||
441 | * acc_enable<whitespace>acc_disable[<whitespace>...]" | ||
369 | */ | 442 | */ |
370 | static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, | 443 | static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, |
371 | size_t count, loff_t *ppos, | 444 | size_t count, loff_t *ppos, |
372 | struct list_head *rule_list, | 445 | struct list_head *rule_list, |
373 | struct mutex *rule_lock, int format) | 446 | struct mutex *rule_lock, int format) |
374 | { | 447 | { |
375 | struct smack_master_list *smlp; | ||
376 | struct smack_known *skp; | 448 | struct smack_known *skp; |
377 | struct smack_rule *rule; | 449 | struct smack_parsed_rule *rule; |
378 | char *data; | 450 | char *data; |
379 | int datalen; | 451 | int datalen; |
380 | int rc = -EINVAL; | 452 | int rc = -EINVAL; |
@@ -417,7 +489,11 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, | |||
417 | * Be sure the data string is terminated. | 489 | * Be sure the data string is terminated. |
418 | */ | 490 | */ |
419 | data[count] = '\0'; | 491 | data[count] = '\0'; |
420 | if (smk_parse_long_rule(data, rule, 1)) | 492 | if (smk_parse_long_rule(data, rule, 1, 0)) |
493 | goto out_free_rule; | ||
494 | } else if (format == SMK_CHANGE_FMT) { | ||
495 | data[count] = '\0'; | ||
496 | if (smk_parse_long_rule(data, rule, 1, 1)) | ||
421 | goto out_free_rule; | 497 | goto out_free_rule; |
422 | } else { | 498 | } else { |
423 | /* | 499 | /* |
@@ -437,22 +513,9 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, | |||
437 | rule_lock = &skp->smk_rules_lock; | 513 | rule_lock = &skp->smk_rules_lock; |
438 | } | 514 | } |
439 | 515 | ||
440 | rc = count; | 516 | rc = smk_set_access(rule, rule_list, rule_lock, load); |
441 | /* | 517 | if (rc == 0) { |
442 | * If this is a global as opposed to self and a new rule | 518 | rc = count; |
443 | * it needs to get added for reporting. | ||
444 | * smk_set_access returns true if there was already a rule | ||
445 | * for the subject/object pair, and false if it was new. | ||
446 | */ | ||
447 | if (!smk_set_access(rule, rule_list, rule_lock)) { | ||
448 | if (load) { | ||
449 | smlp = kzalloc(sizeof(*smlp), GFP_KERNEL); | ||
450 | if (smlp != NULL) { | ||
451 | smlp->smk_rule = rule; | ||
452 | list_add_rcu(&smlp->list, &smack_rule_list); | ||
453 | } else | ||
454 | rc = -ENOMEM; | ||
455 | } | ||
456 | goto out; | 519 | goto out; |
457 | } | 520 | } |
458 | 521 | ||
@@ -1774,7 +1837,7 @@ static const struct file_operations smk_load_self_ops = { | |||
1774 | static ssize_t smk_user_access(struct file *file, const char __user *buf, | 1837 | static ssize_t smk_user_access(struct file *file, const char __user *buf, |
1775 | size_t count, loff_t *ppos, int format) | 1838 | size_t count, loff_t *ppos, int format) |
1776 | { | 1839 | { |
1777 | struct smack_rule rule; | 1840 | struct smack_parsed_rule rule; |
1778 | char *data; | 1841 | char *data; |
1779 | char *cod; | 1842 | char *cod; |
1780 | int res; | 1843 | int res; |
@@ -1796,14 +1859,14 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, | |||
1796 | return -ENOMEM; | 1859 | return -ENOMEM; |
1797 | memcpy(cod, data, count); | 1860 | memcpy(cod, data, count); |
1798 | cod[count] = '\0'; | 1861 | cod[count] = '\0'; |
1799 | res = smk_parse_long_rule(cod, &rule, 0); | 1862 | res = smk_parse_long_rule(cod, &rule, 0, 0); |
1800 | kfree(cod); | 1863 | kfree(cod); |
1801 | } | 1864 | } |
1802 | 1865 | ||
1803 | if (res) | 1866 | if (res) |
1804 | return -EINVAL; | 1867 | return -EINVAL; |
1805 | 1868 | ||
1806 | res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access, | 1869 | res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access1, |
1807 | NULL); | 1870 | NULL); |
1808 | data[0] = res == 0 ? '1' : '0'; | 1871 | data[0] = res == 0 ? '1' : '0'; |
1809 | data[1] = '\0'; | 1872 | data[1] = '\0'; |
@@ -2035,10 +2098,8 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf, | |||
2035 | } | 2098 | } |
2036 | 2099 | ||
2037 | skp = smk_find_entry(cp); | 2100 | skp = smk_find_entry(cp); |
2038 | if (skp == NULL) { | 2101 | if (skp == NULL) |
2039 | rc = -EINVAL; | ||
2040 | goto free_out; | 2102 | goto free_out; |
2041 | } | ||
2042 | 2103 | ||
2043 | rule_list = &skp->smk_rules; | 2104 | rule_list = &skp->smk_rules; |
2044 | rule_lock = &skp->smk_rules_lock; | 2105 | rule_lock = &skp->smk_rules_lock; |
@@ -2077,6 +2138,33 @@ static int smk_init_sysfs(void) | |||
2077 | } | 2138 | } |
2078 | 2139 | ||
2079 | /** | 2140 | /** |
2141 | * smk_write_change_rule - write() for /smack/change-rule | ||
2142 | * @file: file pointer | ||
2143 | * @buf: data from user space | ||
2144 | * @count: bytes sent | ||
2145 | * @ppos: where to start - must be 0 | ||
2146 | */ | ||
2147 | static ssize_t smk_write_change_rule(struct file *file, const char __user *buf, | ||
2148 | size_t count, loff_t *ppos) | ||
2149 | { | ||
2150 | /* | ||
2151 | * Must have privilege. | ||
2152 | */ | ||
2153 | if (!capable(CAP_MAC_ADMIN)) | ||
2154 | return -EPERM; | ||
2155 | |||
2156 | return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, | ||
2157 | SMK_CHANGE_FMT); | ||
2158 | } | ||
2159 | |||
2160 | static const struct file_operations smk_change_rule_ops = { | ||
2161 | .write = smk_write_change_rule, | ||
2162 | .read = simple_transaction_read, | ||
2163 | .release = simple_transaction_release, | ||
2164 | .llseek = generic_file_llseek, | ||
2165 | }; | ||
2166 | |||
2167 | /** | ||
2080 | * smk_fill_super - fill the /smackfs superblock | 2168 | * smk_fill_super - fill the /smackfs superblock |
2081 | * @sb: the empty superblock | 2169 | * @sb: the empty superblock |
2082 | * @data: unused | 2170 | * @data: unused |
@@ -2125,6 +2213,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
2125 | [SMK_REVOKE_SUBJ] = { | 2213 | [SMK_REVOKE_SUBJ] = { |
2126 | "revoke-subject", &smk_revoke_subj_ops, | 2214 | "revoke-subject", &smk_revoke_subj_ops, |
2127 | S_IRUGO|S_IWUSR}, | 2215 | S_IRUGO|S_IWUSR}, |
2216 | [SMK_CHANGE_RULE] = { | ||
2217 | "change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR}, | ||
2128 | /* last one */ | 2218 | /* last one */ |
2129 | {""} | 2219 | {""} |
2130 | }; | 2220 | }; |
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index a2ee362546ab..f0b756e27fed 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -536,7 +536,7 @@ static struct security_operations tomoyo_security_ops = { | |||
536 | }; | 536 | }; |
537 | 537 | ||
538 | /* Lock for GC. */ | 538 | /* Lock for GC. */ |
539 | struct srcu_struct tomoyo_ss; | 539 | DEFINE_SRCU(tomoyo_ss); |
540 | 540 | ||
541 | /** | 541 | /** |
542 | * tomoyo_init - Register TOMOYO Linux as a LSM module. | 542 | * tomoyo_init - Register TOMOYO Linux as a LSM module. |
@@ -550,8 +550,7 @@ static int __init tomoyo_init(void) | |||
550 | if (!security_module_enable(&tomoyo_security_ops)) | 550 | if (!security_module_enable(&tomoyo_security_ops)) |
551 | return 0; | 551 | return 0; |
552 | /* register ourselves with the security framework */ | 552 | /* register ourselves with the security framework */ |
553 | if (register_security(&tomoyo_security_ops) || | 553 | if (register_security(&tomoyo_security_ops)) |
554 | init_srcu_struct(&tomoyo_ss)) | ||
555 | panic("Failure registering TOMOYO Linux"); | 554 | panic("Failure registering TOMOYO Linux"); |
556 | printk(KERN_INFO "TOMOYO Linux initialized\n"); | 555 | printk(KERN_INFO "TOMOYO Linux initialized\n"); |
557 | cred->security = &tomoyo_kernel_domain; | 556 | cred->security = &tomoyo_kernel_domain; |