diff options
author | etienne <etienne.basset@numericable.fr> | 2009-03-04 01:33:51 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-03-04 16:36:34 -0500 |
commit | 211a40c0870457b29100cffea0180fa5083caf96 (patch) | |
tree | fae71ac7a443a45391ee6049f2300a5c25fe2272 /security/smack/smackfs.c | |
parent | 559595a985e106d2fa9f0c79b7f5805453fed593 (diff) |
smack: fixes for unlabeled host support
The following patch (against 2.6.29rc5) fixes a few issues in the
smack/netlabel "unlabeled host support" functionnality that was added in
2.6.29rc. It should go in before -final.
1) smack_host_label disregard a "0.0.0.0/0 @" rule (or other label),
preventing 'tagged' tasks to access Internet (many systems drop packets with
IP options)
2) netmasks were not handled correctly, they were stored in a way _not
equivalent_ to conversion to be32 (it was equivalent for /0, /8, /16, /24,
/32 masks but not other masks)
3) smack_netlbladdr prefixes (IP/mask) were not consistent (mask&IP was not
done), so there could have been different list entries for the same IP
prefix; if those entries had different labels, well ...
4) they were not sorted
1) 2) 3) are bugs, 4) is a more cosmetic issue.
The patch :
-creates a new helper smk_netlbladdr_insert to insert a smk_netlbladdr,
-sorted by netmask length
-use the new sorted nature of smack_netlbladdrs list to simplify
smack_host_label : the first match _will_ be the more specific
-corrects endianness issues in smk_write_netlbladdr & netlbladdr_seq_show
Signed-off-by: <etienne.basset@numericable.fr>
Acked-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Paul Moore <paul.moore@hp.com>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/smack/smackfs.c')
-rw-r--r-- | security/smack/smackfs.c | 64 |
1 files changed, 49 insertions, 15 deletions
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 8e42800878f4..51f0efc50dab 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -650,10 +650,6 @@ static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) | |||
650 | 650 | ||
651 | return skp; | 651 | return skp; |
652 | } | 652 | } |
653 | /* | ||
654 | #define BEMASK 0x80000000 | ||
655 | */ | ||
656 | #define BEMASK 0x00000001 | ||
657 | #define BEBITS (sizeof(__be32) * 8) | 653 | #define BEBITS (sizeof(__be32) * 8) |
658 | 654 | ||
659 | /* | 655 | /* |
@@ -663,12 +659,10 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v) | |||
663 | { | 659 | { |
664 | struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v; | 660 | struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v; |
665 | unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; | 661 | unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; |
666 | __be32 bebits; | 662 | int maskn; |
667 | int maskn = 0; | 663 | u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr); |
668 | 664 | ||
669 | for (bebits = BEMASK; bebits != 0; maskn++, bebits <<= 1) | 665 | for (maskn = 0; temp_mask; temp_mask <<= 1, maskn++); |
670 | if ((skp->smk_mask.s_addr & bebits) == 0) | ||
671 | break; | ||
672 | 666 | ||
673 | seq_printf(s, "%u.%u.%u.%u/%d %s\n", | 667 | seq_printf(s, "%u.%u.%u.%u/%d %s\n", |
674 | hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label); | 668 | hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label); |
@@ -702,6 +696,42 @@ static int smk_open_netlbladdr(struct inode *inode, struct file *file) | |||
702 | } | 696 | } |
703 | 697 | ||
704 | /** | 698 | /** |
699 | * smk_netlbladdr_insert | ||
700 | * @new : netlabel to insert | ||
701 | * | ||
702 | * This helper insert netlabel in the smack_netlbladdrs list | ||
703 | * sorted by netmask length (longest to smallest) | ||
704 | */ | ||
705 | static void smk_netlbladdr_insert(struct smk_netlbladdr *new) | ||
706 | { | ||
707 | struct smk_netlbladdr *m; | ||
708 | |||
709 | if (smack_netlbladdrs == NULL) { | ||
710 | smack_netlbladdrs = new; | ||
711 | return; | ||
712 | } | ||
713 | |||
714 | /* the comparison '>' is a bit hacky, but works */ | ||
715 | if (new->smk_mask.s_addr > smack_netlbladdrs->smk_mask.s_addr) { | ||
716 | new->smk_next = smack_netlbladdrs; | ||
717 | smack_netlbladdrs = new; | ||
718 | return; | ||
719 | } | ||
720 | for (m = smack_netlbladdrs; m != NULL; m = m->smk_next) { | ||
721 | if (m->smk_next == NULL) { | ||
722 | m->smk_next = new; | ||
723 | return; | ||
724 | } | ||
725 | if (new->smk_mask.s_addr > m->smk_next->smk_mask.s_addr) { | ||
726 | new->smk_next = m->smk_next; | ||
727 | m->smk_next = new; | ||
728 | return; | ||
729 | } | ||
730 | } | ||
731 | } | ||
732 | |||
733 | |||
734 | /** | ||
705 | * smk_write_netlbladdr - write() for /smack/netlabel | 735 | * smk_write_netlbladdr - write() for /smack/netlabel |
706 | * @filp: file pointer, not actually used | 736 | * @filp: file pointer, not actually used |
707 | * @buf: where to get the data from | 737 | * @buf: where to get the data from |
@@ -724,8 +754,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
724 | struct netlbl_audit audit_info; | 754 | struct netlbl_audit audit_info; |
725 | struct in_addr mask; | 755 | struct in_addr mask; |
726 | unsigned int m; | 756 | unsigned int m; |
727 | __be32 bebits = BEMASK; | 757 | u32 mask_bits = (1<<31); |
728 | __be32 nsa; | 758 | __be32 nsa; |
759 | u32 temp_mask; | ||
729 | 760 | ||
730 | /* | 761 | /* |
731 | * Must have privilege. | 762 | * Must have privilege. |
@@ -761,10 +792,13 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
761 | if (sp == NULL) | 792 | if (sp == NULL) |
762 | return -EINVAL; | 793 | return -EINVAL; |
763 | 794 | ||
764 | for (mask.s_addr = 0; m > 0; m--) { | 795 | for (temp_mask = 0; m > 0; m--) { |
765 | mask.s_addr |= bebits; | 796 | temp_mask |= mask_bits; |
766 | bebits <<= 1; | 797 | mask_bits >>= 1; |
767 | } | 798 | } |
799 | mask.s_addr = cpu_to_be32(temp_mask); | ||
800 | |||
801 | newname.sin_addr.s_addr &= mask.s_addr; | ||
768 | /* | 802 | /* |
769 | * Only allow one writer at a time. Writes should be | 803 | * Only allow one writer at a time. Writes should be |
770 | * quite rare and small in any case. | 804 | * quite rare and small in any case. |
@@ -772,6 +806,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
772 | mutex_lock(&smk_netlbladdr_lock); | 806 | mutex_lock(&smk_netlbladdr_lock); |
773 | 807 | ||
774 | nsa = newname.sin_addr.s_addr; | 808 | nsa = newname.sin_addr.s_addr; |
809 | /* try to find if the prefix is already in the list */ | ||
775 | for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next) | 810 | for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next) |
776 | if (skp->smk_host.sin_addr.s_addr == nsa && | 811 | if (skp->smk_host.sin_addr.s_addr == nsa && |
777 | skp->smk_mask.s_addr == mask.s_addr) | 812 | skp->smk_mask.s_addr == mask.s_addr) |
@@ -787,9 +822,8 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
787 | rc = 0; | 822 | rc = 0; |
788 | skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr; | 823 | skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr; |
789 | skp->smk_mask.s_addr = mask.s_addr; | 824 | skp->smk_mask.s_addr = mask.s_addr; |
790 | skp->smk_next = smack_netlbladdrs; | ||
791 | skp->smk_label = sp; | 825 | skp->smk_label = sp; |
792 | smack_netlbladdrs = skp; | 826 | smk_netlbladdr_insert(skp); |
793 | } | 827 | } |
794 | } else { | 828 | } else { |
795 | rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, | 829 | rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, |