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:30:01 -0500 |
commit | 113a0e4590881ce579ca992a80ddc562b3372ede (patch) | |
tree | 29dd1cd1c5f594efb51cdf9530a90ba2f3f2854e /security/smack/smackfs.c | |
parent | 454804ab0302b354e35d992d08e53fe03313baaf (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 fd8d1eb43700..a1b57e4dba3e 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -651,10 +651,6 @@ static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) | |||
651 | 651 | ||
652 | return skp; | 652 | return skp; |
653 | } | 653 | } |
654 | /* | ||
655 | #define BEMASK 0x80000000 | ||
656 | */ | ||
657 | #define BEMASK 0x00000001 | ||
658 | #define BEBITS (sizeof(__be32) * 8) | 654 | #define BEBITS (sizeof(__be32) * 8) |
659 | 655 | ||
660 | /* | 656 | /* |
@@ -664,12 +660,10 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v) | |||
664 | { | 660 | { |
665 | struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v; | 661 | struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v; |
666 | unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; | 662 | unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; |
667 | __be32 bebits; | 663 | int maskn; |
668 | int maskn = 0; | 664 | u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr); |
669 | 665 | ||
670 | for (bebits = BEMASK; bebits != 0; maskn++, bebits <<= 1) | 666 | for (maskn = 0; temp_mask; temp_mask <<= 1, maskn++); |
671 | if ((skp->smk_mask.s_addr & bebits) == 0) | ||
672 | break; | ||
673 | 667 | ||
674 | seq_printf(s, "%u.%u.%u.%u/%d %s\n", | 668 | seq_printf(s, "%u.%u.%u.%u/%d %s\n", |
675 | hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label); | 669 | hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label); |
@@ -703,6 +697,42 @@ static int smk_open_netlbladdr(struct inode *inode, struct file *file) | |||
703 | } | 697 | } |
704 | 698 | ||
705 | /** | 699 | /** |
700 | * smk_netlbladdr_insert | ||
701 | * @new : netlabel to insert | ||
702 | * | ||
703 | * This helper insert netlabel in the smack_netlbladdrs list | ||
704 | * sorted by netmask length (longest to smallest) | ||
705 | */ | ||
706 | static void smk_netlbladdr_insert(struct smk_netlbladdr *new) | ||
707 | { | ||
708 | struct smk_netlbladdr *m; | ||
709 | |||
710 | if (smack_netlbladdrs == NULL) { | ||
711 | smack_netlbladdrs = new; | ||
712 | return; | ||
713 | } | ||
714 | |||
715 | /* the comparison '>' is a bit hacky, but works */ | ||
716 | if (new->smk_mask.s_addr > smack_netlbladdrs->smk_mask.s_addr) { | ||
717 | new->smk_next = smack_netlbladdrs; | ||
718 | smack_netlbladdrs = new; | ||
719 | return; | ||
720 | } | ||
721 | for (m = smack_netlbladdrs; m != NULL; m = m->smk_next) { | ||
722 | if (m->smk_next == NULL) { | ||
723 | m->smk_next = new; | ||
724 | return; | ||
725 | } | ||
726 | if (new->smk_mask.s_addr > m->smk_next->smk_mask.s_addr) { | ||
727 | new->smk_next = m->smk_next; | ||
728 | m->smk_next = new; | ||
729 | return; | ||
730 | } | ||
731 | } | ||
732 | } | ||
733 | |||
734 | |||
735 | /** | ||
706 | * smk_write_netlbladdr - write() for /smack/netlabel | 736 | * smk_write_netlbladdr - write() for /smack/netlabel |
707 | * @file: file pointer, not actually used | 737 | * @file: file pointer, not actually used |
708 | * @buf: where to get the data from | 738 | * @buf: where to get the data from |
@@ -725,8 +755,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
725 | struct netlbl_audit audit_info; | 755 | struct netlbl_audit audit_info; |
726 | struct in_addr mask; | 756 | struct in_addr mask; |
727 | unsigned int m; | 757 | unsigned int m; |
728 | __be32 bebits = BEMASK; | 758 | u32 mask_bits = (1<<31); |
729 | __be32 nsa; | 759 | __be32 nsa; |
760 | u32 temp_mask; | ||
730 | 761 | ||
731 | /* | 762 | /* |
732 | * Must have privilege. | 763 | * Must have privilege. |
@@ -762,10 +793,13 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
762 | if (sp == NULL) | 793 | if (sp == NULL) |
763 | return -EINVAL; | 794 | return -EINVAL; |
764 | 795 | ||
765 | for (mask.s_addr = 0; m > 0; m--) { | 796 | for (temp_mask = 0; m > 0; m--) { |
766 | mask.s_addr |= bebits; | 797 | temp_mask |= mask_bits; |
767 | bebits <<= 1; | 798 | mask_bits >>= 1; |
768 | } | 799 | } |
800 | mask.s_addr = cpu_to_be32(temp_mask); | ||
801 | |||
802 | newname.sin_addr.s_addr &= mask.s_addr; | ||
769 | /* | 803 | /* |
770 | * Only allow one writer at a time. Writes should be | 804 | * Only allow one writer at a time. Writes should be |
771 | * quite rare and small in any case. | 805 | * quite rare and small in any case. |
@@ -773,6 +807,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
773 | mutex_lock(&smk_netlbladdr_lock); | 807 | mutex_lock(&smk_netlbladdr_lock); |
774 | 808 | ||
775 | nsa = newname.sin_addr.s_addr; | 809 | nsa = newname.sin_addr.s_addr; |
810 | /* try to find if the prefix is already in the list */ | ||
776 | for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next) | 811 | for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next) |
777 | if (skp->smk_host.sin_addr.s_addr == nsa && | 812 | if (skp->smk_host.sin_addr.s_addr == nsa && |
778 | skp->smk_mask.s_addr == mask.s_addr) | 813 | skp->smk_mask.s_addr == mask.s_addr) |
@@ -788,9 +823,8 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
788 | rc = 0; | 823 | rc = 0; |
789 | skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr; | 824 | skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr; |
790 | skp->smk_mask.s_addr = mask.s_addr; | 825 | skp->smk_mask.s_addr = mask.s_addr; |
791 | skp->smk_next = smack_netlbladdrs; | ||
792 | skp->smk_label = sp; | 826 | skp->smk_label = sp; |
793 | smack_netlbladdrs = skp; | 827 | smk_netlbladdr_insert(skp); |
794 | } | 828 | } |
795 | } else { | 829 | } else { |
796 | rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, | 830 | rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, |