diff --git a/include/net/netlabel.h b/include/net/netlabel.h index 4fe018c48ed9..a4fc39bb3e4f 100644 --- a/include/net/netlabel.h +++ b/include/net/netlabel.h @@ -139,7 +139,7 @@ struct netlbl_lsm_cache { }; /** - * struct netlbl_lsm_secattr_catmap - NetLabel LSM secattr category bitmap + * struct netlbl_lsm_catmap - NetLabel LSM secattr category bitmap * @startbit: the value of the lowest order bit in the bitmap * @bitmap: the category bitmap * @next: pointer to the next bitmap "node" or NULL @@ -162,10 +162,10 @@ struct netlbl_lsm_cache { #define NETLBL_CATMAP_SIZE (NETLBL_CATMAP_MAPSIZE * \ NETLBL_CATMAP_MAPCNT) #define NETLBL_CATMAP_BIT (NETLBL_CATMAP_MAPTYPE)0x01 -struct netlbl_lsm_secattr_catmap { +struct netlbl_lsm_catmap { u32 startbit; NETLBL_CATMAP_MAPTYPE bitmap[NETLBL_CATMAP_MAPCNT]; - struct netlbl_lsm_secattr_catmap *next; + struct netlbl_lsm_catmap *next; }; /** @@ -209,7 +209,7 @@ struct netlbl_lsm_secattr { struct netlbl_lsm_cache *cache; struct { struct { - struct netlbl_lsm_secattr_catmap *cat; + struct netlbl_lsm_catmap *cat; u32 lvl; } mls; u32 secid; @@ -258,7 +258,7 @@ static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache) } /** - * netlbl_secattr_catmap_alloc - Allocate a LSM secattr catmap + * netlbl_catmap_alloc - Allocate a LSM secattr catmap * @flags: memory allocation flags * * Description: @@ -266,30 +266,28 @@ static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache) * on failure. * */ -static inline struct netlbl_lsm_secattr_catmap *netlbl_secattr_catmap_alloc( - gfp_t flags) +static inline struct netlbl_lsm_catmap *netlbl_catmap_alloc(gfp_t flags) { - return kzalloc(sizeof(struct netlbl_lsm_secattr_catmap), flags); + return kzalloc(sizeof(struct netlbl_lsm_catmap), flags); } /** - * netlbl_secattr_catmap_free - Free a LSM secattr catmap + * netlbl_catmap_free - Free a LSM secattr catmap * @catmap: the category bitmap * * Description: * Free a LSM secattr catmap. * */ -static inline void netlbl_secattr_catmap_free( - struct netlbl_lsm_secattr_catmap *catmap) +static inline void netlbl_catmap_free(struct netlbl_lsm_catmap *catmap) { - struct netlbl_lsm_secattr_catmap *iter; + struct netlbl_lsm_catmap *iter; - do { + while (catmap) { iter = catmap; catmap = catmap->next; kfree(iter); - } while (catmap); + } } /** @@ -321,7 +319,7 @@ static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr) if (secattr->flags & NETLBL_SECATTR_CACHE) netlbl_secattr_cache_free(secattr->cache); if (secattr->flags & NETLBL_SECATTR_MLS_CAT) - netlbl_secattr_catmap_free(secattr->attr.mls.cat); + netlbl_catmap_free(secattr->attr.mls.cat); } /** @@ -390,17 +388,22 @@ int netlbl_cfg_cipsov4_map_add(u32 doi, /* * LSM security attribute operations */ -int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap, - u32 offset); -int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap, - u32 offset); -int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap, - u32 bit, - gfp_t flags); -int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, - u32 start, - u32 end, - gfp_t flags); +int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset); +int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, u32 offset); +int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap, + u32 *offset, + unsigned long *bitmap); +int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap, + u32 bit, + gfp_t flags); +int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap, + u32 start, + u32 end, + gfp_t flags); +int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap, + u32 offset, + unsigned long bitmap, + gfp_t flags); /* * LSM protocol operations (NetLabel LSM/kernel API) @@ -492,30 +495,39 @@ static inline int netlbl_cfg_cipsov4_map_add(u32 doi, { return -ENOSYS; } -static inline int netlbl_secattr_catmap_walk( - struct netlbl_lsm_secattr_catmap *catmap, - u32 offset) +static inline int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, + u32 offset) { return -ENOENT; } -static inline int netlbl_secattr_catmap_walk_rng( - struct netlbl_lsm_secattr_catmap *catmap, - u32 offset) +static inline int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, + u32 offset) { return -ENOENT; } -static inline int netlbl_secattr_catmap_setbit( - struct netlbl_lsm_secattr_catmap *catmap, - u32 bit, - gfp_t flags) +static inline int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap, + u32 *offset, + unsigned long *bitmap) { return 0; } -static inline int netlbl_secattr_catmap_setrng( - struct netlbl_lsm_secattr_catmap *catmap, - u32 start, - u32 end, - gfp_t flags) +static inline int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap, + u32 bit, + gfp_t flags) +{ + return 0; +} +static inline int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap, + u32 start, + u32 end, + gfp_t flags) +{ + return 0; +} +static int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap, + u32 offset, + unsigned long bitmap, + gfp_t flags) { return 0; } diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 69e77c8ff285..05b708bbdb0d 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -890,8 +890,8 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, } for (;;) { - host_spot = netlbl_secattr_catmap_walk(secattr->attr.mls.cat, - host_spot + 1); + host_spot = netlbl_catmap_walk(secattr->attr.mls.cat, + host_spot + 1); if (host_spot < 0) break; @@ -973,7 +973,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, return -EPERM; break; } - ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat, + ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat, host_spot, GFP_ATOMIC); if (ret_val != 0) @@ -1039,8 +1039,7 @@ static int cipso_v4_map_cat_enum_hton(const struct cipso_v4_doi *doi_def, u32 cat_iter = 0; for (;;) { - cat = netlbl_secattr_catmap_walk(secattr->attr.mls.cat, - cat + 1); + cat = netlbl_catmap_walk(secattr->attr.mls.cat, cat + 1); if (cat < 0) break; if ((cat_iter + 2) > net_cat_len) @@ -1075,9 +1074,9 @@ static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def, u32 iter; for (iter = 0; iter < net_cat_len; iter += 2) { - ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat, - get_unaligned_be16(&net_cat[iter]), - GFP_ATOMIC); + ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat, + get_unaligned_be16(&net_cat[iter]), + GFP_ATOMIC); if (ret_val != 0) return ret_val; } @@ -1155,8 +1154,7 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def, return -ENOSPC; for (;;) { - iter = netlbl_secattr_catmap_walk(secattr->attr.mls.cat, - iter + 1); + iter = netlbl_catmap_walk(secattr->attr.mls.cat, iter + 1); if (iter < 0) break; cat_size += (iter == 0 ? 0 : sizeof(u16)); @@ -1164,8 +1162,7 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def, return -ENOSPC; array[array_cnt++] = iter; - iter = netlbl_secattr_catmap_walk_rng(secattr->attr.mls.cat, - iter); + iter = netlbl_catmap_walkrng(secattr->attr.mls.cat, iter); if (iter < 0) return -EFAULT; cat_size += sizeof(u16); @@ -1217,10 +1214,10 @@ static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def, else cat_low = 0; - ret_val = netlbl_secattr_catmap_setrng(secattr->attr.mls.cat, - cat_low, - cat_high, - GFP_ATOMIC); + ret_val = netlbl_catmap_setrng(&secattr->attr.mls.cat, + cat_low, + cat_high, + GFP_ATOMIC); if (ret_val != 0) return ret_val; } @@ -1335,16 +1332,12 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, secattr->flags |= NETLBL_SECATTR_MLS_LVL; if (tag_len > 4) { - secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); - if (secattr->attr.mls.cat == NULL) - return -ENOMEM; - ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def, &tag[4], tag_len - 4, secattr); if (ret_val != 0) { - netlbl_secattr_catmap_free(secattr->attr.mls.cat); + netlbl_catmap_free(secattr->attr.mls.cat); return ret_val; } @@ -1430,16 +1423,12 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def, secattr->flags |= NETLBL_SECATTR_MLS_LVL; if (tag_len > 4) { - secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); - if (secattr->attr.mls.cat == NULL) - return -ENOMEM; - ret_val = cipso_v4_map_cat_enum_ntoh(doi_def, &tag[4], tag_len - 4, secattr); if (ret_val != 0) { - netlbl_secattr_catmap_free(secattr->attr.mls.cat); + netlbl_catmap_free(secattr->attr.mls.cat); return ret_val; } @@ -1524,16 +1513,12 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def, secattr->flags |= NETLBL_SECATTR_MLS_LVL; if (tag_len > 4) { - secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); - if (secattr->attr.mls.cat == NULL) - return -ENOMEM; - ret_val = cipso_v4_map_cat_rng_ntoh(doi_def, &tag[4], tag_len - 4, secattr); if (ret_val != 0) { - netlbl_secattr_catmap_free(secattr->attr.mls.cat); + netlbl_catmap_free(secattr->attr.mls.cat); return ret_val; } diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 3045a964f39c..05ea4a4cc0ac 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -405,8 +405,72 @@ out_entry: * Security Attribute Functions */ +#define _CM_F_NONE 0x00000000 +#define _CM_F_ALLOC 0x00000001 +#define _CM_F_WALK 0x00000002 + /** - * netlbl_secattr_catmap_walk - Walk a LSM secattr catmap looking for a bit + * _netlbl_catmap_getnode - Get a individual node from a catmap + * @catmap: pointer to the category bitmap + * @offset: the requested offset + * @cm_flags: catmap flags, see _CM_F_* + * @gfp_flags: memory allocation flags + * + * Description: + * Iterate through the catmap looking for the node associated with @offset. + * If the _CM_F_ALLOC flag is set in @cm_flags and there is no associated node, + * one will be created and inserted into the catmap. If the _CM_F_WALK flag is + * set in @cm_flags and there is no associated node, the next highest node will + * be returned. Returns a pointer to the node on success, NULL on failure. + * + */ +static struct netlbl_lsm_catmap *_netlbl_catmap_getnode( + struct netlbl_lsm_catmap **catmap, + u32 offset, + unsigned int cm_flags, + gfp_t gfp_flags) +{ + struct netlbl_lsm_catmap *iter = *catmap; + struct netlbl_lsm_catmap *prev = NULL; + + if (iter == NULL) + goto catmap_getnode_alloc; + if (offset < iter->startbit) + goto catmap_getnode_walk; + while (iter && offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) { + prev = iter; + iter = iter->next; + } + if (iter == NULL || offset < iter->startbit) + goto catmap_getnode_walk; + + return iter; + +catmap_getnode_walk: + if (cm_flags & _CM_F_WALK) + return iter; +catmap_getnode_alloc: + if (!(cm_flags & _CM_F_ALLOC)) + return NULL; + + iter = netlbl_catmap_alloc(gfp_flags); + if (iter == NULL) + return NULL; + iter->startbit = offset & ~(NETLBL_CATMAP_SIZE - 1); + + if (prev == NULL) { + iter->next = *catmap; + *catmap = iter; + } else { + iter->next = prev->next; + prev->next = iter; + } + + return iter; +} + +/** + * netlbl_catmap_walk - Walk a LSM secattr catmap looking for a bit * @catmap: the category bitmap * @offset: the offset to start searching at, in bits * @@ -415,54 +479,51 @@ out_entry: * 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) +int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset) { - struct netlbl_lsm_secattr_catmap *iter = catmap; - u32 node_idx; - u32 node_bit; + struct netlbl_lsm_catmap *iter = catmap; + u32 idx; + u32 bit; NETLBL_CATMAP_MAPTYPE bitmap; + iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0); + if (iter == NULL) + return -ENOENT; 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); + offset -= iter->startbit; + idx = offset / NETLBL_CATMAP_MAPSIZE; + bit = offset % NETLBL_CATMAP_MAPSIZE; } else { - node_idx = 0; - node_bit = 0; + idx = 0; + bit = 0; } - bitmap = iter->bitmap[node_idx] >> node_bit; + bitmap = iter->bitmap[idx] >> bit; for (;;) { if (bitmap != 0) { while ((bitmap & NETLBL_CATMAP_BIT) == 0) { bitmap >>= 1; - node_bit++; + bit++; } return iter->startbit + - (NETLBL_CATMAP_MAPSIZE * node_idx) + node_bit; + (NETLBL_CATMAP_MAPSIZE * idx) + bit; } - if (++node_idx >= NETLBL_CATMAP_MAPCNT) { + if (++idx >= NETLBL_CATMAP_MAPCNT) { if (iter->next != NULL) { iter = iter->next; - node_idx = 0; + idx = 0; } else return -ENOENT; } - bitmap = iter->bitmap[node_idx]; - node_bit = 0; + bitmap = iter->bitmap[idx]; + bit = 0; } return -ENOENT; } /** - * netlbl_secattr_catmap_walk_rng - Find the end of a string of set bits + * netlbl_catmap_walkrng - Find the end of a string of set bits * @catmap: the category bitmap * @offset: the offset to start searching at, in bits * @@ -472,57 +533,105 @@ int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap, * the end of the bitmap. * */ -int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap, - u32 offset) +int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, u32 offset) { - struct netlbl_lsm_secattr_catmap *iter = catmap; - u32 node_idx; - u32 node_bit; + struct netlbl_lsm_catmap *iter; + struct netlbl_lsm_catmap *prev = NULL; + u32 idx; + u32 bit; NETLBL_CATMAP_MAPTYPE bitmask; NETLBL_CATMAP_MAPTYPE bitmap; + iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0); + if (iter == NULL) + return -ENOENT; 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); + offset -= iter->startbit; + idx = offset / NETLBL_CATMAP_MAPSIZE; + bit = offset % NETLBL_CATMAP_MAPSIZE; } else { - node_idx = 0; - node_bit = 0; + idx = 0; + bit = 0; } - bitmask = NETLBL_CATMAP_BIT << node_bit; + bitmask = NETLBL_CATMAP_BIT << bit; for (;;) { - bitmap = iter->bitmap[node_idx]; + bitmap = iter->bitmap[idx]; while (bitmask != 0 && (bitmap & bitmask) != 0) { bitmask <<= 1; - node_bit++; + bit++; } - if (bitmask != 0) + if (prev && idx == 0 && bit == 0) + return prev->startbit + NETLBL_CATMAP_SIZE - 1; + else if (bitmask != 0) return iter->startbit + - (NETLBL_CATMAP_MAPSIZE * node_idx) + - node_bit - 1; - else if (++node_idx >= NETLBL_CATMAP_MAPCNT) { + (NETLBL_CATMAP_MAPSIZE * idx) + bit - 1; + else if (++idx >= NETLBL_CATMAP_MAPCNT) { if (iter->next == NULL) - return iter->startbit + NETLBL_CATMAP_SIZE - 1; + return iter->startbit + NETLBL_CATMAP_SIZE - 1; + prev = iter; iter = iter->next; - node_idx = 0; + idx = 0; } bitmask = NETLBL_CATMAP_BIT; - node_bit = 0; + bit = 0; } return -ENOENT; } /** - * netlbl_secattr_catmap_setbit - Set a bit in a LSM secattr catmap - * @catmap: the category bitmap + * netlbl_catmap_getlong - Export an unsigned long bitmap + * @catmap: pointer to the category bitmap + * @offset: pointer to the requested offset + * @bitmap: the exported bitmap + * + * Description: + * Export a bitmap with an offset greater than or equal to @offset and return + * it in @bitmap. The @offset must be aligned to an unsigned long and will be + * updated on return if different from what was requested; if the catmap is + * empty at the requested offset and beyond, the @offset is set to (u32)-1. + * Returns zero on sucess, negative values on failure. + * + */ +int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap, + u32 *offset, + unsigned long *bitmap) +{ + struct netlbl_lsm_catmap *iter; + u32 off = *offset; + u32 idx; + + /* only allow aligned offsets */ + if ((off & (BITS_PER_LONG - 1)) != 0) + return -EINVAL; + + if (off < catmap->startbit) { + off = catmap->startbit; + *offset = off; + } + iter = _netlbl_catmap_getnode(&catmap, off, _CM_F_NONE, 0); + if (iter == NULL) { + *offset = (u32)-1; + return 0; + } + + if (off < iter->startbit) { + off = iter->startbit; + *offset = off; + } else + off -= iter->startbit; + + idx = off / NETLBL_CATMAP_MAPSIZE; + *bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_SIZE); + + return 0; +} + +/** + * netlbl_catmap_setbit - Set a bit in a LSM secattr catmap + * @catmap: pointer to the category bitmap * @bit: the bit to set * @flags: memory allocation flags * @@ -531,36 +640,27 @@ int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap, * negative values on failure. * */ -int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap, - u32 bit, - gfp_t flags) +int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap, + u32 bit, + gfp_t flags) { - struct netlbl_lsm_secattr_catmap *iter = catmap; - u32 node_bit; - u32 node_idx; + struct netlbl_lsm_catmap *iter; + u32 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); - } + iter = _netlbl_catmap_getnode(catmap, bit, _CM_F_ALLOC, flags); + if (iter == NULL) + return -ENOMEM; - /* 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; + bit -= iter->startbit; + idx = bit / NETLBL_CATMAP_MAPSIZE; + iter->bitmap[idx] |= NETLBL_CATMAP_BIT << (bit % NETLBL_CATMAP_MAPSIZE); return 0; } /** - * netlbl_secattr_catmap_setrng - Set a range of bits in a LSM secattr catmap - * @catmap: the category bitmap + * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap + * @catmap: pointer to the category bitmap * @start: the starting bit * @end: the last bit in the string * @flags: memory allocation flags @@ -570,36 +670,63 @@ int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap, * 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 netlbl_catmap_setrng(struct netlbl_lsm_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; + int rc = 0; + u32 spot = start; - /* 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, flags); + while (rc == 0 && spot <= end) { + if (((spot & (BITS_PER_LONG - 1)) != 0) && + ((end - spot) > BITS_PER_LONG)) { + rc = netlbl_catmap_setlong(catmap, + spot, + (unsigned long)-1, + flags); + spot += BITS_PER_LONG; + } else + rc = netlbl_catmap_setbit(catmap, spot++, flags); } - return ret_val; + return rc; +} + +/** + * netlbl_catmap_setlong - Import an unsigned long bitmap + * @catmap: pointer to the category bitmap + * @offset: offset to the start of the imported bitmap + * @bitmap: the bitmap to import + * @flags: memory allocation flags + * + * Description: + * Import the bitmap specified in @bitmap into @catmap, using the offset + * in @offset. The offset must be aligned to an unsigned long. Returns zero + * on success, negative values on failure. + * + */ +int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap, + u32 offset, + unsigned long bitmap, + gfp_t flags) +{ + struct netlbl_lsm_catmap *iter; + u32 idx; + + /* only allow aligned offsets */ + if ((offset & (BITS_PER_LONG - 1)) != 0) + return -EINVAL; + + iter = _netlbl_catmap_getnode(catmap, offset, _CM_F_ALLOC, flags); + if (iter == NULL) + return -ENOMEM; + + offset -= iter->startbit; + idx = offset / NETLBL_CATMAP_MAPSIZE; + iter->bitmap[idx] |= bitmap << (offset % NETLBL_CATMAP_MAPSIZE); + + return 0; } /* diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 820313a04d49..afe6a269ec17 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -86,51 +86,36 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src) * */ int ebitmap_netlbl_export(struct ebitmap *ebmap, - struct netlbl_lsm_secattr_catmap **catmap) + struct netlbl_lsm_catmap **catmap) { struct ebitmap_node *e_iter = ebmap->node; - struct netlbl_lsm_secattr_catmap *c_iter; - u32 cmap_idx, cmap_sft; - int i; - - /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, - * however, it is not always compatible with an array of unsigned long - * in ebitmap_node. - * In addition, you should pay attention the following implementation - * assumes unsigned long has a width equal with or less than 64-bit. - */ + unsigned long e_map; + u32 offset; + unsigned int iter; + int rc; 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); + if (*catmap != NULL) + netlbl_catmap_free(*catmap); + *catmap = NULL; while (e_iter) { - for (i = 0; i < EBITMAP_UNIT_NUMS; i++) { - unsigned int delta, e_startbit, c_endbit; - - e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE; - c_endbit = c_iter->startbit + NETLBL_CATMAP_SIZE; - if (e_startbit >= c_endbit) { - c_iter->next - = netlbl_secattr_catmap_alloc(GFP_ATOMIC); - if (c_iter->next == NULL) + offset = e_iter->startbit; + for (iter = 0; iter < EBITMAP_UNIT_NUMS; iter++) { + e_map = e_iter->maps[iter]; + if (e_map != 0) { + rc = netlbl_catmap_setlong(catmap, + offset, + e_map, + GFP_ATOMIC); + if (rc != 0) goto netlbl_export_failure; - c_iter = c_iter->next; - c_iter->startbit - = e_startbit & ~(NETLBL_CATMAP_SIZE - 1); } - delta = e_startbit - c_iter->startbit; - cmap_idx = delta / NETLBL_CATMAP_MAPSIZE; - cmap_sft = delta % NETLBL_CATMAP_MAPSIZE; - c_iter->bitmap[cmap_idx] - |= e_iter->maps[i] << cmap_sft; + offset += EBITMAP_UNIT_SIZE; } e_iter = e_iter->next; } @@ -138,7 +123,7 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, return 0; netlbl_export_failure: - netlbl_secattr_catmap_free(*catmap); + netlbl_catmap_free(*catmap); return -ENOMEM; } @@ -153,58 +138,44 @@ netlbl_export_failure: * */ int ebitmap_netlbl_import(struct ebitmap *ebmap, - struct netlbl_lsm_secattr_catmap *catmap) + struct netlbl_lsm_catmap *catmap) { + int rc; struct ebitmap_node *e_iter = NULL; - struct ebitmap_node *emap_prev = NULL; - struct netlbl_lsm_secattr_catmap *c_iter = catmap; - u32 c_idx, c_pos, e_idx, e_sft; + struct ebitmap_node *e_prev = NULL; + u32 offset = 0, idx; + unsigned long bitmap; - /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, - * however, it is not always compatible with an array of unsigned long - * in ebitmap_node. - * In addition, you should pay attention the following implementation - * assumes unsigned long has a width equal with or less than 64-bit. - */ + for (;;) { + rc = netlbl_catmap_getlong(catmap, &offset, &bitmap); + if (rc < 0) + goto netlbl_import_failure; + if (offset == (u32)-1) + return 0; - do { - for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) { - unsigned int delta; - u64 map = c_iter->bitmap[c_idx]; - - if (!map) - continue; - - c_pos = c_iter->startbit - + c_idx * NETLBL_CATMAP_MAPSIZE; - if (!e_iter - || c_pos >= e_iter->startbit + EBITMAP_SIZE) { - e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); - if (!e_iter) - goto netlbl_import_failure; - e_iter->startbit - = c_pos - (c_pos % EBITMAP_SIZE); - if (emap_prev == NULL) - ebmap->node = e_iter; - else - emap_prev->next = e_iter; - emap_prev = e_iter; - } - delta = c_pos - e_iter->startbit; - e_idx = delta / EBITMAP_UNIT_SIZE; - e_sft = delta % EBITMAP_UNIT_SIZE; - while (map) { - e_iter->maps[e_idx++] |= map & (-1UL); - map = EBITMAP_SHIFT_UNIT_SIZE(map); - } + if (e_iter == NULL || + offset >= e_iter->startbit + EBITMAP_SIZE) { + e_prev = e_iter; + e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); + if (e_iter == NULL) + goto netlbl_import_failure; + e_iter->startbit = offset & ~(EBITMAP_SIZE - 1); + if (e_prev == NULL) + ebmap->node = e_iter; + else + e_prev->next = e_iter; + ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; } - c_iter = c_iter->next; - } while (c_iter); - if (e_iter != NULL) - ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; - else - ebitmap_destroy(ebmap); + /* offset will always be aligned to an unsigned long */ + idx = EBITMAP_NODE_INDEX(e_iter, offset); + e_iter->maps[idx] = bitmap; + + /* next */ + offset += EBITMAP_UNIT_SIZE; + } + + /* NOTE: we should never reach this return */ return 0; netlbl_import_failure: diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index 712c8a7b8e8b..9637b8c71085 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h @@ -132,17 +132,17 @@ int ebitmap_write(struct ebitmap *e, void *fp); #ifdef CONFIG_NETLABEL int ebitmap_netlbl_export(struct ebitmap *ebmap, - struct netlbl_lsm_secattr_catmap **catmap); + struct netlbl_lsm_catmap **catmap); int ebitmap_netlbl_import(struct ebitmap *ebmap, - struct netlbl_lsm_secattr_catmap *catmap); + struct netlbl_lsm_catmap *catmap); #else static inline int ebitmap_netlbl_export(struct ebitmap *ebmap, - struct netlbl_lsm_secattr_catmap **catmap) + struct netlbl_lsm_catmap **catmap) { return -ENOMEM; } static inline int ebitmap_netlbl_import(struct ebitmap *ebmap, - struct netlbl_lsm_secattr_catmap *catmap) + struct netlbl_lsm_catmap *catmap) { return -ENOMEM; } diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index c062e9467b62..f97d0842e621 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -457,19 +457,16 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, sap->flags |= NETLBL_SECATTR_MLS_CAT; sap->attr.mls.lvl = level; - sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); - if (!sap->attr.mls.cat) - return -ENOMEM; - sap->attr.mls.cat->startbit = 0; + sap->attr.mls.cat = NULL; for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++) for (m = 0x80; m != 0; m >>= 1, cat++) { if ((m & *cp) == 0) continue; - rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat, - cat, GFP_ATOMIC); + rc = netlbl_catmap_setbit(&sap->attr.mls.cat, + cat, GFP_ATOMIC); if (rc < 0) { - netlbl_secattr_catmap_free(sap->attr.mls.cat); + netlbl_catmap_free(sap->attr.mls.cat); return rc; } } diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index f2c30801ce41..e6ab307ce86e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3209,9 +3209,9 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, break; } for (acat = -1, kcat = -1; acat == kcat; ) { - acat = netlbl_secattr_catmap_walk( - sap->attr.mls.cat, acat + 1); - kcat = netlbl_secattr_catmap_walk( + acat = netlbl_catmap_walk(sap->attr.mls.cat, + acat + 1); + kcat = netlbl_catmap_walk( skp->smk_netlabel.attr.mls.cat, kcat + 1); if (acat < 0 || kcat < 0) diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 32b248820840..3c720ff10591 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -787,7 +787,7 @@ static int cipso_seq_show(struct seq_file *s, void *v) struct list_head *list = v; struct smack_known *skp = list_entry(list, struct smack_known, list); - struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat; + struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat; char sep = '/'; int i; @@ -804,8 +804,8 @@ static int cipso_seq_show(struct seq_file *s, void *v) seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); - for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0; - i = netlbl_secattr_catmap_walk(cmp, i + 1)) { + for (i = netlbl_catmap_walk(cmp, 0); i >= 0; + i = netlbl_catmap_walk(cmp, i + 1)) { seq_printf(s, "%c%d", sep, i); sep = ','; } @@ -926,7 +926,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN); if (rc >= 0) { - netlbl_secattr_catmap_free(skp->smk_netlabel.attr.mls.cat); + netlbl_catmap_free(skp->smk_netlabel.attr.mls.cat); skp->smk_netlabel.attr.mls.cat = ncats.attr.mls.cat; skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl; rc = count; @@ -976,14 +976,14 @@ static int cipso2_seq_show(struct seq_file *s, void *v) struct list_head *list = v; struct smack_known *skp = list_entry(list, struct smack_known, list); - struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat; + struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat; char sep = '/'; int i; seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); - for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0; - i = netlbl_secattr_catmap_walk(cmp, i + 1)) { + for (i = netlbl_catmap_walk(cmp, 0); i >= 0; + i = netlbl_catmap_walk(cmp, i + 1)) { seq_printf(s, "%c%d", sep, i); sep = ','; }