Commit 211a40c0 authored by etienne's avatar etienne Committed by James Morris

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: default avatarCasey Schaufler <casey@schaufler-ca.com>
Reviewed-by: default avatarPaul Moore <paul.moore@hp.com>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 559595a9
...@@ -1498,58 +1498,31 @@ static int smack_socket_post_create(struct socket *sock, int family, ...@@ -1498,58 +1498,31 @@ static int smack_socket_post_create(struct socket *sock, int family,
* looks for host based access restrictions * looks for host based access restrictions
* *
* This version will only be appropriate for really small * This version will only be appropriate for really small
* sets of single label hosts. Because of the masking * sets of single label hosts.
* it cannot shortcut out on the first match. There are
* numerious ways to address the problem, but none of them
* have been applied here.
* *
* Returns the label of the far end or NULL if it's not special. * Returns the label of the far end or NULL if it's not special.
*/ */
static char *smack_host_label(struct sockaddr_in *sip) static char *smack_host_label(struct sockaddr_in *sip)
{ {
struct smk_netlbladdr *snp; struct smk_netlbladdr *snp;
char *bestlabel = NULL;
struct in_addr *siap = &sip->sin_addr; struct in_addr *siap = &sip->sin_addr;
struct in_addr *liap;
struct in_addr *miap;
struct in_addr bestmask;
if (siap->s_addr == 0) if (siap->s_addr == 0)
return NULL; return NULL;
bestmask.s_addr = 0;
for (snp = smack_netlbladdrs; snp != NULL; snp = snp->smk_next) { for (snp = smack_netlbladdrs; snp != NULL; snp = snp->smk_next) {
liap = &snp->smk_host.sin_addr;
miap = &snp->smk_mask;
/*
* If the addresses match after applying the list entry mask
* the entry matches the address. If it doesn't move along to
* the next entry.
*/
if ((liap->s_addr & miap->s_addr) !=
(siap->s_addr & miap->s_addr))
continue;
/* /*
* If the list entry mask identifies a single address * we break after finding the first match because
* it can't get any more specific. * the list is sorted from longest to shortest mask
* so we have found the most specific match
*/ */
if (miap->s_addr == 0xffffffff) if ((&snp->smk_host.sin_addr)->s_addr ==
(siap->s_addr & (&snp->smk_mask)->s_addr)) {
return snp->smk_label; return snp->smk_label;
/* }
* If the list entry mask is less specific than the best
* already found this entry is uninteresting.
*/
if ((miap->s_addr | bestmask.s_addr) == bestmask.s_addr)
continue;
/*
* This is better than any entry found so far.
*/
bestmask.s_addr = miap->s_addr;
bestlabel = snp->smk_label;
} }
return bestlabel; return NULL;
} }
/** /**
......
...@@ -650,10 +650,6 @@ static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) ...@@ -650,10 +650,6 @@ static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
return skp; return skp;
} }
/*
#define BEMASK 0x80000000
*/
#define BEMASK 0x00000001
#define BEBITS (sizeof(__be32) * 8) #define BEBITS (sizeof(__be32) * 8)
/* /*
...@@ -663,12 +659,10 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v) ...@@ -663,12 +659,10 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v)
{ {
struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v; struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v;
unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
__be32 bebits; int maskn;
int maskn = 0; u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr);
for (bebits = BEMASK; bebits != 0; maskn++, bebits <<= 1) for (maskn = 0; temp_mask; temp_mask <<= 1, maskn++);
if ((skp->smk_mask.s_addr & bebits) == 0)
break;
seq_printf(s, "%u.%u.%u.%u/%d %s\n", seq_printf(s, "%u.%u.%u.%u/%d %s\n",
hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label); hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label);
...@@ -701,6 +695,42 @@ static int smk_open_netlbladdr(struct inode *inode, struct file *file) ...@@ -701,6 +695,42 @@ static int smk_open_netlbladdr(struct inode *inode, struct file *file)
return seq_open(file, &netlbladdr_seq_ops); return seq_open(file, &netlbladdr_seq_ops);
} }
/**
* smk_netlbladdr_insert
* @new : netlabel to insert
*
* This helper insert netlabel in the smack_netlbladdrs list
* sorted by netmask length (longest to smallest)
*/
static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
{
struct smk_netlbladdr *m;
if (smack_netlbladdrs == NULL) {
smack_netlbladdrs = new;
return;
}
/* the comparison '>' is a bit hacky, but works */
if (new->smk_mask.s_addr > smack_netlbladdrs->smk_mask.s_addr) {
new->smk_next = smack_netlbladdrs;
smack_netlbladdrs = new;
return;
}
for (m = smack_netlbladdrs; m != NULL; m = m->smk_next) {
if (m->smk_next == NULL) {
m->smk_next = new;
return;
}
if (new->smk_mask.s_addr > m->smk_next->smk_mask.s_addr) {
new->smk_next = m->smk_next;
m->smk_next = new;
return;
}
}
}
/** /**
* smk_write_netlbladdr - write() for /smack/netlabel * smk_write_netlbladdr - write() for /smack/netlabel
* @filp: file pointer, not actually used * @filp: file pointer, not actually used
...@@ -724,8 +754,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, ...@@ -724,8 +754,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
struct netlbl_audit audit_info; struct netlbl_audit audit_info;
struct in_addr mask; struct in_addr mask;
unsigned int m; unsigned int m;
__be32 bebits = BEMASK; u32 mask_bits = (1<<31);
__be32 nsa; __be32 nsa;
u32 temp_mask;
/* /*
* Must have privilege. * Must have privilege.
...@@ -761,10 +792,13 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, ...@@ -761,10 +792,13 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
if (sp == NULL) if (sp == NULL)
return -EINVAL; return -EINVAL;
for (mask.s_addr = 0; m > 0; m--) { for (temp_mask = 0; m > 0; m--) {
mask.s_addr |= bebits; temp_mask |= mask_bits;
bebits <<= 1; mask_bits >>= 1;
} }
mask.s_addr = cpu_to_be32(temp_mask);
newname.sin_addr.s_addr &= mask.s_addr;
/* /*
* Only allow one writer at a time. Writes should be * Only allow one writer at a time. Writes should be
* quite rare and small in any case. * 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,6 +806,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
mutex_lock(&smk_netlbladdr_lock); mutex_lock(&smk_netlbladdr_lock);
nsa = newname.sin_addr.s_addr; nsa = newname.sin_addr.s_addr;
/* try to find if the prefix is already in the list */
for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next) for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next)
if (skp->smk_host.sin_addr.s_addr == nsa && if (skp->smk_host.sin_addr.s_addr == nsa &&
skp->smk_mask.s_addr == mask.s_addr) 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,9 +822,8 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
rc = 0; rc = 0;
skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr; skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr;
skp->smk_mask.s_addr = mask.s_addr; skp->smk_mask.s_addr = mask.s_addr;
skp->smk_next = smack_netlbladdrs;
skp->smk_label = sp; skp->smk_label = sp;
smack_netlbladdrs = skp; smk_netlbladdr_insert(skp);
} }
} else { } else {
rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment