*
* 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 = NULL;
- 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 = NULL;
- 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;
n = src->node;
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 = NULL;
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;
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));
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]);
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;
}
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]);
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) {
bad_free:
kfree(n);
bad:
+ if (!rc)
+ rc = -EINVAL;
ebitmap_destroy(e);
goto out;
}