Skip to content

Commit

Permalink
NetLabel: convert to an extensibile/sparse category bitmap
Browse files Browse the repository at this point in the history
The original NetLabel category bitmap was a straight char bitmap which worked
fine for the initial release as it only supported 240 bits due to limitations
in the CIPSO restricted bitmap tag (tag type 0x01).  This patch converts that
straight char bitmap into an extensibile/sparse bitmap in order to lay the
foundation for other CIPSO tag types and protocols.

This patch also has a nice side effect in that all of the security attributes
passed by NetLabel into the LSM are now in a format which is in the host's
native byte/bit ordering which makes the LSM specific code much simpler; look
at the changes in security/selinux/ss/ebitmap.c as an example.

Signed-off-by: Paul Moore <[email protected]>
Signed-off-by: James Morris <[email protected]>
  • Loading branch information
pcmoore authored and David S. Miller committed Dec 3, 2006
1 parent ef91fd5 commit 0275276
Show file tree
Hide file tree
Showing 8 changed files with 568 additions and 352 deletions.
102 changes: 99 additions & 3 deletions include/net/netlabel.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,22 @@ struct netlbl_lsm_cache {
void (*free) (const void *data);
void *data;
};
/* The catmap bitmap field MUST be a power of two in length and large
* enough to hold at least 240 bits. Special care (i.e. check the code!)
* should be used when changing these values as the LSM implementation
* probably has functions which rely on the sizes of these types to speed
* processing. */
#define NETLBL_CATMAP_MAPTYPE u64
#define NETLBL_CATMAP_MAPCNT 4
#define NETLBL_CATMAP_MAPSIZE (sizeof(NETLBL_CATMAP_MAPTYPE) * 8)
#define NETLBL_CATMAP_SIZE (NETLBL_CATMAP_MAPSIZE * \
NETLBL_CATMAP_MAPCNT)
#define NETLBL_CATMAP_BIT (NETLBL_CATMAP_MAPTYPE)0x01
struct netlbl_lsm_secattr_catmap {
u32 startbit;
NETLBL_CATMAP_MAPTYPE bitmap[NETLBL_CATMAP_MAPCNT];
struct netlbl_lsm_secattr_catmap *next;
};
#define NETLBL_SECATTR_NONE 0x00000000
#define NETLBL_SECATTR_DOMAIN 0x00000001
#define NETLBL_SECATTR_CACHE 0x00000002
Expand All @@ -122,8 +138,7 @@ struct netlbl_lsm_secattr {
char *domain;

u32 mls_lvl;
unsigned char *mls_cat;
size_t mls_cat_len;
struct netlbl_lsm_secattr_catmap *mls_cat;

struct netlbl_lsm_cache *cache;
};
Expand Down Expand Up @@ -170,6 +185,41 @@ static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache)
kfree(cache);
}

/**
* netlbl_secattr_catmap_alloc - Allocate a LSM secattr catmap
* @flags: memory allocation flags
*
* Description:
* Allocate memory for a LSM secattr catmap, returns a pointer on success, NULL
* on failure.
*
*/
static inline struct netlbl_lsm_secattr_catmap *netlbl_secattr_catmap_alloc(
gfp_t flags)
{
return kzalloc(sizeof(struct netlbl_lsm_secattr_catmap), flags);
}

