Commit 9fe79ad1 authored by KaiGai Kohei's avatar KaiGai Kohei Committed by James Morris

SELinux: improve performance when AVC misses.

* We add ebitmap_for_each_positive_bit() which enables to walk on
  any positive bit on the given ebitmap, to improve its performance
  using common bit-operations defined in linux/bitops.h.
  In the previous version, this logic was implemented using a combination
  of ebitmap_for_each_bit() and ebitmap_node_get_bit(), but is was worse
  in performance aspect.
  This logic is most frequestly used to compute a new AVC entry,
  so this patch can improve SELinux performance when AVC misses are happen.
* struct ebitmap_node is redefined as an array of "unsigned long", to get
  suitable for using find_next_bit() which is fasted than iteration of
  shift and logical operation, and to maximize memory usage allocated
  from general purpose slab.
* Any ebitmap_for_each_bit() are repleced by the new implementation
  in ss/service.c and ss/mls.c. Some of related implementation are
  changed, however, there is no incompatibility with the previous
  version.
* The width of any new line are less or equal than 80-chars.

The following benchmark shows the effect of this patch, when we
access many files which have different security context one after
another. The number is more than /selinux/avc/cache_threshold, so
any access always causes AVC misses.

      selinux-2.6      selinux-2.6-ebitmap
