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.c218
1 files changed, 131 insertions, 87 deletions
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index a1b57e4dba3e..e03a7e19c73b 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -80,10 +80,14 @@ 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; 88
89const char *smack_cipso_option = SMACK_CIPSO_OPTION;
90
87 91
88#define SEQ_READ_FINISHED 1 92#define SEQ_READ_FINISHED 1
89 93
@@ -134,24 +138,27 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos)
134{ 138{
135 if (*pos == SEQ_READ_FINISHED) 139 if (*pos == SEQ_READ_FINISHED)
136 return NULL; 140 return NULL;
137 141 if (list_empty(&smack_rule_list))
138 return smack_list; 142 return NULL;
143 return smack_rule_list.next;
139} 144}
140 145
141static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos) 146static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
142{ 147{
143 struct smk_list_entry *skp = ((struct smk_list_entry *) v)->smk_next; 148 struct list_head *list = v;
144 149
145 if (skp == NULL) 150 if (list_is_last(list, &smack_rule_list)) {
146 *pos = SEQ_READ_FINISHED; 151 *pos = SEQ_READ_FINISHED;
147 152 return NULL;
148 return skp; 153 }
154 return list->next;
149} 155}
150 156
151static int load_seq_show(struct seq_file *s, void *v) 157static int load_seq_show(struct seq_file *s, void *v)
152{ 158{
153 struct smk_list_entry *slp = (struct smk_list_entry *) v; 159 struct list_head *list = v;
154 struct smack_rule *srp = &slp->smk_rule; 160 struct smack_rule *srp =
161 list_entry(list, struct smack_rule, list);
155 162
156 seq_printf(s, "%s %s", (char *)srp->smk_subject, 163 seq_printf(s, "%s %s", (char *)srp->smk_subject,
157 (char *)srp->smk_object); 164 (char *)srp->smk_object);
@@ -212,32 +219,23 @@ static int smk_open_load(struct inode *inode, struct file *file)
212 */ 219 */
213static int smk_set_access(struct smack_rule *srp) 220static int smk_set_access(struct smack_rule *srp)
214{ 221{
215 struct smk_list_entry *sp; 222 struct smack_rule *sp;
216 struct smk_list_entry *newp;
217 int ret = 0; 223 int ret = 0;
218 224 int found;
219 mutex_lock(&smack_list_lock); 225 mutex_lock(&smack_list_lock);
220 226
221 for (sp = smack_list; sp != NULL; sp = sp->smk_next) 227 found = 0;
222 if (sp->smk_rule.smk_subject == srp->smk_subject && 228 list_for_each_entry_rcu(sp, &smack_rule_list, list) {
223 sp->smk_rule.smk_object == srp->smk_object) { 229 if (sp->smk_subject == srp->smk_subject &&
224 sp->smk_rule.smk_access = srp->smk_access; 230 sp->smk_object == srp->smk_object) {
231 found = 1;
232 sp->smk_access = srp->smk_access;
225 break; 233 break;
226 } 234 }
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 } 235 }
236 if (found == 0)
237 list_add_rcu(&srp->list, &smack_rule_list);
239 238
240out:
241 mutex_unlock(&smack_list_lock); 239 mutex_unlock(&smack_list_lock);
242 240
243 return ret; 241 return ret;
@@ -261,7 +259,7 @@ out:
261static ssize_t smk_write_load(struct file *file, const char __user *buf, 259static ssize_t smk_write_load(struct file *file, const char __user *buf,
262 size_t count, loff_t *ppos) 260 size_t count, loff_t *ppos)
263{ 261{
264 struct smack_rule rule; 262 struct smack_rule *rule;
265 char *data; 263 char *data;
266 int rc = -EINVAL; 264 int rc = -EINVAL;
267 265
@@ -272,9 +270,8 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
272 */ 270 */
273 if (!capable(CAP_MAC_ADMIN)) 271 if (!capable(CAP_MAC_ADMIN))
274 return -EPERM; 272 return -EPERM;
275 if (*ppos != 0) 273
276 return -EINVAL; 274 if (*ppos != 0 || count != SMK_LOADLEN)
277 if (count != SMK_LOADLEN)
278 return -EINVAL; 275 return -EINVAL;
279 276
280 data = kzalloc(count, GFP_KERNEL); 277 data = kzalloc(count, GFP_KERNEL);
@@ -286,25 +283,31 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
286 goto out; 283 goto out;
287 } 284 }
288 285
289 rule.smk_subject = smk_import(data, 0); 286 rule = kzalloc(sizeof(*rule), GFP_KERNEL);
290 if (rule.smk_subject == NULL) 287 if (rule == NULL) {
288 rc = -ENOMEM;
291 goto out; 289 goto out;
290 }
292 291
293 rule.smk_object = smk_import(data + SMK_LABELLEN, 0); 292 rule->smk_subject = smk_import(data, 0);
294 if (rule.smk_object == NULL) 293 if (rule->smk_subject == NULL)
295 goto out; 294 goto out_free_rule;
296 295
297 rule.smk_access = 0; 296 rule->smk_object = smk_import(data + SMK_LABELLEN, 0);
297 if (rule->smk_object == NULL)
298 goto out_free_rule;
299
300 rule->smk_access = 0;
298 301
299 switch (data[SMK_LABELLEN + SMK_LABELLEN]) { 302 switch (data[SMK_LABELLEN + SMK_LABELLEN]) {
300 case '-': 303 case '-':
301 break; 304 break;
302 case 'r': 305 case 'r':
303 case 'R': 306 case 'R':
304 rule.smk_access |= MAY_READ; 307 rule->smk_access |= MAY_READ;
305 break; 308 break;
306 default: 309 default:
307 goto out; 310 goto out_free_rule;
308 } 311 }
309 312
310 switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { 313 switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
@@ -312,10 +315,10 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
312 break; 315 break;
313 case 'w': 316 case 'w':
314 case 'W': 317 case 'W':
315 rule.smk_access |= MAY_WRITE; 318 rule->smk_access |= MAY_WRITE;
316 break; 319 break;
317 default: 320 default:
318 goto out; 321 goto out_free_rule;
319 } 322 }
320 323
321 switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { 324 switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
@@ -323,10 +326,10 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
323 break; 326 break;
324 case 'x': 327 case 'x':
325 case 'X': 328 case 'X':
326 rule.smk_access |= MAY_EXEC; 329 rule->smk_access |= MAY_EXEC;
327 break; 330 break;
328 default: 331 default:
329 goto out; 332 goto out_free_rule;
330 } 333 }
331 334
332 switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { 335 switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
@@ -334,17 +337,20 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
334 break; 337 break;
335 case 'a': 338 case 'a':
336 case 'A': 339 case 'A':
337 rule.smk_access |= MAY_APPEND; 340 rule->smk_access |= MAY_APPEND;
338 break; 341 break;
339 default: 342 default:
340 goto out; 343 goto out_free_rule;
341 } 344 }
342 345
343 rc = smk_set_access(&rule); 346 rc = smk_set_access(rule);
344 347
345 if (!rc) 348 if (!rc)
346 rc = count; 349 rc = count;
350 goto out;
347 351
352out_free_rule:
353 kfree(rule);
348out: 354out:
349 kfree(data); 355 kfree(data);
350 return rc; 356 return rc;
@@ -433,24 +439,26 @@ static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
433{ 439{
434 if (*pos == SEQ_READ_FINISHED) 440 if (*pos == SEQ_READ_FINISHED)
435 return NULL; 441 return NULL;
442 if (list_empty(&smack_known_list))
443 return NULL;
436 444
437 return smack_known; 445 return smack_known_list.next;
438} 446}
439 447
440static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos) 448static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
441{ 449{
442 struct smack_known *skp = ((struct smack_known *) v)->smk_next; 450 struct list_head *list = v;
443 451
444 /* 452 /*
445 * Omit labels with no associated cipso value 453 * labels with no associated cipso value wont be printed
454 * in cipso_seq_show
446 */ 455 */
447 while (skp != NULL && !skp->smk_cipso) 456 if (list_is_last(list, &smack_known_list)) {
448 skp = skp->smk_next;
449
450 if (skp == NULL)
451 *pos = SEQ_READ_FINISHED; 457 *pos = SEQ_READ_FINISHED;
458 return NULL;
459 }
452 460
453 return skp; 461 return list->next;
454} 462}
455 463
456/* 464/*
@@ -459,7 +467,9 @@ static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
459 */ 467 */
460static int cipso_seq_show(struct seq_file *s, void *v) 468static int cipso_seq_show(struct seq_file *s, void *v)
461{ 469{
462 struct smack_known *skp = (struct smack_known *) v; 470 struct list_head *list = v;
471 struct smack_known *skp =
472 list_entry(list, struct smack_known, list);
463 struct smack_cipso *scp = skp->smk_cipso; 473 struct smack_cipso *scp = skp->smk_cipso;
464 char *cbp; 474 char *cbp;
465 char sep = '/'; 475 char sep = '/';
@@ -558,6 +568,11 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
558 goto unlockedout; 568 goto unlockedout;
559 } 569 }
560 570
571 /* labels cannot begin with a '-' */
572 if (data[0] == '-') {
573 rc = -EINVAL;
574 goto unlockedout;
575 }
561 data[count] = '\0'; 576 data[count] = '\0';
562 rule = data; 577 rule = data;
563 /* 578 /*
@@ -638,18 +653,21 @@ static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos)
638{ 653{
639 if (*pos == SEQ_READ_FINISHED) 654 if (*pos == SEQ_READ_FINISHED)
640 return NULL; 655 return NULL;
641 656 if (list_empty(&smk_netlbladdr_list))
642 return smack_netlbladdrs; 657 return NULL;
658 return smk_netlbladdr_list.next;
643} 659}
644 660
645static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) 661static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
646{ 662{
647 struct smk_netlbladdr *skp = ((struct smk_netlbladdr *) v)->smk_next; 663 struct list_head *list = v;
648 664
649 if (skp == NULL) 665 if (list_is_last(list, &smk_netlbladdr_list)) {
650 *pos = SEQ_READ_FINISHED; 666 *pos = SEQ_READ_FINISHED;
667 return NULL;
668 }
651 669
652 return skp; 670 return list->next;
653} 671}
654#define BEBITS (sizeof(__be32) * 8) 672#define BEBITS (sizeof(__be32) * 8)
655 673
@@ -658,7 +676,9 @@ static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
658 */ 676 */
659static int netlbladdr_seq_show(struct seq_file *s, void *v) 677static int netlbladdr_seq_show(struct seq_file *s, void *v)
660{ 678{
661 struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v; 679 struct list_head *list = v;
680 struct smk_netlbladdr *skp =
681 list_entry(list, struct smk_netlbladdr, list);
662 unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; 682 unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
663 int maskn; 683 int maskn;
664 u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr); 684 u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr);
@@ -702,30 +722,36 @@ static int smk_open_netlbladdr(struct inode *inode, struct file *file)
702 * 722 *
703 * This helper insert netlabel in the smack_netlbladdrs list 723 * This helper insert netlabel in the smack_netlbladdrs list
704 * sorted by netmask length (longest to smallest) 724 * sorted by netmask length (longest to smallest)
725 * locked by &smk_netlbladdr_lock in smk_write_netlbladdr
726 *
705 */ 727 */
706static void smk_netlbladdr_insert(struct smk_netlbladdr *new) 728static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
707{ 729{
708 struct smk_netlbladdr *m; 730 struct smk_netlbladdr *m, *m_next;
709 731
710 if (smack_netlbladdrs == NULL) { 732 if (list_empty(&smk_netlbladdr_list)) {
711 smack_netlbladdrs = new; 733 list_add_rcu(&new->list, &smk_netlbladdr_list);
712 return; 734 return;
713 } 735 }
714 736
737 m = list_entry(rcu_dereference(smk_netlbladdr_list.next),
738 struct smk_netlbladdr, list);
739
715 /* the comparison '>' is a bit hacky, but works */ 740 /* the comparison '>' is a bit hacky, but works */
716 if (new->smk_mask.s_addr > smack_netlbladdrs->smk_mask.s_addr) { 741 if (new->smk_mask.s_addr > m->smk_mask.s_addr) {
717 new->smk_next = smack_netlbladdrs; 742 list_add_rcu(&new->list, &smk_netlbladdr_list);
718 smack_netlbladdrs = new;
719 return; 743 return;
720 } 744 }
721 for (m = smack_netlbladdrs; m != NULL; m = m->smk_next) { 745
722 if (m->smk_next == NULL) { 746 list_for_each_entry_rcu(m, &smk_netlbladdr_list, list) {
723 m->smk_next = new; 747 if (list_is_last(&m->list, &smk_netlbladdr_list)) {
748 list_add_rcu(&new->list, &m->list);
724 return; 749 return;
725 } 750 }
726 if (new->smk_mask.s_addr > m->smk_next->smk_mask.s_addr) { 751 m_next = list_entry(rcu_dereference(m->list.next),
727 new->smk_next = m->smk_next; 752 struct smk_netlbladdr, list);
728 m->smk_next = new; 753 if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) {
754 list_add_rcu(&new->list, &m->list);
729 return; 755 return;
730 } 756 }
731 } 757 }
@@ -755,6 +781,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
755 struct netlbl_audit audit_info; 781 struct netlbl_audit audit_info;
756 struct in_addr mask; 782 struct in_addr mask;
757 unsigned int m; 783 unsigned int m;
784 int found;
758 u32 mask_bits = (1<<31); 785 u32 mask_bits = (1<<31);
759 __be32 nsa; 786 __be32 nsa;
760 u32 temp_mask; 787 u32 temp_mask;
@@ -789,9 +816,18 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
789 if (m > BEBITS) 816 if (m > BEBITS)
790 return -EINVAL; 817 return -EINVAL;
791 818
792 sp = smk_import(smack, 0); 819 /* if smack begins with '-', its an option, don't import it */
793 if (sp == NULL) 820 if (smack[0] != '-') {
794 return -EINVAL; 821 sp = smk_import(smack, 0);
822 if (sp == NULL)
823 return -EINVAL;
824 } else {
825 /* check known options */
826 if (strcmp(smack, smack_cipso_option) == 0)
827 sp = (char *)smack_cipso_option;
828 else
829 return -EINVAL;
830 }
795 831
796 for (temp_mask = 0; m > 0; m--) { 832 for (temp_mask = 0; m > 0; m--) {
797 temp_mask |= mask_bits; 833 temp_mask |= mask_bits;
@@ -808,14 +844,17 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
808 844
809 nsa = newname.sin_addr.s_addr; 845 nsa = newname.sin_addr.s_addr;
810 /* try to find if the prefix is already in the list */ 846 /* try to find if the prefix is already in the list */
811 for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next) 847 found = 0;
848 list_for_each_entry_rcu(skp, &smk_netlbladdr_list, list) {
812 if (skp->smk_host.sin_addr.s_addr == nsa && 849 if (skp->smk_host.sin_addr.s_addr == nsa &&
813 skp->smk_mask.s_addr == mask.s_addr) 850 skp->smk_mask.s_addr == mask.s_addr) {
851 found = 1;
814 break; 852 break;
815 853 }
854 }
816 smk_netlabel_audit_set(&audit_info); 855 smk_netlabel_audit_set(&audit_info);
817 856
818 if (skp == NULL) { 857 if (found == 0) {
819 skp = kzalloc(sizeof(*skp), GFP_KERNEL); 858 skp = kzalloc(sizeof(*skp), GFP_KERNEL);
820 if (skp == NULL) 859 if (skp == NULL)
821 rc = -ENOMEM; 860 rc = -ENOMEM;
@@ -827,18 +866,23 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
827 smk_netlbladdr_insert(skp); 866 smk_netlbladdr_insert(skp);
828 } 867 }
829 } else { 868 } else {
830 rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, 869 /* we delete the unlabeled entry, only if the previous label
831 &skp->smk_host.sin_addr, &skp->smk_mask, 870 * wasnt the special CIPSO option */
832 PF_INET, &audit_info); 871 if (skp->smk_label != smack_cipso_option)
872 rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
873 &skp->smk_host.sin_addr, &skp->smk_mask,
874 PF_INET, &audit_info);
875 else
876 rc = 0;
833 skp->smk_label = sp; 877 skp->smk_label = sp;
834 } 878 }
835 879
836 /* 880 /*
837 * Now tell netlabel about the single label nature of 881 * Now tell netlabel about the single label nature of
838 * this host so that incoming packets get labeled. 882 * this host so that incoming packets get labeled.
883 * but only if we didn't get the special CIPSO option
839 */ 884 */
840 885 if (rc == 0 && sp != smack_cipso_option)
841 if (rc == 0)
842 rc = netlbl_cfg_unlbl_static_add(&init_net, NULL, 886 rc = netlbl_cfg_unlbl_static_add(&init_net, NULL,
843 &skp->smk_host.sin_addr, &skp->smk_mask, PF_INET, 887 &skp->smk_host.sin_addr, &skp->smk_mask, PF_INET,
844 smack_to_secid(skp->smk_label), &audit_info); 888 smack_to_secid(skp->smk_label), &audit_info);