aboutsummaryrefslogtreecommitdiffstats
path: root/security/smack/smackfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/smack/smackfs.c')
-rw-r--r--security/smack/smackfs.c180
1 files changed, 101 insertions, 79 deletions
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index a1b57e4dba3e..856c8a287523 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -80,10 +80,11 @@ char *smack_onlycap;
80 * Packets are sent there unlabeled, but only from tasks that 80 * Packets are sent there unlabeled, but only from tasks that
81 * can write to the specified label. 81 * can write to the specified label.
82 */ 82 */
83struct smk_netlbladdr *smack_netlbladdrs; 83
84LIST_HEAD(smk_netlbladdr_list);
85LIST_HEAD(smack_rule_list);
84 86
85static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; 87static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
86struct smk_list_entry *smack_list;
87 88
88#define SEQ_READ_FINISHED 1 89#define SEQ_READ_FINISHED 1
89 90
@@ -134,24 +135,27 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos)
134{ 135{
135 if (*pos == SEQ_READ_FINISHED) 136 if (*pos == SEQ_READ_FINISHED)
136 return NULL; 137 return NULL;
137 138 if (list_empty(&smack_rule_list))
138 return smack_list; 139 return NULL;
140 return smack_rule_list.next;
139} 141}
140 142
141static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos) 143static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
142{ 144{
143 struct smk_list_entry *skp = ((struct smk_list_entry *) v)->smk_next; 145 struct list_head *list = v;
144 146
145 if (skp == NULL) 147 if (list_is_last(list, &smack_rule_list)) {
146 *pos = SEQ_READ_FINISHED; 148 *pos = SEQ_READ_FINISHED;
147 149 return NULL;
148 return skp; 150 }
151 return list->next;
149} 152}
150 153
151static int load_seq_show(struct seq_file *s, void *v) 154static int load_seq_show(struct seq_file *s, void *v)
152{ 155{
153 struct smk_list_entry *slp = (struct smk_list_entry *) v; 156 struct list_head *list = v;
154 struct smack_rule *srp = &slp->smk_rule; 157 struct smack_rule *srp =
158 list_entry(list, struct smack_rule, list);
155 159
156 seq_printf(s, "%s %s", (char *)srp->smk_subject, 160 seq_printf(s, "%s %s", (char *)srp->smk_subject,
157 (char *)srp->smk_object); 161 (char *)srp->smk_object);
@@ -212,32 +216,23 @@ static int smk_open_load(struct inode *inode, struct file *file)
212 */ 216 */
213static int smk_set_access(struct smack_rule *srp) 217static int smk_set_access(struct smack_rule *srp)
214{ 218{
215 struct smk_list_entry *sp; 219 struct smack_rule *sp;
216 struct smk_list_entry *newp;
217 int ret = 0; 220 int ret = 0;
218 221 int found;
219 mutex_lock(&smack_list_lock); 222 mutex_lock(&smack_list_lock);
220 223
221 for (sp = smack_list; sp != NULL; sp = sp->smk_next) 224 found = 0;
222 if (sp->smk_rule.smk_subject == srp->smk_subject && 225 list_for_each_entry_rcu(sp, &smack_rule_list, list) {
223 sp->smk_rule.smk_object == srp->smk_object) { 226 if (sp->smk_subject == srp->smk_subject &&
224 sp->smk_rule.smk_access = srp->smk_access; 227 sp->smk_object == srp->smk_object) {
228 found = 1;
229 sp->smk_access = srp->smk_access;
225 break; 230 break;
226 } 231 }
227
228 if (sp == NULL) {
229 newp = kzalloc(sizeof(struct smk_list_entry), GFP_KERNEL);
230 if (newp == NULL) {
231 ret = -ENOMEM;
232 goto out;
233 }
234
235 newp->smk_rule = *srp;
236 newp->smk_next = smack_list;
237 smack_list = newp;
238 } 232 }
233 if (found == 0)
234 list_add_rcu(&srp->list, &smack_rule_list);
239 235
240out:
241 mutex_unlock(&smack_list_lock); 236 mutex_unlock(&smack_list_lock);
242 237
243 return ret; 238 return ret;
@@ -261,7 +256,7 @@ out:
261static ssize_t smk_write_load(struct file *file, const char __user *buf, 256static ssize_t smk_write_load(struct file *file, const char __user *buf,
262 size_t count, loff_t *ppos) 257 size_t count, loff_t *ppos)
263{ 258{
264 struct smack_rule rule; 259 struct smack_rule *rule;
265 char *data; 260 char *data;
266 int rc = -EINVAL; 261 int rc = -EINVAL;
267 262
@@ -272,9 +267,8 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
272 */ 267 */
273 if (!capable(CAP_MAC_ADMIN)) 268 if (!capable(CAP_MAC_ADMIN))
274 return -EPERM; 269 return -EPERM;
275 if (*ppos != 0) 270
276 return -EINVAL; 271 if (*ppos != 0 || count != SMK_LOADLEN)
277 if (count != SMK_LOADLEN)
278 return -EINVAL; 272 return -EINVAL;
279 273
280 data = kzalloc(count, GFP_KERNEL); 274 data = kzalloc(count, GFP_KERNEL);
@@ -286,25 +280,31 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
286 goto out; 280 goto out;
287 } 281 }
288 282
289 rule.smk_subject = smk_import(data, 0); 283 rule = kzalloc(sizeof(*rule), GFP_KERNEL);
290 if (rule.smk_subject == NULL) 284 if (rule == NULL) {
285 rc = -ENOMEM;
291 goto out; 286 goto out;
287 }
292 288
293 rule.smk_object = smk_import(data + SMK_LABELLEN, 0); 289 rule->smk_subject = smk_import(data, 0);
294 if (rule.smk_object == NULL) 290 if (rule->smk_subject == NULL)
295 goto out; 291 goto out_free_rule;
296 292
297 rule.smk_access = 0; 293 rule->smk_object = smk_import(data + SMK_LABELLEN, 0);
294 if (rule->smk_object == NULL)
295 goto out_free_rule;
296
297 rule->smk_access = 0;
298 298
299 switch (data[SMK_LABELLEN + SMK_LABELLEN]) { 299 switch (data[SMK_LABELLEN + SMK_LABELLEN]) {
300 case '-': 300 case '-':
301 break; 301 break;
302 case 'r': 302 case 'r':
303 case 'R': 303 case 'R':
304 rule.smk_access |= MAY_READ; 304 rule->smk_access |= MAY_READ;
305 break; 305 break;
306 default: 306 default:
307 goto out; 307 goto out_free_rule;
308 } 308 }
309 309
310 switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { 310 switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
@@ -312,10 +312,10 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
312 break; 312 break;
313 case 'w': 313 case 'w':
314 case 'W': 314 case 'W':
315 rule.smk_access |= MAY_WRITE; 315 rule->smk_access |= MAY_WRITE;
316 break; 316 break;
317 default: 317 default:
318 goto out; 318 goto out_free_rule;
319 } 319 }
320 320
321 switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { 321 switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
@@ -323,10 +323,10 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
323 break; 323 break;
324 case 'x': 324 case 'x':
325 case 'X': 325 case 'X':
326 rule.smk_access |= MAY_EXEC; 326 rule->smk_access |= MAY_EXEC;
327 break; 327 break;
328 default: 328 default:
329 goto out; 329 goto out_free_rule;
330 } 330 }
331 331
332 switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { 332 switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
@@ -334,17 +334,20 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
334 break; 334 break;
335 case 'a': 335 case 'a':
336 case 'A': 336 case 'A':
337 rule.smk_access |= MAY_APPEND; 337 rule->smk_access |= MAY_APPEND;
338 break; 338 break;
339 default: 339 default:
340 goto out; 340 goto out_free_rule;
341 } 341 }
342 342
343 rc = smk_set_access(&rule); 343 rc = smk_set_access(rule);
344 344
345 if (!rc) 345 if (!rc)
346 rc = count; 346 rc = count;
347 goto out;
347 348
349out_free_rule:
350 kfree(rule);
348out: 351out:
349 kfree(data); 352 kfree(data);
350 return rc; 353 return rc;
@@ -433,24 +436,26 @@ static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
433{ 436{
434 if (*pos == SEQ_READ_FINISHED) 437 if (*pos == SEQ_READ_FINISHED)
435 return NULL; 438 return NULL;
439 if (list_empty(&smack_known_list))
440 return NULL;
436 441
437 return smack_known; 442 return smack_known_list.next;
438} 443}
439 444
440static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos) 445static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
441{ 446{
442 struct smack_known *skp = ((struct smack_known *) v)->smk_next; 447 struct list_head *list = v;
443 448
444 /* 449 /*
445 * Omit labels with no associated cipso value 450 * labels with no associated cipso value wont be printed
451 * in cipso_seq_show
446 */ 452 */
447 while (skp != NULL && !skp->smk_cipso) 453 if (list_is_last(list, &smack_known_list)) {
448 skp = skp->smk_next;
449
450 if (skp == NULL)
451 *pos = SEQ_READ_FINISHED; 454 *pos = SEQ_READ_FINISHED;
455 return NULL;
456 }
452 457
453 return skp; 458 return list->next;
454} 459}
455 460
456/* 461/*
@@ -459,7 +464,9 @@ static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
459 */ 464 */
460static int cipso_seq_show(struct seq_file *s, void *v) 465static int cipso_seq_show(struct seq_file *s, void *v)
461{ 466{
462 struct smack_known *skp = (struct smack_known *) v; 467 struct list_head *list = v;
468 struct smack_known *skp =
469 list_entry(list, struct smack_known, list);
463 struct smack_cipso *scp = skp->smk_cipso; 470 struct smack_cipso *scp = skp->smk_cipso;
464 char *cbp; 471 char *cbp;
465 char sep = '/'; 472 char sep = '/';
@@ -638,18 +645,21 @@ static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos)
638{ 645{
639 if (*pos == SEQ_READ_FINISHED) 646 if (*pos == SEQ_READ_FINISHED)
640 return NULL; 647 return NULL;
641 648 if (list_empty(&smk_netlbladdr_list))
642 return smack_netlbladdrs; 649 return NULL;
650 return smk_netlbladdr_list.next;
643} 651}
644 652
645static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) 653static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
646{ 654{
647 struct smk_netlbladdr *skp = ((struct smk_netlbladdr *) v)->smk_next; 655 struct list_head *list = v;
648 656
649 if (skp == NULL) 657 if (list_is_last(list, &smk_netlbladdr_list)) {
650 *pos = SEQ_READ_FINISHED; 658 *pos = SEQ_READ_FINISHED;
659 return NULL;
660 }
651 661
652 return skp; 662 return list->next;
653} 663}
654#define BEBITS (sizeof(__be32) * 8) 664#define BEBITS (sizeof(__be32) * 8)
655 665
@@ -658,7 +668,9 @@ static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
658 */ 668 */
659static int netlbladdr_seq_show(struct seq_file *s, void *v) 669static int netlbladdr_seq_show(struct seq_file *s, void *v)
660{ 670{
661 struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v; 671 struct list_head *list = v;
672 struct smk_netlbladdr *skp =
673 list_entry(list, struct smk_netlbladdr, list);
662 unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; 674 unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
663 int maskn; 675 int maskn;
664 u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr); 676 u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr);
@@ -702,30 +714,36 @@ static int smk_open_netlbladdr(struct inode *inode, struct file *file)
702 * 714 *
703 * This helper insert netlabel in the smack_netlbladdrs list 715 * This helper insert netlabel in the smack_netlbladdrs list
704 * sorted by netmask length (longest to smallest) 716 * sorted by netmask length (longest to smallest)
717 * locked by &smk_netlbladdr_lock in smk_write_netlbladdr
718 *
705 */ 719 */
706static void smk_netlbladdr_insert(struct smk_netlbladdr *new) 720static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
707{ 721{
708 struct smk_netlbladdr *m; 722 struct smk_netlbladdr *m, *m_next;
709 723
710 if (smack_netlbladdrs == NULL) { 724 if (list_empty(&smk_netlbladdr_list)) {
711 smack_netlbladdrs = new; 725 list_add_rcu(&new->list, &smk_netlbladdr_list);
712 return; 726 return;
713 } 727 }
714 728
729 m = list_entry(rcu_dereference(smk_netlbladdr_list.next),
730 struct smk_netlbladdr, list);
731
715 /* the comparison '>' is a bit hacky, but works */ 732 /* the comparison '>' is a bit hacky, but works */
716 if (new->smk_mask.s_addr > smack_netlbladdrs->smk_mask.s_addr) { 733 if (new->smk_mask.s_addr > m->smk_mask.s_addr) {
717 new->smk_next = smack_netlbladdrs; 734 list_add_rcu(&new->list, &smk_netlbladdr_list);
718 smack_netlbladdrs = new;
719 return; 735 return;
720 } 736 }
721 for (m = smack_netlbladdrs; m != NULL; m = m->smk_next) { 737
722 if (m->smk_next == NULL) { 738 list_for_each_entry_rcu(m, &smk_netlbladdr_list, list) {
723 m->smk_next = new; 739 if (list_is_last(&m->list, &smk_netlbladdr_list)) {
740 list_add_rcu(&new->list, &m->list);
724 return; 741 return;
725 } 742 }
726 if (new->smk_mask.s_addr > m->smk_next->smk_mask.s_addr) { 743 m_next = list_entry(rcu_dereference(m->list.next),
727 new->smk_next = m->smk_next; 744 struct smk_netlbladdr, list);
728 m->smk_next = new; 745 if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) {
746 list_add_rcu(&new->list, &m->list);
729 return; 747 return;
730 } 748 }
731 } 749 }
@@ -755,6 +773,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
755 struct netlbl_audit audit_info; 773 struct netlbl_audit audit_info;
756 struct in_addr mask; 774 struct in_addr mask;
757 unsigned int m; 775 unsigned int m;
776 int found;
758 u32 mask_bits = (1<<31); 777 u32 mask_bits = (1<<31);
759 __be32 nsa; 778 __be32 nsa;
760 u32 temp_mask; 779 u32 temp_mask;
@@ -808,14 +827,17 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
808 827
809 nsa = newname.sin_addr.s_addr; 828 nsa = newname.sin_addr.s_addr;
810 /* try to find if the prefix is already in the list */ 829 /* try to find if the prefix is already in the list */
811 for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next) 830 found = 0;
831 list_for_each_entry_rcu(skp, &smk_netlbladdr_list, list) {
812 if (skp->smk_host.sin_addr.s_addr == nsa && 832 if (skp->smk_host.sin_addr.s_addr == nsa &&
813 skp->smk_mask.s_addr == mask.s_addr) 833 skp->smk_mask.s_addr == mask.s_addr) {
834 found = 1;
814 break; 835 break;
815 836 }
837 }
816 smk_netlabel_audit_set(&audit_info); 838 smk_netlabel_audit_set(&audit_info);
817 839
818 if (skp == NULL) { 840 if (found == 0) {
819 skp = kzalloc(sizeof(*skp), GFP_KERNEL); 841 skp = kzalloc(sizeof(*skp), GFP_KERNEL);
820 if (skp == NULL) 842 if (skp == NULL)
821 rc = -ENOMEM; 843 rc = -ENOMEM;