Loading include/net/netlabel.h +53 −41 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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; }; /** Loading Loading @@ -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; Loading Loading @@ -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: Loading @@ -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); } } /** Loading Loading @@ -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); } /** Loading Loading @@ -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, 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_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, 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) Loading Loading @@ -492,33 +495,42 @@ 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, 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, 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, static inline int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap, u32 *offset, unsigned long *bitmap) { return 0; } static inline int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap, u32 bit, gfp_t flags) { return 0; } static inline int netlbl_secattr_catmap_setrng( struct netlbl_lsm_secattr_catmap *catmap, 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; } static inline int netlbl_enabled(void) { return 0; Loading net/ipv4/cipso_ipv4.c +16 −31 Original line number Diff line number Diff line Loading @@ -890,7 +890,7 @@ 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 = netlbl_catmap_walk(secattr->attr.mls.cat, host_spot + 1); if (host_spot < 0) break; Loading Loading @@ -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) Loading Loading @@ -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) Loading Loading @@ -1075,7 +1074,7 @@ 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, ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat, get_unaligned_be16(&net_cat[iter]), GFP_ATOMIC); if (ret_val != 0) Loading Loading @@ -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)); Loading @@ -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); Loading Loading @@ -1217,7 +1214,7 @@ 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, ret_val = netlbl_catmap_setrng(&secattr->attr.mls.cat, cat_low, cat_high, GFP_ATOMIC); Loading Loading @@ -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; } Loading Loading @@ -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; } Loading Loading @@ -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; } Loading net/netlabel/netlabel_kapi.c +227 −100 Original line number Diff line number Diff line Loading @@ -405,8 +405,72 @@ int netlbl_cfg_cipsov4_map_add(u32 doi, * 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 * Loading @@ -415,54 +479,51 @@ int netlbl_cfg_cipsov4_map_add(u32 doi, * 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; if (offset > iter->startbit) { while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) { iter = iter->next; iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0); if (iter == NULL) return -ENOENT; } node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE; node_bit = offset - iter->startbit - (NETLBL_CATMAP_MAPSIZE * node_idx); if (offset > iter->startbit) { 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 * Loading @@ -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; if (offset > iter->startbit) { while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) { iter = iter->next; iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0); if (iter == NULL) return -ENOENT; } node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE; node_bit = offset - iter->startbit - (NETLBL_CATMAP_MAPSIZE * node_idx); if (offset > iter->startbit) { 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; 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 * Loading @@ -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, 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) iter = _netlbl_catmap_getnode(catmap, bit, _CM_F_ALLOC, flags); if (iter == NULL) return -ENOMEM; iter = iter->next; iter->startbit = bit & ~(NETLBL_CATMAP_SIZE - 1); } /* 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 Loading @@ -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, 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; /* 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; int rc = 0; u32 spot = start; 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); } ret_val = netlbl_secattr_catmap_setbit(iter, spot, flags); return rc; } return ret_val; /** * 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; } /* Loading security/selinux/ss/ebitmap.c +52 −81 Original line number Diff line number Diff line Loading @@ -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; } Loading @@ -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; } Loading @@ -153,58 +138,44 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, * */ 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; /* 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. */ do { for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) { unsigned int delta; u64 map = c_iter->bitmap[c_idx]; struct ebitmap_node *e_prev = NULL; u32 offset = 0, idx; unsigned long bitmap; if (!map) continue; for (;;) { rc = netlbl_catmap_getlong(catmap, &offset, &bitmap); if (rc < 0) goto netlbl_import_failure; if (offset == (u32)-1) return 0; c_pos = c_iter->startbit + c_idx * NETLBL_CATMAP_MAPSIZE; if (!e_iter || c_pos >= e_iter->startbit + EBITMAP_SIZE) { 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) if (e_iter == NULL) goto netlbl_import_failure; e_iter->startbit = c_pos - (c_pos % EBITMAP_SIZE); if (emap_prev == NULL) e_iter->startbit = offset & ~(EBITMAP_SIZE - 1); if (e_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); e_prev->next = e_iter; ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; } /* 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; } c_iter = c_iter->next; } while (c_iter); if (e_iter != NULL) ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; else ebitmap_destroy(ebmap); /* NOTE: we should never reach this return */ return 0; netlbl_import_failure: Loading security/selinux/ss/ebitmap.h +4 −4 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading
include/net/netlabel.h +53 −41 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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; }; /** Loading Loading @@ -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; Loading Loading @@ -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: Loading @@ -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); } } /** Loading Loading @@ -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); } /** Loading Loading @@ -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, 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_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, 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) Loading Loading @@ -492,33 +495,42 @@ 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, 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, 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, static inline int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap, u32 *offset, unsigned long *bitmap) { return 0; } static inline int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap, u32 bit, gfp_t flags) { return 0; } static inline int netlbl_secattr_catmap_setrng( struct netlbl_lsm_secattr_catmap *catmap, 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; } static inline int netlbl_enabled(void) { return 0; Loading
net/ipv4/cipso_ipv4.c +16 −31 Original line number Diff line number Diff line Loading @@ -890,7 +890,7 @@ 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 = netlbl_catmap_walk(secattr->attr.mls.cat, host_spot + 1); if (host_spot < 0) break; Loading Loading @@ -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) Loading Loading @@ -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) Loading Loading @@ -1075,7 +1074,7 @@ 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, ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat, get_unaligned_be16(&net_cat[iter]), GFP_ATOMIC); if (ret_val != 0) Loading Loading @@ -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)); Loading @@ -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); Loading Loading @@ -1217,7 +1214,7 @@ 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, ret_val = netlbl_catmap_setrng(&secattr->attr.mls.cat, cat_low, cat_high, GFP_ATOMIC); Loading Loading @@ -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; } Loading Loading @@ -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; } Loading Loading @@ -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; } Loading
net/netlabel/netlabel_kapi.c +227 −100 Original line number Diff line number Diff line Loading @@ -405,8 +405,72 @@ int netlbl_cfg_cipsov4_map_add(u32 doi, * 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 * Loading @@ -415,54 +479,51 @@ int netlbl_cfg_cipsov4_map_add(u32 doi, * 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; if (offset > iter->startbit) { while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) { iter = iter->next; iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0); if (iter == NULL) return -ENOENT; } node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE; node_bit = offset - iter->startbit - (NETLBL_CATMAP_MAPSIZE * node_idx); if (offset > iter->startbit) { 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 * Loading @@ -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; if (offset > iter->startbit) { while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) { iter = iter->next; iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0); if (iter == NULL) return -ENOENT; } node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE; node_bit = offset - iter->startbit - (NETLBL_CATMAP_MAPSIZE * node_idx); if (offset > iter->startbit) { 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; 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 * Loading @@ -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, 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) iter = _netlbl_catmap_getnode(catmap, bit, _CM_F_ALLOC, flags); if (iter == NULL) return -ENOMEM; iter = iter->next; iter->startbit = bit & ~(NETLBL_CATMAP_SIZE - 1); } /* 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 Loading @@ -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, 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; /* 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; int rc = 0; u32 spot = start; 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); } ret_val = netlbl_secattr_catmap_setbit(iter, spot, flags); return rc; } return ret_val; /** * 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; } /* Loading
security/selinux/ss/ebitmap.c +52 −81 Original line number Diff line number Diff line Loading @@ -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; } Loading @@ -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; } Loading @@ -153,58 +138,44 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, * */ 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; /* 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. */ do { for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) { unsigned int delta; u64 map = c_iter->bitmap[c_idx]; struct ebitmap_node *e_prev = NULL; u32 offset = 0, idx; unsigned long bitmap; if (!map) continue; for (;;) { rc = netlbl_catmap_getlong(catmap, &offset, &bitmap); if (rc < 0) goto netlbl_import_failure; if (offset == (u32)-1) return 0; c_pos = c_iter->startbit + c_idx * NETLBL_CATMAP_MAPSIZE; if (!e_iter || c_pos >= e_iter->startbit + EBITMAP_SIZE) { 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) if (e_iter == NULL) goto netlbl_import_failure; e_iter->startbit = c_pos - (c_pos % EBITMAP_SIZE); if (emap_prev == NULL) e_iter->startbit = offset & ~(EBITMAP_SIZE - 1); if (e_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); e_prev->next = e_iter; ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; } /* 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; } c_iter = c_iter->next; } while (c_iter); if (e_iter != NULL) ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; else ebitmap_destroy(ebmap); /* NOTE: we should never reach this return */ return 0; netlbl_import_failure: Loading
security/selinux/ss/ebitmap.h +4 −4 Original line number Diff line number Diff line Loading @@ -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; } Loading