diff options
Diffstat (limited to 'security/selinux')
-rw-r--r-- | security/selinux/ss/ebitmap.c | 198 | ||||
-rw-r--r-- | security/selinux/ss/ebitmap.h | 26 | ||||
-rw-r--r-- | security/selinux/ss/mls.c | 156 | ||||
-rw-r--r-- | security/selinux/ss/mls.h | 46 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 23 |
5 files changed, 199 insertions, 250 deletions
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index d539346ab3a2..ce492a6b38ed 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -6,7 +6,7 @@ /* * Updated: Hewlett-Packard <paul.moore@hp.com> * - * Added ebitmap_export() and ebitmap_import() + * Added support to import/export the NetLabel category bitmap * * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 */ @@ -14,6 +14,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/errno.h> +#include <net/netlabel.h> #include "ebitmap.h" #include "policydb.h" @@ -67,141 +68,120 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src) return 0; } +#ifdef CONFIG_NETLABEL /** - * ebitmap_export - Export an ebitmap to a unsigned char bitmap string - * @src: the ebitmap to export - * @dst: the resulting bitmap string - * @dst_len: length of dst in bytes + * ebitmap_netlbl_export - Export an ebitmap into a NetLabel category bitmap + * @ebmap: the ebitmap to export + * @catmap: the NetLabel category bitmap * * Description: - * Allocate a buffer at least src->highbit bits long and export the extensible - * bitmap into the buffer. The bitmap string will be in little endian format, - * i.e. LSB first. The value returned in dst_len may not the true size of the - * buffer as the length of the buffer is rounded up to a multiple of MAPTYPE. - * The caller must free the buffer when finished. Returns zero on success, - * negative values on failure. + * Export a SELinux extensibile bitmap into a NetLabel category bitmap. + * Returns zero on success, negative values on error. * */ -int ebitmap_export(const struct ebitmap *src, - unsigned char **dst, - size_t *dst_len) +int ebitmap_netlbl_export(struct ebitmap *ebmap, + struct netlbl_lsm_secattr_catmap **catmap) { - size_t bitmap_len; - unsigned char *bitmap; - struct ebitmap_node *iter_node; - MAPTYPE node_val; - size_t bitmap_byte; - unsigned char bitmask; - - if (src->highbit == 0) { - *dst = NULL; - *dst_len = 0; + 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; } - bitmap_len = src->highbit / 8; - if (src->highbit % 7) - bitmap_len += 1; - - bitmap = kzalloc((bitmap_len & ~(sizeof(MAPTYPE) - 1)) + - sizeof(MAPTYPE), - GFP_ATOMIC); - if (bitmap == NULL) + 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; + } - iter_node = src->node; - do { - bitmap_byte = iter_node->startbit / 8; - bitmask = 0x80; - node_val = iter_node->map; - do { - if (bitmask == 0) { - bitmap_byte++; - bitmask = 0x80; - } - if (node_val & (MAPTYPE)0x01) - bitmap[bitmap_byte] |= bitmask; - node_val >>= 1; - bitmask >>= 1; - } while (node_val > 0); - iter_node = iter_node->next; - } while (iter_node); - - *dst = bitmap; - *dst_len = bitmap_len; return 0; + +netlbl_export_failure: + netlbl_secattr_catmap_free(*catmap); + return -ENOMEM; } /** - * ebitmap_import - Import an unsigned char bitmap string into an ebitmap - * @src: the bitmap string - * @src_len: the bitmap length in bytes - * @dst: the empty ebitmap + * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap + * @ebmap: the ebitmap to export + * @catmap: the NetLabel category bitmap * * Description: - * This function takes a little endian bitmap string in src and imports it into - * the ebitmap pointed to by dst. Returns zero on success, negative values on - * failure. + * Import a NetLabel category bitmap into a SELinux extensibile bitmap. + * Returns zero on success, negative values on error. * */ -int ebitmap_import(const unsigned char *src, - size_t src_len, - struct ebitmap *dst) +int ebitmap_netlbl_import(struct ebitmap *ebmap, + struct netlbl_lsm_secattr_catmap *catmap) { - size_t src_off = 0; - size_t node_limit; - struct ebitmap_node *node_new; - struct ebitmap_node *node_last = NULL; - u32 i_byte; - u32 i_bit; - unsigned char src_byte; - - while (src_off < src_len) { - if (src_len - src_off >= sizeof(MAPTYPE)) { - if (*(MAPTYPE *)&src[src_off] == 0) { - src_off += sizeof(MAPTYPE); - continue; - } - node_limit = sizeof(MAPTYPE); - } else { - for (src_byte = 0, i_byte = src_off; - i_byte < src_len && src_byte == 0; - i_byte++) - src_byte |= src[i_byte]; - if (src_byte == 0) - break; - node_limit = src_len - src_off; - } + struct ebitmap_node *e_iter = NULL; + struct ebitmap_node *emap_prev = NULL; + struct netlbl_lsm_secattr_catmap *c_iter = catmap; + u32 c_idx; - node_new = kzalloc(sizeof(*node_new), GFP_ATOMIC); - if (unlikely(node_new == NULL)) { - ebitmap_destroy(dst); - return -ENOMEM; - } - node_new->startbit = src_off * 8; - for (i_byte = 0; i_byte < node_limit; i_byte++) { - src_byte = src[src_off++]; - for (i_bit = i_byte * 8; src_byte != 0; i_bit++) { - if (src_byte & 0x80) - node_new->map |= MAPBIT << i_bit; - src_byte <<= 1; - } - } + /* 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 (node_last != NULL) - node_last->next = node_new; - else - dst->node = node_new; - node_last = node_new; - } + 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; - if (likely(node_last != NULL)) - dst->highbit = node_last->startbit + MAPSIZE; + 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_init(dst); + 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) { diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index da2d4651b10d..1270e34b61c1 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h @@ -14,6 +14,8 @@ #ifndef _SS_EBITMAP_H_ #define _SS_EBITMAP_H_ +#include <net/netlabel.h> + #define MAPTYPE u64 /* portion of bitmap in each node */ #define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */ #define MAPBIT 1ULL /* a bit in the node bitmap */ @@ -69,16 +71,28 @@ static inline int ebitmap_node_get_bit(struct ebitmap_node * n, int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); -int ebitmap_export(const struct ebitmap *src, - unsigned char **dst, - size_t *dst_len); -int ebitmap_import(const unsigned char *src, - size_t src_len, - struct ebitmap *dst); int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2); int ebitmap_get_bit(struct ebitmap *e, unsigned long bit); int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); void ebitmap_destroy(struct ebitmap *e); int ebitmap_read(struct ebitmap *e, void *fp); +#ifdef CONFIG_NETLABEL +int ebitmap_netlbl_export(struct ebitmap *ebmap, + struct netlbl_lsm_secattr_catmap **catmap); +int ebitmap_netlbl_import(struct ebitmap *ebmap, + struct netlbl_lsm_secattr_catmap *catmap); +#else +static inline int ebitmap_netlbl_export(struct ebitmap *ebmap, + struct netlbl_lsm_secattr_catmap **catmap) +{ + return -ENOMEM; +} +static inline int ebitmap_netlbl_import(struct ebitmap *ebmap, + struct netlbl_lsm_secattr_catmap *catmap) +{ + return -ENOMEM; +} +#endif + #endif /* _SS_EBITMAP_H_ */ diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 2cca8e251624..b4f682dc13ff 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -13,7 +13,7 @@ /* * Updated: Hewlett-Packard <paul.moore@hp.com> * - * Added support to import/export the MLS label + * Added support to import/export the MLS label from NetLabel * * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 */ @@ -22,6 +22,7 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/errno.h> +#include <net/netlabel.h> #include "sidtab.h" #include "mls.h" #include "policydb.h" @@ -571,163 +572,108 @@ int mls_compute_sid(struct context *scontext, return -EINVAL; } +#ifdef CONFIG_NETLABEL /** - * mls_export_lvl - Export the MLS sensitivity levels + * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel * @context: the security context - * @low: the low sensitivity level - * @high: the high sensitivity level + * @secattr: the NetLabel security attributes * * Description: - * Given the security context copy the low MLS sensitivity level into lvl_low - * and the high sensitivity level in lvl_high. The MLS levels are only - * exported if the pointers are not NULL, if they are NULL then that level is - * not exported. + * Given the security context copy the low MLS sensitivity level into the + * NetLabel MLS sensitivity level field. * */ -void mls_export_lvl(const struct context *context, u32 *low, u32 *high) +void mls_export_netlbl_lvl(struct context *context, + struct netlbl_lsm_secattr *secattr) { if (!selinux_mls_enabled) return; - if (low != NULL) - *low = context->range.level[0].sens - 1; - if (high != NULL) - *high = context->range.level[1].sens - 1; + secattr->mls_lvl = context->range.level[0].sens - 1; + secattr->flags |= NETLBL_SECATTR_MLS_LVL; } /** - * mls_import_lvl - Import the MLS sensitivity levels + * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels * @context: the security context - * @low: the low sensitivity level - * @high: the high sensitivity level + * @secattr: the NetLabel security attributes * * Description: - * Given the security context and the two sensitivty levels, set the MLS levels - * in the context according the two given as parameters. Returns zero on - * success, negative values on failure. + * Given the security context and the NetLabel security attributes, copy the + * NetLabel MLS sensitivity level into the context. * */ -void mls_import_lvl(struct context *context, u32 low, u32 high) +void mls_import_netlbl_lvl(struct context *context, + struct netlbl_lsm_secattr *secattr) { if (!selinux_mls_enabled) return; - context->range.level[0].sens = low + 1; - context->range.level[1].sens = high + 1; + context->range.level[0].sens = secattr->mls_lvl + 1; + context->range.level[1].sens = context->range.level[0].sens; } /** - * mls_export_cat - Export the MLS categories + * mls_export_netlbl_cat - Export the MLS categories to NetLabel * @context: the security context - * @low: the low category - * @low_len: length of the cat_low bitmap in bytes - * @high: the high category - * @high_len: length of the cat_high bitmap in bytes + * @secattr: the NetLabel security attributes * * Description: - * Given the security context export the low MLS category bitmap into cat_low - * and the high category bitmap into cat_high. The MLS categories are only - * exported if the pointers are not NULL, if they are NULL then that level is - * not exported. The caller is responsibile for freeing the memory when - * finished. Returns zero on success, negative values on failure. + * Given the security context copy the low MLS categories into the NetLabel + * MLS category field. Returns zero on success, negative values on failure. * */ -int mls_export_cat(const struct context *context, - unsigned char **low, - size_t *low_len, - unsigned char **high, - size_t *high_len) +int mls_export_netlbl_cat(struct context *context, + struct netlbl_lsm_secattr *secattr) { - int rc = -EPERM; + int rc; - if (!selinux_mls_enabled) { - *low = NULL; - *low_len = 0; - *high = NULL; - *high_len = 0; + if (!selinux_mls_enabled) return 0; - } - if (low != NULL) { - rc = ebitmap_export(&context->range.level[0].cat, - low, - low_len); - if (rc != 0) - goto export_cat_failure; - } - if (high != NULL) { - rc = ebitmap_export(&context->range.level[1].cat, - high, - high_len); - if (rc != 0) - goto export_cat_failure; - } - - return 0; + rc = ebitmap_netlbl_export(&context->range.level[0].cat, + &secattr->mls_cat); + if (rc == 0 && secattr->mls_cat != NULL) + secattr->flags |= NETLBL_SECATTR_MLS_CAT; -export_cat_failure: - if (low != NULL) { - kfree(*low); - *low = NULL; - *low_len = 0; - } - if (high != NULL) { - kfree(*high); - *high = NULL; - *high_len = 0; - } return rc; } /** - * mls_import_cat - Import the MLS categories + * mls_import_netlbl_cat - Import the MLS categories from NetLabel * @context: the security context - * @low: the low category - * @low_len: length of the cat_low bitmap in bytes - * @high: the high category - * @high_len: length of the cat_high bitmap in bytes + * @secattr: the NetLabel security attributes * * Description: - * Given the security context and the two category bitmap strings import the - * categories into the security context. The MLS categories are only imported - * if the pointers are not NULL, if they are NULL they are skipped. Returns - * zero on success, negative values on failure. + * Copy the NetLabel security attributes into the SELinux context; since the + * NetLabel security attribute only contains a single MLS category use it for + * both the low and high categories of the context. Returns zero on success, + * negative values on failure. * */ -int mls_import_cat(struct context *context, - const unsigned char *low, - size_t low_len, - const unsigned char *high, - size_t high_len) +int mls_import_netlbl_cat(struct context *context, + struct netlbl_lsm_secattr *secattr) { - int rc = -EPERM; + int rc; if (!selinux_mls_enabled) return 0; - if (low != NULL) { - rc = ebitmap_import(low, - low_len, - &context->range.level[0].cat); - if (rc != 0) - goto import_cat_failure; - } - if (high != NULL) { - if (high == low) - rc = ebitmap_cpy(&context->range.level[1].cat, - &context->range.level[0].cat); - else - rc = ebitmap_import(high, - high_len, - &context->range.level[1].cat); - if (rc != 0) - goto import_cat_failure; - } + rc = ebitmap_netlbl_import(&context->range.level[0].cat, + secattr->mls_cat); + if (rc != 0) + goto import_netlbl_cat_failure; + + rc = ebitmap_cpy(&context->range.level[1].cat, + &context->range.level[0].cat); + if (rc != 0) + goto import_netlbl_cat_failure; return 0; -import_cat_failure: +import_netlbl_cat_failure: ebitmap_destroy(&context->range.level[0].cat); ebitmap_destroy(&context->range.level[1].cat); return rc; } +#endif /* CONFIG_NETLABEL */ diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index df6032c6d492..661d6fc76966 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h @@ -13,7 +13,7 @@ /* * Updated: Hewlett-Packard <paul.moore@hp.com> * - * Added support to import/export the MLS label + * Added support to import/export the MLS label from NetLabel * * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 */ @@ -69,19 +69,37 @@ int mls_compute_sid(struct context *scontext, int mls_setup_user_range(struct context *fromcon, struct user_datum *user, struct context *usercon); -void mls_export_lvl(const struct context *context, u32 *low, u32 *high); -void mls_import_lvl(struct context *context, u32 low, u32 high); - -int mls_export_cat(const struct context *context, - unsigned char **low, - size_t *low_len, - unsigned char **high, - size_t *high_len); -int mls_import_cat(struct context *context, - const unsigned char *low, - size_t low_len, - const unsigned char *high, - size_t high_len); +#ifdef CONFIG_NETLABEL +void mls_export_netlbl_lvl(struct context *context, + struct netlbl_lsm_secattr *secattr); +void mls_import_netlbl_lvl(struct context *context, + struct netlbl_lsm_secattr *secattr); +int mls_export_netlbl_cat(struct context *context, + struct netlbl_lsm_secattr *secattr); +int mls_import_netlbl_cat(struct context *context, + struct netlbl_lsm_secattr *secattr); +#else +static inline void mls_export_netlbl_lvl(struct context *context, + struct netlbl_lsm_secattr *secattr) +{ + return; +} +static inline void mls_import_netlbl_lvl(struct context *context, + struct netlbl_lsm_secattr *secattr) +{ + return; +} +static inline int mls_export_netlbl_cat(struct context *context, + struct netlbl_lsm_secattr *secattr) +{ + return -ENOMEM; +} +static inline int mls_import_netlbl_cat(struct context *context, + struct netlbl_lsm_secattr *secattr) +{ + return -ENOMEM; +} +#endif #endif /* _SS_MLS_H */ diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b43dd803fd5e..bdb7070dd3dc 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -55,6 +55,7 @@ #include "objsec.h" #include "selinux_netlabel.h" #include "xfrm.h" +#include "ebitmap.h" extern void selnl_notify_policyload(u32 seqno); unsigned int policydb_loaded_version; @@ -2384,13 +2385,10 @@ static int selinux_netlbl_secattr_to_sid(struct sk_buff *skb, ctx_new.user = ctx->user; ctx_new.role = ctx->role; ctx_new.type = ctx->type; - mls_import_lvl(&ctx_new, secattr->mls_lvl, secattr->mls_lvl); + mls_import_netlbl_lvl(&ctx_new, secattr); if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { - if (mls_import_cat(&ctx_new, - secattr->mls_cat, - secattr->mls_cat_len, - NULL, - 0) != 0) + if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat, + secattr->mls_cat) != 0) goto netlbl_secattr_to_sid_return; ctx_new.range.level[1].cat.highbit = ctx_new.range.level[0].cat.highbit; @@ -2486,19 +2484,12 @@ static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid) secattr.domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], GFP_ATOMIC); - mls_export_lvl(ctx, &secattr.mls_lvl, NULL); - rc = mls_export_cat(ctx, - &secattr.mls_cat, - &secattr.mls_cat_len, - NULL, - NULL); + secattr.flags |= NETLBL_SECATTR_DOMAIN; + mls_export_netlbl_lvl(ctx, &secattr); + rc = mls_export_netlbl_cat(ctx, &secattr); if (rc != 0) goto netlbl_socket_setsid_return; - secattr.flags |= NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; - if (secattr.mls_cat) - secattr.flags |= NETLBL_SECATTR_MLS_CAT; - rc = netlbl_socket_setattr(sock, &secattr); if (rc == 0) { spin_lock(&sksec->nlbl_lock); |