fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / security / selinux / ss / ebitmap.c
index 98be57f..ce492a6 100644 (file)
@@ -3,55 +3,21 @@
  *
  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
  */
+/*
+ * Updated: Hewlett-Packard <paul.moore@hp.com>
+ *
+ *      Added support to import/export the NetLabel category bitmap
+ *
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ */
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
+#include <net/netlabel.h>
 #include "ebitmap.h"
 #include "policydb.h"
 
-int ebitmap_or(struct ebitmap *dst, struct ebitmap *e1, struct ebitmap *e2)
-{
-       struct ebitmap_node *n1, *n2, *new, *prev;
-
-       ebitmap_init(dst);
-
-       n1 = e1->node;
-       n2 = e2->node;
-       prev = 0;
-       while (n1 || n2) {
-               new = kmalloc(sizeof(*new), GFP_ATOMIC);
-               if (!new) {
-                       ebitmap_destroy(dst);
-                       return -ENOMEM;
-               }
-               memset(new, 0, sizeof(*new));
-               if (n1 && n2 && n1->startbit == n2->startbit) {
-                       new->startbit = n1->startbit;
-                       new->map = n1->map | n2->map;
-                       n1 = n1->next;
-                       n2 = n2->next;
-               } else if (!n2 || (n1 && n1->startbit < n2->startbit)) {
-                       new->startbit = n1->startbit;
-                       new->map = n1->map;
-                       n1 = n1->next;
-               } else {
-                       new->startbit = n2->startbit;
-                       new->map = n2->map;
-                       n2 = n2->next;
-               }
-
-               new->next = 0;
-               if (prev)
-                       prev->next = new;
-               else
-                       dst->node = new;
-               prev = new;
-       }
-
-       dst->highbit = (e1->highbit > e2->highbit) ? e1->highbit : e2->highbit;
-       return 0;
-}
-
 int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
 {
        struct ebitmap_node *n1, *n2;
@@ -80,17 +46,16 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
 
        ebitmap_init(dst);
        n = src->node;
-       prev = 0;
+       prev = NULL;
        while (n) {
-               new = kmalloc(sizeof(*new), GFP_ATOMIC);
+               new = kzalloc(sizeof(*new), GFP_ATOMIC);
                if (!new) {
                        ebitmap_destroy(dst);
                        return -ENOMEM;
                }
-               memset(new, 0, sizeof(*new));
                new->startbit = n->startbit;
                new->map = n->map;
-               new->next = 0;
+               new->next = NULL;
                if (prev)
                        prev->next = new;
                else
@@ -103,6 +68,121 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
        return 0;
 }
 
+#ifdef CONFIG_NETLABEL
+/**
+ * ebitmap_netlbl_export - Export an ebitmap into a NetLabel category bitmap
+ * @ebmap: the ebitmap to export
+ * @catmap: the NetLabel category bitmap
+ *
+ * Description:
+ * Export a SELinux extensibile bitmap into a NetLabel category bitmap.
+ * Returns zero on success, negative values on error.
+ *
+ */
+int ebitmap_netlbl_export(struct ebitmap *ebmap,
+                         struct netlbl_lsm_secattr_catmap **catmap)
+{
+       struct ebitmap_node *e_iter = ebmap->node;
+       struct netlbl_lsm_secattr_catmap *c_iter;
+       u32 cmap_idx;
+
+       /* This function is a much simpler because SELinux's MAPTYPE happens
+        * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
+        * changed from a u64 this function will most likely need to be changed
+        * as well.  It's not ideal but I think the tradeoff in terms of
+        * neatness and speed is worth it. */
+
+       if (e_iter == NULL) {
+               *catmap = NULL;
+               return 0;
+       }
+
+       c_iter = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+       if (c_iter == NULL)
+               return -ENOMEM;
+       *catmap = c_iter;
+       c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
+
+       while (e_iter != NULL) {
+               if (e_iter->startbit >=
+                   (c_iter->startbit + NETLBL_CATMAP_SIZE)) {
+                       c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+                       if (c_iter->next == NULL)
+                               goto netlbl_export_failure;
+                       c_iter = c_iter->next;
+                       c_iter->startbit = e_iter->startbit &
+                                          ~(NETLBL_CATMAP_SIZE - 1);
+               }
+               cmap_idx = (e_iter->startbit - c_iter->startbit) /
+                          NETLBL_CATMAP_MAPSIZE;
+               c_iter->bitmap[cmap_idx] = e_iter->map;
+               e_iter = e_iter->next;
+       }
+
+       return 0;
+
+netlbl_export_failure:
+       netlbl_secattr_catmap_free(*catmap);
+       return -ENOMEM;
+}
+
+/**
+ * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
+ * @ebmap: the ebitmap to export
+ * @catmap: the NetLabel category bitmap
+ *
+ * Description:
+ * Import a NetLabel category bitmap into a SELinux extensibile bitmap.
+ * Returns zero on success, negative values on error.
+ *
+ */
+int ebitmap_netlbl_import(struct ebitmap *ebmap,
+                         struct netlbl_lsm_secattr_catmap *catmap)
+{
+       struct ebitmap_node *e_iter = NULL;
+       struct ebitmap_node *emap_prev = NULL;
+       struct netlbl_lsm_secattr_catmap *c_iter = catmap;
+       u32 c_idx;
+
+       /* This function is a much simpler because SELinux's MAPTYPE happens
+        * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is
+        * changed from a u64 this function will most likely need to be changed
+        * as well.  It's not ideal but I think the tradeoff in terms of
+        * neatness and speed is worth it. */
+
+       do {
+               for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
+                       if (c_iter->bitmap[c_idx] == 0)
+                               continue;
+
+                       e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
+                       if (e_iter == NULL)
+                               goto netlbl_import_failure;
+                       if (emap_prev == NULL)
+                               ebmap->node = e_iter;
+                       else
+                               emap_prev->next = e_iter;
+                       emap_prev = e_iter;
+
+                       e_iter->startbit = c_iter->startbit +
+                                          NETLBL_CATMAP_MAPSIZE * c_idx;
+                       e_iter->map = c_iter->bitmap[c_idx];
+               }
+               c_iter = c_iter->next;
+       } while (c_iter != NULL);
+       if (e_iter != NULL)
+               ebmap->highbit = e_iter->startbit + MAPSIZE;
+       else
+               ebitmap_destroy(ebmap);
+
+       return 0;
+
+netlbl_import_failure:
+       ebitmap_destroy(ebmap);
+       return -ENOMEM;
+}
+#endif /* CONFIG_NETLABEL */
+
 int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
 {
        struct ebitmap_node *n1, *n2;
@@ -155,7 +235,7 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
 {
        struct ebitmap_node *n, *prev, *new;
 
-       prev = 0;
+       prev = NULL;
        n = e->node;
        while (n && n->startbit <= bit) {
                if ((n->startbit + MAPSIZE) > bit) {
@@ -193,10 +273,9 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
        if (!value)
                return 0;
 
-       new = kmalloc(sizeof(*new), GFP_ATOMIC);
+       new = kzalloc(sizeof(*new), GFP_ATOMIC);
        if (!new)
                return -ENOMEM;
-       memset(new, 0, sizeof(*new));
 
        new->startbit = bit & ~(MAPSIZE - 1);
        new->map = (MAPBIT << (bit - new->startbit));
@@ -231,21 +310,22 @@ void ebitmap_destroy(struct ebitmap *e)
        }
 
        e->highbit = 0;
-       e->node = 0;
+       e->node = NULL;
        return;
 }
 
 int ebitmap_read(struct ebitmap *e, void *fp)
 {
-       int rc = -EINVAL;
+       int rc;
        struct ebitmap_node *n, *l;
-       u32 *buf, mapsize, count, i;
-       u64 map;
+       __le32 buf[3];
+       u32 mapsize, count, i;
+       __le64 map;
 
        ebitmap_init(e);
 
-       buf = next_entry(fp, sizeof(u32)*3);
-       if (!buf)
+       rc = next_entry(buf, fp, sizeof buf);
+       if (rc < 0)
                goto out;
 
        mapsize = le32_to_cpu(buf[0]);
@@ -256,7 +336,7 @@ int ebitmap_read(struct ebitmap *e, void *fp)
                printk(KERN_ERR "security: ebitmap: map size %u does not "
                       "match my size %Zd (high bit was %d)\n", mapsize,
                       MAPSIZE, e->highbit);
-               goto out;
+               goto bad;
        }
        if (!e->highbit) {
                e->node = NULL;
@@ -269,18 +349,17 @@ int ebitmap_read(struct ebitmap *e, void *fp)
        }
        l = NULL;
        for (i = 0; i < count; i++) {
-               buf = next_entry(fp, sizeof(u32));
-               if (!buf) {
+               rc = next_entry(buf, fp, sizeof(u32));
+               if (rc < 0) {
                        printk(KERN_ERR "security: ebitmap: truncated map\n");
                        goto bad;
                }
-               n = kmalloc(sizeof(*n), GFP_KERNEL);
+               n = kzalloc(sizeof(*n), GFP_KERNEL);
                if (!n) {
                        printk(KERN_ERR "security: ebitmap: out of memory\n");
                        rc = -ENOMEM;
                        goto bad;
                }
-               memset(n, 0, sizeof(*n));
 
                n->startbit = le32_to_cpu(buf[0]);
 
@@ -296,12 +375,11 @@ int ebitmap_read(struct ebitmap *e, void *fp)
                               n->startbit, (e->highbit - MAPSIZE));
                        goto bad_free;
                }
-               buf = next_entry(fp, sizeof(u64));
-               if (!buf) {
+               rc = next_entry(&map, fp, sizeof(u64));
+               if (rc < 0) {
                        printk(KERN_ERR "security: ebitmap: truncated map\n");
                        goto bad_free;
                }
-               memcpy(&map, buf, sizeof(u64));
                n->map = le64_to_cpu(map);
 
                if (!n->map) {
@@ -330,6 +408,8 @@ out:
 bad_free:
        kfree(n);
 bad:
+       if (!rc)
+               rc = -EINVAL;
        ebitmap_destroy(e);
        goto out;
 }