mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 22:02:28 +00:00
Merge branch 'next' of git://git.infradead.org/users/pcmoore/selinux into next
This commit is contained in:
commit
103ae675b1
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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 = ',';
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user