X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=security%2Fselinux%2Fss%2Febitmap.c;h=ce492a6b38ed64110e2f8b0db68510df12281782;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=98be57f3391f63342a2bee78442d3e9cd351fba3;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 98be57f33..ce492a6b3 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -3,55 +3,21 @@ * * Author : Stephen Smalley, */ +/* + * Updated: Hewlett-Packard + * + * Added support to import/export the NetLabel category bitmap + * + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 + */ + #include #include #include +#include #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; }