/**
* netlbl_secattr_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)
{
struct netlbl_lsm_secattr_catmap *iter;

do {
iter = catmap;
catmap = catmap->next;
kfree(iter);
} while (catmap);
}

/**
* netlbl_secattr_init - Initialize a netlbl_lsm_secattr struct
* @secattr: the struct to initialize
Expand Down Expand Up @@ -200,7 +250,8 @@ static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr)
if (secattr->cache)
netlbl_secattr_cache_free(secattr->cache);
kfree(secattr->domain);
kfree(secattr->mls_cat);
if (secattr->mls_cat)
netlbl_secattr_catmap_free(secattr->mls_cat);
}

/**
Expand Down Expand Up @@ -231,6 +282,51 @@ static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
kfree(secattr);
}

#ifdef CONFIG_NETLABEL
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);
#else
static inline int netlbl_secattr_catmap_walk(
struct netlbl_lsm_secattr_catmap *catmap,
u32 offset)
{
return -ENOENT;
}

static inline int netlbl_secattr_catmap_walk_rng(
struct netlbl_lsm_secattr_catmap *catmap,
u32 offset)
{
return -ENOENT;
}

static inline int netlbl_secattr_catmap_setbit(
struct netlbl_lsm_secattr_catmap *catmap,
u32 bit,
gfp_t flags)
{
return 0;
}

static inline int netlbl_secattr_catmap_setrng(
struct netlbl_lsm_secattr_catmap *catmap,
u32 start,
u32 end,
gfp_t flags)
{
return 0;
}
#endif

/*
* LSM protocol operations
*/
Expand Down
168 changes: 69 additions & 99 deletions net/ipv4/cipso_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -819,8 +819,7 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
/**
* cipso_v4_map_cat_rbm_hton - Perform a category mapping from host to network
* @doi_def: the DOI definition
* @host_cat: the category bitmap in host format
* @host_cat_len: the length of the host's category bitmap in bytes
* @secattr: the security attributes
* @net_cat: the zero'd out category bitmap in network/CIPSO format
* @net_cat_len: the length of the CIPSO bitmap in bytes
*
Expand All @@ -831,128 +830,111 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
*
*/
static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
const unsigned char *host_cat,
u32 host_cat_len,
const struct netlbl_lsm_secattr *secattr,
unsigned char *net_cat,
u32 net_cat_len)
{
int host_spot = -1;
u32 net_spot;
u32 net_spot = CIPSO_V4_INV_CAT;
u32 net_spot_max = 0;
u32 host_clen_bits = host_cat_len * 8;
u32 net_clen_bits = net_cat_len * 8;
u32 host_cat_size;
u32 *host_cat_array;
u32 host_cat_size = 0;
u32 *host_cat_array = NULL;

switch (doi_def->type) {
case CIPSO_V4_MAP_PASS:
net_spot_max = host_cat_len;
while (net_spot_max > 0 && host_cat[net_spot_max - 1] == 0)
net_spot_max--;
if (net_spot_max > net_cat_len)
return -EINVAL;
memcpy(net_cat, host_cat, net_spot_max);
return net_spot_max;
case CIPSO_V4_MAP_STD:
if (doi_def->type == CIPSO_V4_MAP_STD) {
host_cat_size = doi_def->map.std->cat.local_size;
host_cat_array = doi_def->map.std->cat.local;
for (;;) {
host_spot = cipso_v4_bitmap_walk(host_cat,
host_clen_bits,
host_spot + 1,
1);
if (host_spot < 0)
break;
}

for (;;) {
host_spot = netlbl_secattr_catmap_walk(secattr->mls_cat,
host_spot + 1);
if (host_spot < 0)
break;

switch (doi_def->type) {
case CIPSO_V4_MAP_PASS:
net_spot = host_spot;
break;
case CIPSO_V4_MAP_STD:
if (host_spot >= host_cat_size)
return -EPERM;

net_spot = host_cat_array[host_spot];
if (net_spot >= CIPSO_V4_INV_CAT)
return -EPERM;
if (net_spot >= net_clen_bits)
return -ENOSPC;
cipso_v4_bitmap_setbit(net_cat, net_spot, 1);

if (net_spot > net_spot_max)
net_spot_max = net_spot;
break;
}
if (net_spot >= net_clen_bits)
return -ENOSPC;
cipso_v4_bitmap_setbit(net_cat, net_spot, 1);

if (host_spot == -2)
return -EFAULT;

if (++net_spot_max % 8)
return net_spot_max / 8 + 1;
return net_spot_max / 8;
if (net_spot > net_spot_max)
net_spot_max = net_spot;
}

return -EINVAL;
if (++net_spot_max % 8)
return net_spot_max / 8 + 1;
return net_spot_max / 8;
}

/**
* cipso_v4_map_cat_rbm_ntoh - Perform a category mapping from network to host
* @doi_def: the DOI definition
* @net_cat: the category bitmap in network/CIPSO format
* @net_cat_len: the length of the CIPSO bitmap in bytes
* @host_cat: the zero'd out category bitmap in host format
* @host_cat_len: the length of the host's category bitmap in bytes
* @secattr: the security attributes
*
* Description:
* Perform a label mapping to translate a CIPSO bitmap to the correct local
* MLS category bitmap using the given DOI definition. Returns the minimum
* size in bytes of the host bitmap on success, negative values otherwise.
* MLS category bitmap using the given DOI definition. Returns zero on
* success, negative values on failure.
*
*/
static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
const unsigned char *net_cat,
u32 net_cat_len,
unsigned char *host_cat,
u32 host_cat_len)
struct netlbl_lsm_secattr *secattr)
{
u32 host_spot;
u32 host_spot_max = 0;
int ret_val;
int net_spot = -1;
u32 host_spot = CIPSO_V4_INV_CAT;
u32 net_clen_bits = net_cat_len * 8;
u32 host_clen_bits = host_cat_len * 8;
u32 net_cat_size;
u32 *net_cat_array;
u32 net_cat_size = 0;
u32 *net_cat_array = NULL;

switch (doi_def->type) {
case CIPSO_V4_MAP_PASS:
if (net_cat_len > host_cat_len)
return -EINVAL;
memcpy(host_cat, net_cat, net_cat_len);
return net_cat_len;
case CIPSO_V4_MAP_STD:
if (doi_def->type == CIPSO_V4_MAP_STD) {
net_cat_size = doi_def->map.std->cat.cipso_size;
net_cat_array = doi_def->map.std->cat.cipso;
for (;;) {
net_spot = cipso_v4_bitmap_walk(net_cat,
net_clen_bits,
net_spot + 1,
1);
if (net_spot < 0)
break;
if (net_spot >= net_cat_size ||
net_cat_array[net_spot] >= CIPSO_V4_INV_CAT)
return -EPERM;
}

for (;;) {
net_spot = cipso_v4_bitmap_walk(net_cat,
net_clen_bits,
net_spot + 1,
1);
if (net_spot < 0) {
if (net_spot == -2)
return -EFAULT;
return 0;
}

switch (doi_def->type) {
case CIPSO_V4_MAP_PASS:
host_spot = net_spot;
break;
case CIPSO_V4_MAP_STD:
if (net_spot >= net_cat_size)
return -EPERM;
host_spot = net_cat_array[net_spot];
if (host_spot >= CIPSO_V4_INV_CAT)
return -EPERM;
if (host_spot >= host_clen_bits)
return -ENOSPC;
cipso_v4_bitmap_setbit(host_cat, host_spot, 1);

if (host_spot > host_spot_max)
host_spot_max = host_spot;
break;
}

if (net_spot == -2)
return -EFAULT;

if (++host_spot_max % 8)
return host_spot_max / 8 + 1;
return host_spot_max / 8;
ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat,
host_spot,
GFP_ATOMIC);
if (ret_val != 0)
return ret_val;
}

return -EINVAL;
Expand Down Expand Up @@ -1016,8 +998,7 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,

if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
ret_val = cipso_v4_map_cat_rbm_hton(doi_def,
secattr->mls_cat,
secattr->mls_cat_len,
secattr,
&buffer[4],
buffer_len - 4);
if (ret_val < 0)
Expand Down Expand Up @@ -1067,31 +1048,20 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
secattr->flags |= NETLBL_SECATTR_MLS_LVL;

if (tag_len > 4) {
switch (doi_def->type) {
case CIPSO_V4_MAP_PASS:
secattr->mls_cat_len = tag_len - 4;
break;
case CIPSO_V4_MAP_STD:
secattr->mls_cat_len =
doi_def->map.std->cat.local_size;
break;
}
secattr->mls_cat = kzalloc(secattr->mls_cat_len, GFP_ATOMIC);
secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
if (secattr->mls_cat == NULL)
return -ENOMEM;

ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
&tag[4],
tag_len - 4,
secattr->mls_cat,
secattr->mls_cat_len);
if (ret_val < 0) {
kfree(secattr->mls_cat);
secattr);
if (ret_val != 0) {
netlbl_secattr_catmap_free(secattr->mls_cat);
return ret_val;
} else if (ret_val > 0) {
secattr->mls_cat_len = ret_val;
secattr->flags |= NETLBL_SECATTR_MLS_CAT;
}

secattr->flags |= NETLBL_SECATTR_MLS_CAT;
}

return 0;
Expand Down
Loading

0 comments on commit 0275276

Please sign in to comment.