AVG:   22.763 [s]          8.750 [s]
STD:    0.265              0.019
------------------------------------------
1st:   22.558 [s]          8.786 [s]
2nd:   22.458 [s]          8.750 [s]
3rd:   22.478 [s]          8.754 [s]
4th:   22.724 [s]          8.745 [s]
5th:   22.918 [s]          8.748 [s]
6th:   22.905 [s]          8.764 [s]
7th:   23.238 [s]          8.726 [s]
8th:   22.822 [s]          8.729 [s]
Signed-off-by: default avatarKaiGai Kohei <kaigai@ak.jp.nec.com>
Acked-by: default avatarStephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 3f12070e
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
* *
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
*/ */
/*
* Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
* Applied standard bit operations to improve bitmap scanning.
*/
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2) ...@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
n2 = e2->node; n2 = e2->node;
while (n1 && n2 && while (n1 && n2 &&
(n1->startbit == n2->startbit) && (n1->startbit == n2->startbit) &&
(n1->map == n2->map)) { !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) {
n1 = n1->next; n1 = n1->next;
n2 = n2->next; n2 = n2->next;
} }
...@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src) ...@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
return -ENOMEM; return -ENOMEM;
} }
new->startbit = n->startbit; new->startbit = n->startbit;
new->map = n->map; memcpy(new->maps, n->maps, EBITMAP_SIZE / 8);
new->next = NULL; new->next = NULL;
if (prev) if (prev)
prev->next = new; prev->next = new;
...@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, ...@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
{ {
struct ebitmap_node *e_iter = ebmap->node; struct ebitmap_node *e_iter = ebmap->node;
struct netlbl_lsm_secattr_catmap *c_iter; struct netlbl_lsm_secattr_catmap *c_iter;
u32 cmap_idx; u32 cmap_idx, cmap_sft;
int i;
/* This function is a much simpler because SELinux's MAPTYPE happens /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is * however, it is not always compatible with an array of unsigned long
* changed from a u64 this function will most likely need to be changed * in ebitmap_node.
* as well. It's not ideal but I think the tradeoff in terms of * In addition, you should pay attention the following implementation
* neatness and speed is worth it. */ * assumes unsigned long has a width equal with or less than 64-bit.
*/
if (e_iter == NULL) { if (e_iter == NULL) {
*catmap = NULL; *catmap = NULL;
...@@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, ...@@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1); c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
while (e_iter != NULL) { while (e_iter != NULL) {
if (e_iter->startbit >= for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
(c_iter->startbit + NETLBL_CATMAP_SIZE)) { unsigned int delta, e_startbit, c_endbit;
c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
if (c_iter->next == NULL) e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
goto netlbl_export_failure; c_endbit = c_iter->startbit + NETLBL_CATMAP_SIZE;
c_iter = c_iter->next; if (e_startbit >= c_endbit) {
c_iter->startbit = e_iter->startbit & c_iter->next
~(NETLBL_CATMAP_SIZE - 1); = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
if (c_iter->next == NULL)
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[cmap_idx] << cmap_sft;
e_iter = e_iter->next;
} }
cmap_idx = (e_iter->startbit - c_iter->startbit) /
NETLBL_CATMAP_MAPSIZE;
c_iter->bitmap[cmap_idx] = e_iter->map;
e_iter = e_iter->next;
} }
return 0; return 0;
...@@ -128,7 +142,7 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, ...@@ -128,7 +142,7 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
/** /**
* ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
* @ebmap: the ebitmap to export * @ebmap: the ebitmap to import
* @catmap: the NetLabel category bitmap * @catmap: the NetLabel category bitmap
* *
* Description: * Description:
...@@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap, ...@@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
struct ebitmap_node *e_iter = NULL; struct ebitmap_node *e_iter = NULL;
struct ebitmap_node *emap_prev = NULL; struct ebitmap_node *emap_prev = NULL;
struct netlbl_lsm_secattr_catmap *c_iter = catmap; struct netlbl_lsm_secattr_catmap *c_iter = catmap;
u32 c_idx; u32 c_idx, c_pos, e_idx, e_sft;
/* This function is a much simpler because SELinux's MAPTYPE happens /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
* to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is * however, it is not always compatible with an array of unsigned long
* changed from a u64 this function will most likely need to be changed * in ebitmap_node.
* as well. It's not ideal but I think the tradeoff in terms of * In addition, you should pay attention the following implementation
* neatness and speed is worth it. */ * assumes unsigned long has a width equal with or less than 64-bit.
*/
do { do {
for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) { for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
if (c_iter->bitmap[c_idx] == 0) unsigned int delta;
u64 map = c_iter->bitmap[c_idx];
if (!map)
continue; continue;
e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); c_pos = c_iter->startbit
if (e_iter == NULL) + c_idx * NETLBL_CATMAP_MAPSIZE;
goto netlbl_import_failure; if (!e_iter
if (emap_prev == NULL) || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
ebmap->node = e_iter; e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
else if (!e_iter)
emap_prev->next = e_iter; goto netlbl_import_failure;
emap_prev = e_iter; e_iter->startbit
= c_pos - (c_pos % EBITMAP_SIZE);
e_iter->startbit = c_iter->startbit + if (emap_prev == NULL)
NETLBL_CATMAP_MAPSIZE * c_idx; ebmap->node = e_iter;
e_iter->map = c_iter->bitmap[c_idx]; 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_UNIT_SIZE;
}
} }
c_iter = c_iter->next; c_iter = c_iter->next;
} while (c_iter != NULL); } while (c_iter != NULL);
if (e_iter != NULL) if (e_iter != NULL)
ebmap->highbit = e_iter->startbit + MAPSIZE; ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
else else
ebitmap_destroy(ebmap); ebitmap_destroy(ebmap);
...@@ -186,6 +214,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap, ...@@ -186,6 +214,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
{ {
struct ebitmap_node *n1, *n2; struct ebitmap_node *n1, *n2;
int i;
if (e1->highbit < e2->highbit) if (e1->highbit < e2->highbit)
return 0; return 0;
...@@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) ...@@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
n1 = n1->next; n1 = n1->next;
continue; continue;
} }
if ((n1->map & n2->map) != n2->map) for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
return 0; if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
return 0;
}
n1 = n1->next; n1 = n1->next;
n2 = n2->next; n2 = n2->next;
...@@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit) ...@@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
n = e->node; n = e->node;
while (n && (n->startbit <= bit)) { while (n && (n->startbit <= bit)) {
if ((n->startbit + MAPSIZE) > bit) { if ((n->startbit + EBITMAP_SIZE) > bit)
if (n->map & (MAPBIT << (bit - n->startbit))) return ebitmap_node_get_bit(n, bit);
return 1;
else
return 0;
}
n = n->next; n = n->next;
} }
...@@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) ...@@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
prev = NULL; prev = NULL;
n = e->node; n = e->node;
while (n && n->startbit <= bit) { while (n && n->startbit <= bit) {
if ((n->startbit + MAPSIZE) > bit) { if ((n->startbit + EBITMAP_SIZE) > bit) {
if (value) { if (value) {
n->map |= (MAPBIT << (bit - n->startbit)); ebitmap_node_set_bit(n, bit);
} else { } else {
n->map &= ~(MAPBIT << (bit - n->startbit)); unsigned int s;
if (!n->map) {
/* drop this node from the bitmap */ ebitmap_node_clr_bit(n, bit);
if (!n->next) { s = find_first_bit(n->maps, EBITMAP_SIZE);
/* if (s < EBITMAP_SIZE)
* this was the highest map return 0;
* within the bitmap
*/ /* drop this node from the bitmap */
if (prev) if (!n->next) {
e->highbit = prev->startbit + MAPSIZE; /*
else * this was the highest map
e->highbit = 0; * within the bitmap
} */
if (prev) if (prev)
prev->next = n->next; e->highbit = prev->startbit
+ EBITMAP_SIZE;
else else
e->node = n->next; e->highbit = 0;
kfree(n);
} }
if (prev)
prev->next = n->next;
else
e->node = n->next;
kfree(n);
} }
return 0; return 0;
} }
...@@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) ...@@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
new->startbit = bit & ~(MAPSIZE - 1); new->startbit = bit - (bit % EBITMAP_SIZE);
new->map = (MAPBIT << (bit - new->startbit)); ebitmap_node_set_bit(new, bit);
if (!n) if (!n)
/* this node will be the highest map within the bitmap */ /* this node will be the highest map within the bitmap */
e->highbit = new->startbit + MAPSIZE; e->highbit = new->startbit + EBITMAP_SIZE;
if (prev) { if (prev) {
new->next = prev->next; new->next = prev->next;
...@@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e) ...@@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e)
int ebitmap_read(struct ebitmap *e, void *fp) int ebitmap_read(struct ebitmap *e, void *fp)
{ {
int rc; struct ebitmap_node *n = NULL;
struct ebitmap_node *n, *l; u32 mapunit, count, startbit, index;
u64 map;
__le32 buf[3]; __le32 buf[3];
u32 mapsize, count, i; int rc, i;
__le64 map;
ebitmap_init(e); ebitmap_init(e);
...@@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp) ...@@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (rc < 0) if (rc < 0)
goto out; goto out;
mapsize = le32_to_cpu(buf[0]); mapunit = le32_to_cpu(buf[0]);
e->highbit = le32_to_cpu(buf[1]); e->highbit = le32_to_cpu(buf[1]);
count = le32_to_cpu(buf[2]); count = le32_to_cpu(buf[2]);
if (mapsize != MAPSIZE) { if (mapunit != sizeof(u64) * 8) {
printk(KERN_ERR "security: ebitmap: map size %u does not " printk(KERN_ERR "security: ebitmap: map size %u does not "
"match my size %Zd (high bit was %d)\n", mapsize, "match my size %Zd (high bit was %d)\n",
MAPSIZE, e->highbit); mapunit, sizeof(u64) * 8, e->highbit);
goto bad; goto bad;
} }
/* round up e->highbit */
e->highbit += EBITMAP_SIZE - 1;
e->highbit -= (e->highbit % EBITMAP_SIZE);
if (!e->highbit) { if (!e->highbit) {
e->node = NULL; e->node = NULL;
goto ok; goto ok;
} }
if (e->highbit & (MAPSIZE - 1)) {
printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
"multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
goto bad;
}
l = NULL;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
rc = next_entry(buf, fp, sizeof(u32)); rc = next_entry(&startbit, fp, sizeof(u32));
if (rc < 0) { if (rc < 0) {
printk(KERN_ERR "security: ebitmap: truncated map\n"); printk(KERN_ERR "security: ebitmap: truncated map\n");
goto bad; goto bad;
} }
n = kzalloc(sizeof(*n), GFP_KERNEL); startbit = le32_to_cpu(startbit);
if (!n) {
printk(KERN_ERR "security: ebitmap: out of memory\n");
rc = -ENOMEM;
goto bad;
}
n->startbit = le32_to_cpu(buf[0]);
if (n->startbit & (MAPSIZE - 1)) { if (startbit & (mapunit - 1)) {
printk(KERN_ERR "security: ebitmap start bit (%d) is " printk(KERN_ERR "security: ebitmap start bit (%d) is "
"not a multiple of the map size (%Zd)\n", "not a multiple of the map unit size (%Zd)\n",
n->startbit, MAPSIZE); startbit, mapunit);
goto bad_free; goto bad;
} }
if (n->startbit > (e->highbit - MAPSIZE)) { if (startbit > e->highbit - mapunit) {
printk(KERN_ERR "security: ebitmap start bit (%d) is " printk(KERN_ERR "security: ebitmap start bit (%d) is "
"beyond the end of the bitmap (%Zd)\n", "beyond the end of the bitmap (%Zd)\n",
n->startbit, (e->highbit - MAPSIZE)); startbit, (e->highbit - mapunit));
goto bad_free; goto bad;
}
if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
struct ebitmap_node *tmp;
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp) {
printk(KERN_ERR
"security: ebitmap: out of memory\n");
rc = -ENOMEM;
goto bad;
}
/* round down */
tmp->startbit = startbit - (startbit % EBITMAP_SIZE);
if (n) {
n->next = tmp;
} else {
e->node = tmp;
}
n = tmp;
} else if (startbit <= n->startbit) {
printk(KERN_ERR "security: ebitmap: start bit %d"
" comes after start bit %d\n",
startbit, n->startbit);
goto bad;
} }
rc = next_entry(&map, fp, sizeof(u64)); rc = next_entry(&map, fp, sizeof(u64));
if (rc < 0) { if (rc < 0) {
printk(KERN_ERR "security: ebitmap: truncated map\n"); printk(KERN_ERR "security: ebitmap: truncated map\n");
goto bad_free; goto bad;
} }
n->map = le64_to_cpu(map); map = le64_to_cpu(map);
if (!n->map) { index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
printk(KERN_ERR "security: ebitmap: null map in " while (map) {
"ebitmap (startbit %d)\n", n->startbit); n->maps[index] = map & (-1UL);
goto bad_free; map = map >> EBITMAP_UNIT_SIZE;
index++;
} }
if (l) {
if (n->startbit <= l->startbit) {
printk(KERN_ERR "security: ebitmap: start "
"bit %d comes after start bit %d\n",
n->startbit, l->startbit);
goto bad_free;
}
l->next = n;
} else
e->node = n;
l = n;
} }
ok: ok:
rc = 0; rc = 0;
out: out:
return rc; return rc;
bad_free:
kfree(n);
bad: bad:
if (!rc) if (!rc)
rc = -EINVAL; rc = -EINVAL;
......
...@@ -16,14 +16,16 @@ ...@@ -16,14 +16,16 @@
#include <net/netlabel.h> #include <net/netlabel.h>
#define MAPTYPE u64 /* portion of bitmap in each node */ #define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \
#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */ / sizeof(unsigned long))
#define MAPBIT 1ULL /* a bit in the node bitmap */ #define EBITMAP_UNIT_SIZE BITS_PER_LONG
#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
#define EBITMAP_BIT 1ULL
struct ebitmap_node { struct ebitmap_node {
u32 startbit; /* starting position in the total bitmap */
MAPTYPE map; /* this node's portion of the bitmap */
struct ebitmap_node *next; struct ebitmap_node *next;
unsigned long maps[EBITMAP_UNIT_NUMS];
u32 startbit;
}; };
struct ebitmap { struct ebitmap {
...@@ -34,11 +36,17 @@ struct ebitmap { ...@@ -34,11 +36,17 @@ struct ebitmap {
#define ebitmap_length(e) ((e)->highbit) #define ebitmap_length(e) ((e)->highbit)
#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0) #define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
static inline unsigned int ebitmap_start(struct ebitmap *e, static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
struct ebitmap_node **n) struct ebitmap_node **n)
{ {
*n = e->node; unsigned int ofs;
return ebitmap_startbit(e);
for (*n = e->node; *n; *n = (*n)->next) {
ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
if (ofs < EBITMAP_SIZE)
return (*n)->startbit + ofs;
}
return ebitmap_length(e);
} }
static inline void ebitmap_init(struct ebitmap *e) static inline void ebitmap_init(struct ebitmap *e)
...@@ -46,28 +54,65 @@ static inline void ebitmap_init(struct ebitmap *e) ...@@ -46,28 +54,65 @@ static inline void ebitmap_init(struct ebitmap *e)
memset(e, 0, sizeof(*e)); memset(e, 0, sizeof(*e));
} }
static inline unsigned int ebitmap_next(struct ebitmap_node **n, static inline unsigned int ebitmap_next_positive(struct ebitmap *e,
unsigned int bit) struct ebitmap_node **n,
unsigned int bit)
{ {
if ((bit == ((*n)->startbit + MAPSIZE - 1)) && unsigned int ofs;
(*n)->next) {
*n = (*n)->next; ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
return (*n)->startbit; if (ofs < EBITMAP_SIZE)
} return ofs + (*n)->startbit;
return (bit+1); for (*n = (*n)->next; *n; *n = (*n)->next) {
ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
if (ofs < EBITMAP_SIZE)
return ofs + (*n)->startbit;
}
return ebitmap_length(e);
} }
static inline int ebitmap_node_get_bit(struct ebitmap_node * n, #define EBITMAP_NODE_INDEX(node, bit) \
(((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE)
#define EBITMAP_NODE_OFFSET(node, bit) \
(((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
static inline int ebitmap_node_get_bit(struct ebitmap_node *n,
unsigned int bit) unsigned int bit)
{ {
if (n->map & (MAPBIT << (bit - n->startbit))) unsigned int index = EBITMAP_NODE_INDEX(n, bit);
unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
BUG_ON(index >= EBITMAP_UNIT_NUMS);
if ((n->maps[index] & (EBITMAP_BIT << ofs)))
return 1; return 1;
return 0; return 0;
} }
#define ebitmap_for_each_bit(e, n, bit) \ static inline void ebitmap_node_set_bit(struct ebitmap_node *n,
for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \ unsigned int bit)
{
unsigned int index = EBITMAP_NODE_INDEX(n, bit);
unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
BUG_ON(index >= EBITMAP_UNIT_NUMS);
n->maps[index] |= (EBITMAP_BIT << ofs);
}
static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
unsigned int bit)
{
unsigned int index = EBITMAP_NODE_INDEX(n, bit);
unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
BUG_ON(index >= EBITMAP_UNIT_NUMS);
n->maps[index] &= ~(EBITMAP_BIT << ofs);
}
#define ebitmap_for_each_positive_bit(e, n, bit) \
for (bit = ebitmap_start_positive(e, &n); \
bit < ebitmap_length(e); \
bit = ebitmap_next_positive(e, &n, bit)) \
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
......
...@@ -34,7 +34,9 @@ ...@@ -34,7 +34,9 @@
*/ */
int mls_compute_context_len(struct context * context) int mls_compute_context_len(struct context * context)
{ {
int i, l, len, range; int i, l, len, head, prev;
char *nm;
struct ebitmap *e;
struct ebitmap_node *node; struct ebitmap_node *node;
if (!selinux_mls_enabled) if (!selinux_mls_enabled)
...@@ -42,31 +44,33 @@ int mls_compute_context_len(struct context * context) ...@@ -42,31 +44,33 @@ int mls_compute_context_len(struct context * context)
len = 1; /* for the beginning ":" */ len = 1; /* for the beginning ":" */
for (l = 0; l < 2; l++) { for (l = 0; l < 2; l++) {
range = 0; int index_sens = context->range.level[l].sens;
len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); len += strlen(policydb.p_sens_val_to_name[index_sens - 1]);
ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
if (ebitmap_node_get_bit(node, i)) {
if (range) {
range++;
continue;
}
len += strlen(policydb.p_cat_val_to_name[i]) + 1; /* categories */
range++; head = -2;
} else { prev = -2;
if (range > 1) e = &context->range.level[l].cat;
len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1; ebitmap_for_each_positive_bit(e, node, i) {
range = 0; if (i - prev > 1) {
/* one or more negative bits are skipped */
if (head != prev) {
nm = policydb.p_cat_val_to_name[prev];
len += strlen(nm) + 1;
}
nm = policydb.p_cat_val_to_name[i];
len += strlen(nm) + 1;
head = i;
} }
prev = i;
}
if (prev != head) {
nm = policydb.p_cat_val_to_name[prev];
len += strlen(nm) + 1;
} }
/* Handle case where last category is the end of range */
if (range > 1)
len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
if (l == 0) { if (l == 0) {
if (mls_level_eq(&context->range.level[0], if (mls_level_eq(&context->range.level[0],
&context->range.level[1])) &context->range.level[1]))
break; break;
else else
len++; len++;
...@@ -84,8 +88,9 @@ int mls_compute_context_len(struct context * context) ...@@ -84,8 +88,9 @@ int mls_compute_context_len(struct context * context)
void mls_sid_to_context(struct context *context, void mls_sid_to_context(struct context *context,
char **scontext) char **scontext)
{ {
char *scontextp; char *scontextp, *nm;
int i, l, range, wrote_sep; int i, l, head, prev;
struct ebitmap *e;
struct ebitmap_node *node; struct ebitmap_node *node;
if (!selinux_mls_enabled) if (!selinux_mls_enabled)
...@@ -97,61 +102,54 @@ void mls_sid_to_context(struct context *context, ...@@ -97,61 +102,54 @@ void mls_sid_to_context(struct context *context,
scontextp++; scontextp++;
for (l = 0; l < 2; l++) { for (l = 0; l < 2; l++) {
range = 0;
wrote_sep = 0;
strcpy(scontextp, strcpy(scontextp,
policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); scontextp += strlen(scontextp);
/* categories */ /* categories */
ebitmap_for_each_bit(&context->range.level[l].cat, node, i) { head = -2;
if (ebitmap_node_get_bit(node, i)) { prev = -2;
if (range) { e = &context->range.level[l].cat;
range++; ebitmap_for_each_positive_bit(e, node, i) {
continue; if (i - prev > 1) {
} /* one or more negative bits are skipped */
if (prev != head) {
if (!wrote_sep) { if (prev - head > 1)
*scontextp++ = ':';
wrote_sep = 1;
} else
*scontextp++ = ',';
strcpy(scontextp, policydb.p_cat_val_to_name[i]);
scontextp += strlen(policydb.p_cat_val_to_name[i]);
range++;
} else {
if (range > 1) {
if (range > 2)
*scontextp++ = '.'; *scontextp++ = '.';
else else
*scontextp++ = ','; *scontextp++ = ',';
nm = policydb.p_cat_val_to_name[prev];
strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]); strcpy(scontextp, nm);
scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); scontextp += strlen(nm);
} }
range = 0; if (prev < 0)
*scontextp++ = ':';
else
*scontextp++ = ',';
nm = policydb.p_cat_val_to_name[i];
strcpy(scontextp, nm);
scontextp += strlen(nm);
head = i;
} }
prev = i;
} }
/* Handle case where last category is the end of range */ if (prev != head) {
if (range > 1) { if (prev - head > 1)
if (range > 2)
*scontextp++ = '.'; *scontextp++ = '.';
else else
*scontextp++ = ','; *scontextp++ = ',';
nm = policydb.p_cat_val_to_name[prev];
strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]); strcpy(scontextp, nm);
scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); scontextp += strlen(nm);
} }
if (l == 0) { if (l == 0) {
if (mls_level_eq(&context->range.level[0], if (mls_level_eq(&context->range.level[0],
&context->range.level[1])) &context->range.level[1]))
break; break;
else { else
*scontextp = '-'; *scontextp++ = '-';
scontextp++;
}
} }
} }
...@@ -190,17 +188,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c) ...@@ -190,17 +188,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
if (!levdatum) if (!levdatum)
return 0; return 0;
ebitmap_for_each_bit(&c->range.level[l].cat, node, i) { ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
if (ebitmap_node_get_bit(node, i)) { if (i > p->p_cats.nprim)
if (i > p->p_cats.nprim) return 0;
return 0; if (!ebitmap_get_bit(&levdatum->level->cat, i))
if (!ebitmap_get_bit(&levdatum->level->cat, i)) /*
/* * Category may not be associated with
* Category may not be associated with * sensitivity in low level.
* sensitivity in low level. */
*/ return 0;
return 0;
}
} }
} }
...@@ -485,18 +481,16 @@ int mls_convert_context(struct policydb *oldp, ...@@ -485,18 +481,16 @@ int mls_convert_context(struct policydb *oldp,
c->range.level[l].sens = levdatum->level->sens; c->range.level[l].sens = levdatum->level->sens;
ebitmap_init(&bitmap); ebitmap_init(&bitmap);
ebitmap_for_each_bit(&c->range.level[l].cat, node, i) { ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
if (ebitmap_node_get_bit(node, i)) { int rc;
int rc;
catdatum = hashtab_search(newp->p_cats.table,
catdatum = hashtab_search(newp->p_cats.table, oldp->p_cat_val_to_name[i]);
oldp->p_cat_val_to_name[i]); if (!catdatum)
if (!catdatum) return -EINVAL;
return -EINVAL; rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); if (rc)
if (rc) return rc;
return rc;
}
} }
ebitmap_destroy(&c->range.level[l].cat); ebitmap_destroy(&c->range.level[l].cat);
c->range.level[l].cat = bitmap; c->range.level[l].cat = bitmap;
......
...@@ -353,12 +353,8 @@ static int context_struct_compute_av(struct context *scontext, ...@@ -353,12 +353,8 @@ static int context_struct_compute_av(struct context *scontext,
avkey.specified = AVTAB_AV; avkey.specified = AVTAB_AV;
sattr = &policydb.type_attr_map[scontext->type - 1]; sattr = &policydb.type_attr_map[scontext->type - 1];
tattr = &policydb.type_attr_map[tcontext->type - 1]; tattr = &policydb.type_attr_map[tcontext->type - 1];
ebitmap_for_each_bit(sattr, snode, i) { ebitmap_for_each_positive_bit(sattr, snode, i) {
if (!ebitmap_node_get_bit(snode, i)) ebitmap_for_each_positive_bit(tattr, tnode, j) {
continue;
ebitmap_for_each_bit(tattr, tnode, j) {
if (!ebitmap_node_get_bit(tnode, j))
continue;
avkey.source_type = i + 1; avkey.source_type = i + 1;
avkey.target_type = j + 1; avkey.target_type = j + 1;
for (node = avtab_search_node(&policydb.te_avtab, &avkey); for (node = avtab_search_node(&policydb.te_avtab, &avkey);
...@@ -1668,14 +1664,10 @@ int security_get_user_sids(u32 fromsid, ...@@ -1668,14 +1664,10 @@ int security_get_user_sids(u32 fromsid,
goto out_unlock; goto out_unlock;
} }
ebitmap_for_each_bit(&user->roles, rnode, i) { ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
if (!ebitmap_node_get_bit(rnode, i))
continue;
role = policydb.role_val_to_struct[i]; role = policydb.role_val_to_struct[i];
usercon.role = i+1; usercon.role = i+1;
ebitmap_for_each_bit(&role->types, tnode, j) { ebitmap_for_each_positive_bit(&role->types, tnode, j) {
if (!ebitmap_node_get_bit(tnode, j))
continue;
usercon.type = j+1; usercon.type = j+1;
if (mls_setup_user_range(fromcon, user, &usercon)) if (mls_setup_user_range(fromcon, user, &usercon))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment