diff options
Diffstat (limited to 'net/netlabel')
-rw-r--r-- | net/netlabel/netlabel_cipso_v4.c | 6 | ||||
-rw-r--r-- | net/netlabel/netlabel_kapi.c | 329 | ||||
-rw-r--r-- | net/netlabel/netlabel_mgmt.c | 56 | ||||
-rw-r--r-- | net/netlabel/netlabel_unlabeled.c | 3 | ||||
-rw-r--r-- | net/netlabel/netlabel_user.c | 6 |
5 files changed, 261 insertions, 139 deletions
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index c2f2a53a4879..7fd1104ba900 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -324,8 +324,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info, return 0; add_std_failure: - if (doi_def) - cipso_v4_doi_free(doi_def); + cipso_v4_doi_free(doi_def); return ret_val; } @@ -641,7 +640,8 @@ static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg) if (ret_val != 0) goto listall_cb_failure; - return genlmsg_end(cb_arg->skb, data); + genlmsg_end(cb_arg->skb, data); + return 0; listall_cb_failure: genlmsg_cancel(cb_arg->skb, data); diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 3045a964f39c..a845cd4cf21e 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -170,7 +170,6 @@ int netlbl_cfg_unlbl_map_add(const char *domain, #endif /* IPv6 */ default: goto cfg_unlbl_map_add_failure; - break; } entry->def.addrsel = addrmap; @@ -247,7 +246,6 @@ int netlbl_cfg_unlbl_static_add(struct net *net, * @addr: IP address in network byte order (struct in[6]_addr) * @mask: address mask in network byte order (struct in[6]_addr) * @family: address family - * @secid: LSM secid value for the entry * @audit_info: NetLabel audit information * * Description: @@ -405,8 +403,72 @@ out_entry: * Security Attribute Functions */ +#define _CM_F_NONE 0x00000000 +#define _CM_F_ALLOC 0x00000001 +#define _CM_F_WALK 0x00000002 + +/** + * _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_secattr_catmap_walk - Walk a LSM secattr catmap looking for a bit + * 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 +477,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 +531,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 +638,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 +668,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; - - /* 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); + 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); } - 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/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index e66e977ef2fa..70440748fe5c 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c @@ -93,23 +93,20 @@ static int netlbl_mgmt_add_common(struct genl_info *info, struct netlbl_audit *audit_info) { int ret_val = -EINVAL; - struct netlbl_dom_map *entry = NULL; struct netlbl_domaddr_map *addrmap = NULL; struct cipso_v4_doi *cipsov4 = NULL; u32 tmp_val; + struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL); - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (entry == NULL) { - ret_val = -ENOMEM; - goto add_failure; - } + if (!entry) + return -ENOMEM; entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); if (info->attrs[NLBL_MGMT_A_DOMAIN]) { size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]); entry->domain = kmalloc(tmp_size, GFP_KERNEL); if (entry->domain == NULL) { ret_val = -ENOMEM; - goto add_failure; + goto add_free_entry; } nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); @@ -125,16 +122,16 @@ static int netlbl_mgmt_add_common(struct genl_info *info, break; case NETLBL_NLTYPE_CIPSOV4: if (!info->attrs[NLBL_MGMT_A_CV4DOI]) - goto add_failure; + goto add_free_domain; tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); cipsov4 = cipso_v4_doi_getdef(tmp_val); if (cipsov4 == NULL) - goto add_failure; + goto add_free_domain; entry->def.cipso = cipsov4; break; default: - goto add_failure; + goto add_free_domain; } if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) { @@ -145,7 +142,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info, addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL); if (addrmap == NULL) { ret_val = -ENOMEM; - goto add_failure; + goto add_doi_put_def; } INIT_LIST_HEAD(&addrmap->list4); INIT_LIST_HEAD(&addrmap->list6); @@ -153,12 +150,12 @@ static int netlbl_mgmt_add_common(struct genl_info *info, if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) != sizeof(struct in_addr)) { ret_val = -EINVAL; - goto add_failure; + goto add_free_addrmap; } if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) != sizeof(struct in_addr)) { ret_val = -EINVAL; - goto add_failure; + goto add_free_addrmap; } addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]); mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]); @@ -166,7 +163,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info, map = kzalloc(sizeof(*map), GFP_KERNEL); if (map == NULL) { ret_val = -ENOMEM; - goto add_failure; + goto add_free_addrmap; } map->list.addr = addr->s_addr & mask->s_addr; map->list.mask = mask->s_addr; @@ -178,7 +175,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info, ret_val = netlbl_af4list_add(&map->list, &addrmap->list4); if (ret_val != 0) { kfree(map); - goto add_failure; + goto add_free_addrmap; } entry->def.type = NETLBL_NLTYPE_ADDRSELECT; @@ -192,7 +189,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info, addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL); if (addrmap == NULL) { ret_val = -ENOMEM; - goto add_failure; + goto add_doi_put_def; } INIT_LIST_HEAD(&addrmap->list4); INIT_LIST_HEAD(&addrmap->list6); @@ -200,12 +197,12 @@ static int netlbl_mgmt_add_common(struct genl_info *info, if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) != sizeof(struct in6_addr)) { ret_val = -EINVAL; - goto add_failure; + goto add_free_addrmap; } if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) != sizeof(struct in6_addr)) { ret_val = -EINVAL; - goto add_failure; + goto add_free_addrmap; } addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]); mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]); @@ -213,7 +210,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info, map = kzalloc(sizeof(*map), GFP_KERNEL); if (map == NULL) { ret_val = -ENOMEM; - goto add_failure; + goto add_free_addrmap; } map->list.addr = *addr; map->list.addr.s6_addr32[0] &= mask->s6_addr32[0]; @@ -227,7 +224,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info, ret_val = netlbl_af6list_add(&map->list, &addrmap->list6); if (ret_val != 0) { kfree(map); - goto add_failure; + goto add_free_addrmap; } entry->def.type = NETLBL_NLTYPE_ADDRSELECT; @@ -237,16 +234,17 @@ static int netlbl_mgmt_add_common(struct genl_info *info, ret_val = netlbl_domhsh_add(entry, audit_info); if (ret_val != 0) - goto add_failure; + goto add_free_addrmap; return 0; -add_failure: - if (cipsov4) - cipso_v4_doi_putdef(cipsov4); - if (entry) - kfree(entry->domain); +add_free_addrmap: kfree(addrmap); +add_doi_put_def: + cipso_v4_doi_putdef(cipsov4); +add_free_domain: + kfree(entry->domain); +add_free_entry: kfree(entry); return ret_val; } @@ -456,7 +454,8 @@ static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg) goto listall_cb_failure; cb_arg->seq++; - return genlmsg_end(cb_arg->skb, data); + genlmsg_end(cb_arg->skb, data); + return 0; listall_cb_failure: genlmsg_cancel(cb_arg->skb, data); @@ -620,7 +619,8 @@ static int netlbl_mgmt_protocols_cb(struct sk_buff *skb, if (ret_val != 0) goto protocols_cb_failure; - return genlmsg_end(skb, data); + genlmsg_end(skb, data); + return 0; protocols_cb_failure: genlmsg_cancel(skb, data); diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 78a63c18779e..aec7994f78cf 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -1163,7 +1163,8 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd, goto list_cb_failure; cb_arg->seq++; - return genlmsg_end(cb_arg->skb, data); + genlmsg_end(cb_arg->skb, data); + return 0; list_cb_failure: genlmsg_cancel(cb_arg->skb, data); diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c index 1e779bb7fa43..adf8b7900da2 100644 --- a/net/netlabel/netlabel_user.c +++ b/net/netlabel/netlabel_user.c @@ -71,11 +71,7 @@ int __init netlbl_netlink_init(void) if (ret_val != 0) return ret_val; - ret_val = netlbl_unlabel_genl_init(); - if (ret_val != 0) - return ret_val; - - return 0; + return netlbl_unlabel_genl_init(); } /* |