summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2006-11-29 19:18:18 +0100
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-03 06:31:36 +0100
commit02752760359db6b00a3ffb1acfc13ef8d9eb1e3f (patch)
tree796cd65fd4cd732b295e61dac194efbf36b78842 /net
parent[NETFILTER]: remove the reference to ipchains from Kconfig (diff)
downloadlinux-02752760359db6b00a3ffb1acfc13ef8d9eb1e3f.tar.xz
linux-02752760359db6b00a3ffb1acfc13ef8d9eb1e3f.zip
NetLabel: convert to an extensibile/sparse category bitmap
The original NetLabel category bitmap was a straight char bitmap which worked fine for the initial release as it only supported 240 bits due to limitations in the CIPSO restricted bitmap tag (tag type 0x01). This patch converts that straight char bitmap into an extensibile/sparse bitmap in order to lay the foundation for other CIPSO tag types and protocols. This patch also has a nice side effect in that all of the security attributes passed by NetLabel into the LSM are now in a format which is in the host's native byte/bit ordering which makes the LSM specific code much simpler; look at the changes in security/selinux/ss/ebitmap.c as an example. Signed-off-by: Paul Moore <paul.moore@hp.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/cipso_ipv4.c168
-rw-r--r--net/netlabel/netlabel_kapi.c201
2 files changed, 270 insertions, 99 deletions
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index f3957cfaed42..08144f8fc911 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -819,8 +819,7 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
/**
* cipso_v4_map_cat_rbm_hton - Perform a category mapping from host to network
* @doi_def: the DOI definition
- * @host_cat: the category bitmap in host format
- * @host_cat_len: the length of the host's category bitmap in bytes
+ * @secattr: the security attributes
* @net_cat: the zero'd out category bitmap in network/CIPSO format
* @net_cat_len: the length of the CIPSO bitmap in bytes
*
@@ -831,61 +830,51 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
*
*/
static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
- const unsigned char *host_cat,
- u32 host_cat_len,
+ const struct netlbl_lsm_secattr *secattr,
unsigned char *net_cat,
u32 net_cat_len)
{
int host_spot = -1;
- u32 net_spot;
+ u32 net_spot = CIPSO_V4_INV_CAT;
u32 net_spot_max = 0;
- u32 host_clen_bits = host_cat_len * 8;
u32 net_clen_bits = net_cat_len * 8;
- u32 host_cat_size;
- u32 *host_cat_array;
+ u32 host_cat_size = 0;
+ u32 *host_cat_array = NULL;
- switch (doi_def->type) {
- case CIPSO_V4_MAP_PASS:
- net_spot_max = host_cat_len;
- while (net_spot_max > 0 && host_cat[net_spot_max - 1] == 0)
- net_spot_max--;
- if (net_spot_max > net_cat_len)
- return -EINVAL;
- memcpy(net_cat, host_cat, net_spot_max);
- return net_spot_max;
- case CIPSO_V4_MAP_STD:
+ if (doi_def->type == CIPSO_V4_MAP_STD) {
host_cat_size = doi_def->map.std->cat.local_size;
host_cat_array = doi_def->map.std->cat.local;
- for (;;) {
- host_spot = cipso_v4_bitmap_walk(host_cat,
- host_clen_bits,
- host_spot + 1,
- 1);
- if (host_spot < 0)
- break;
+ }
+
+ for (;;) {
+ host_spot = netlbl_secattr_catmap_walk(secattr->mls_cat,
+ host_spot + 1);
+ if (host_spot < 0)
+ break;
+
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_PASS:
+ net_spot = host_spot;
+ break;
+ case CIPSO_V4_MAP_STD:
if (host_spot >= host_cat_size)
return -EPERM;
-
net_spot = host_cat_array[host_spot];
if (net_spot >= CIPSO_V4_INV_CAT)
return -EPERM;
- if (net_spot >= net_clen_bits)
- return -ENOSPC;
- cipso_v4_bitmap_setbit(net_cat, net_spot, 1);
-
- if (net_spot > net_spot_max)
- net_spot_max = net_spot;
+ break;
}
+ if (net_spot >= net_clen_bits)
+ return -ENOSPC;
+ cipso_v4_bitmap_setbit(net_cat, net_spot, 1);
- if (host_spot == -2)
- return -EFAULT;
-
- if (++net_spot_max % 8)
- return net_spot_max / 8 + 1;
- return net_spot_max / 8;
+ if (net_spot > net_spot_max)
+ net_spot_max = net_spot;
}
- return -EINVAL;
+ if (++net_spot_max % 8)
+ return net_spot_max / 8 + 1;
+ return net_spot_max / 8;
}
/**
@@ -893,66 +882,59 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
* @doi_def: the DOI definition
* @net_cat: the category bitmap in network/CIPSO format
* @net_cat_len: the length of the CIPSO bitmap in bytes
- * @host_cat: the zero'd out category bitmap in host format
- * @host_cat_len: the length of the host's category bitmap in bytes
+ * @secattr: the security attributes
*
* Description:
* Perform a label mapping to translate a CIPSO bitmap to the correct local
- * MLS category bitmap using the given DOI definition. Returns the minimum
- * size in bytes of the host bitmap on success, negative values otherwise.
+ * MLS category bitmap using the given DOI definition. Returns zero on
+ * success, negative values on failure.
*
*/
static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
const unsigned char *net_cat,
u32 net_cat_len,
- unsigned char *host_cat,
- u32 host_cat_len)
+ struct netlbl_lsm_secattr *secattr)
{
- u32 host_spot;
- u32 host_spot_max = 0;
+ int ret_val;
int net_spot = -1;
+ u32 host_spot = CIPSO_V4_INV_CAT;
u32 net_clen_bits = net_cat_len * 8;
- u32 host_clen_bits = host_cat_len * 8;
- u32 net_cat_size;
- u32 *net_cat_array;
+ u32 net_cat_size = 0;
+ u32 *net_cat_array = NULL;
- switch (doi_def->type) {
- case CIPSO_V4_MAP_PASS:
- if (net_cat_len > host_cat_len)
- return -EINVAL;
- memcpy(host_cat, net_cat, net_cat_len);
- return net_cat_len;
- case CIPSO_V4_MAP_STD:
+ if (doi_def->type == CIPSO_V4_MAP_STD) {
net_cat_size = doi_def->map.std->cat.cipso_size;
net_cat_array = doi_def->map.std->cat.cipso;
- for (;;) {
- net_spot = cipso_v4_bitmap_walk(net_cat,
- net_clen_bits,
- net_spot + 1,
- 1);
- if (net_spot < 0)
- break;
- if (net_spot >= net_cat_size ||
- net_cat_array[net_spot] >= CIPSO_V4_INV_CAT)
- return -EPERM;
+ }
+ for (;;) {
+ net_spot = cipso_v4_bitmap_walk(net_cat,
+ net_clen_bits,
+ net_spot + 1,
+ 1);
+ if (net_spot < 0) {
+ if (net_spot == -2)
+ return -EFAULT;
+ return 0;
+ }
+
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_PASS:
+ host_spot = net_spot;
+ break;
+ case CIPSO_V4_MAP_STD:
+ if (net_spot >= net_cat_size)
+ return -EPERM;
host_spot = net_cat_array[net_spot];
if (host_spot >= CIPSO_V4_INV_CAT)
return -EPERM;
- if (host_spot >= host_clen_bits)
- return -ENOSPC;
- cipso_v4_bitmap_setbit(host_cat, host_spot, 1);
-
- if (host_spot > host_spot_max)
- host_spot_max = host_spot;
+ break;
}
-
- if (net_spot == -2)
- return -EFAULT;
-
- if (++host_spot_max % 8)
- return host_spot_max / 8 + 1;
- return host_spot_max / 8;
+ ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat,
+ host_spot,
+ GFP_ATOMIC);
+ if (ret_val != 0)
+ return ret_val;
}
return -EINVAL;
@@ -1016,8 +998,7 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
ret_val = cipso_v4_map_cat_rbm_hton(doi_def,
- secattr->mls_cat,
- secattr->mls_cat_len,
+ secattr,
&buffer[4],
buffer_len - 4);
if (ret_val < 0)
@@ -1067,31 +1048,20 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
secattr->flags |= NETLBL_SECATTR_MLS_LVL;
if (tag_len > 4) {
- switch (doi_def->type) {
- case CIPSO_V4_MAP_PASS:
- secattr->mls_cat_len = tag_len - 4;
- break;
- case CIPSO_V4_MAP_STD:
- secattr->mls_cat_len =
- doi_def->map.std->cat.local_size;
- break;
- }
- secattr->mls_cat = kzalloc(secattr->mls_cat_len, GFP_ATOMIC);
+ secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
if (secattr->mls_cat == NULL)
return -ENOMEM;
ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
&tag[4],
tag_len - 4,
- secattr->mls_cat,
- secattr->mls_cat_len);
- if (ret_val < 0) {
- kfree(secattr->mls_cat);
+ secattr);
+ if (ret_val != 0) {
+ netlbl_secattr_catmap_free(secattr->mls_cat);
return ret_val;
- } else if (ret_val > 0) {
- secattr->mls_cat_len = ret_val;
- secattr->flags |= NETLBL_SECATTR_MLS_CAT;
}
+
+ secattr->flags |= NETLBL_SECATTR_MLS_CAT;
}
return 0;
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index b35ebf94918c..e03a3282c551 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -40,6 +40,207 @@
#include "netlabel_user.h"
/*
+ * Security Attribute Functions
+ */
+
+/**
+ * netlbl_secattr_catmap_walk - Walk a LSM secattr catmap looking for a bit
+ * @catmap: the category bitmap
+ * @offset: the offset to start searching at, in bits
+ *
+ * Description:
+ * This function walks a LSM secattr category bitmap starting at @offset and
+ * returns the spot of the first set bit or -ENOENT if no bits are set.
+ *
+ */
+int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap,
+ u32 offset)
+{
+ struct netlbl_lsm_secattr_catmap *iter = catmap;
+ u32 node_idx;
+ u32 node_bit;
+ NETLBL_CATMAP_MAPTYPE bitmap;
+
+ if (offset > iter->startbit) {
+ while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
+ iter = iter->next;
+ if (iter == NULL)
+ return -ENOENT;
+ }
+ node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE;
+ node_bit = offset - iter->startbit -
+ (NETLBL_CATMAP_MAPSIZE * node_idx);
+ } else {
+ node_idx = 0;
+ node_bit = 0;
+ }
+ bitmap = iter->bitmap[node_idx] >> node_bit;
+
+ for (;;) {
+ if (bitmap != 0) {
+ while ((bitmap & NETLBL_CATMAP_BIT) == 0) {
+ bitmap >>= 1;
+ node_bit++;
+ }
+ return iter->startbit +
+ (NETLBL_CATMAP_MAPSIZE * node_idx) + node_bit;
+ }
+ if (++node_idx >= NETLBL_CATMAP_MAPCNT) {
+ if (iter->next != NULL) {
+ iter = iter->next;
+ node_idx = 0;
+ } else
+ return -ENOENT;
+ }
+ bitmap = iter->bitmap[node_idx];
+ node_bit = 0;
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * netlbl_secattr_catmap_walk_rng - Find the end of a string of set bits
+ * @catmap: the category bitmap
+ * @offset: the offset to start searching at, in bits
+ *
+ * Description:
+ * This function walks a LSM secattr category bitmap starting at @offset and
+ * returns the spot of the first cleared bit or -ENOENT if the offset is past
+ * the end of the bitmap.
+ *
+ */
+int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap,
+ u32 offset)
+{
+ struct netlbl_lsm_secattr_catmap *iter = catmap;
+ u32 node_idx;
+ u32 node_bit;
+ NETLBL_CATMAP_MAPTYPE bitmask;
+ NETLBL_CATMAP_MAPTYPE bitmap;
+
+ if (offset > iter->startbit) {
+ while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
+ iter = iter->next;
+ if (iter == NULL)
+ return -ENOENT;
+ }
+ node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE;
+ node_bit = offset - iter->startbit -
+ (NETLBL_CATMAP_MAPSIZE * node_idx);
+ } else {
+ node_idx = 0;
+ node_bit = 0;
+ }
+ bitmask = NETLBL_CATMAP_BIT << node_bit;
+
+ for (;;) {
+ bitmap = iter->bitmap[node_idx];
+ while (bitmask != 0 && (bitmap & bitmask) != 0) {
+ bitmask <<= 1;
+ node_bit++;
+ }
+
+ if (bitmask != 0)
+ return iter->startbit +
+ (NETLBL_CATMAP_MAPSIZE * node_idx) +
+ node_bit - 1;
+ else if (++node_idx >= NETLBL_CATMAP_MAPCNT) {
+ if (iter->next == NULL)
+ return iter->startbit + NETLBL_CATMAP_SIZE - 1;
+ iter = iter->next;
+ node_idx = 0;
+ }
+ bitmask = NETLBL_CATMAP_BIT;
+ node_bit = 0;
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * netlbl_secattr_catmap_setbit - Set a bit in a LSM secattr catmap
+ * @catmap: the category bitmap
+ * @bit: the bit to set
+ * @flags: memory allocation flags
+ *
+ * Description:
+ * Set the bit specified by @bit in @catmap. Returns zero on success,
+ * negative values on failure.
+ *
+ */
+int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap,
+ u32 bit,
+ gfp_t flags)
+{
+ struct netlbl_lsm_secattr_catmap *iter = catmap;
+ u32 node_bit;
+ u32 node_idx;
+
+ while (iter->next != NULL &&
+ bit >= (iter->startbit + NETLBL_CATMAP_SIZE))
+ iter = iter->next;
+ if (bit >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
+ iter->next = netlbl_secattr_catmap_alloc(flags);
+ if (iter->next == NULL)
+ return -ENOMEM;
+ iter = iter->next;
+ iter->startbit = bit & ~(NETLBL_CATMAP_SIZE - 1);
+ }
+
+ /* gcc always rounds to zero when doing integer division */
+ node_idx = (bit - iter->startbit) / NETLBL_CATMAP_MAPSIZE;
+ node_bit = bit - iter->startbit - (NETLBL_CATMAP_MAPSIZE * node_idx);
+ iter->bitmap[node_idx] |= NETLBL_CATMAP_BIT << node_bit;
+
+ return 0;
+}
+
+/**
+ * netlbl_secattr_catmap_setrng - Set a range of bits in a LSM secattr catmap
+ * @catmap: the category bitmap
+ * @start: the starting bit
+ * @end: the last bit in the string
+ * @flags: memory allocation flags
+ *
+ * Description:
+ * Set a range of bits, starting at @start and ending with @end. Returns zero
+ * on success, negative values on failure.
+ *
+ */
+int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
+ u32 start,
+ u32 end,
+ gfp_t flags)
+{
+ int ret_val = 0;
+ struct netlbl_lsm_secattr_catmap *iter = catmap;
+ u32 iter_max_spot;
+ u32 spot;
+
+ /* XXX - This could probably be made a bit faster by combining writes
+ * to the catmap instead of setting a single bit each time, but for
+ * right now skipping to the start of the range in the catmap should
+ * be a nice improvement over calling the individual setbit function
+ * repeatedly from a loop. */
+
+ while (iter->next != NULL &&
+ start >= (iter->startbit + NETLBL_CATMAP_SIZE))
+ iter = iter->next;
+ iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE;
+
+ for (spot = start; spot <= end && ret_val == 0; spot++) {
+ if (spot >= iter_max_spot && iter->next != NULL) {
+ iter = iter->next;
+ iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE;
+ }
+ ret_val = netlbl_secattr_catmap_setbit(iter, spot, GFP_ATOMIC);
+ }
+
+ return ret_val;
+}
+
+/*
* LSM Functions
*/