aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux
diff options
context:
space:
mode:
authorKaiGai Kohei <kaigai@ak.jp.nec.com>2007-09-28 13:20:55 -0400
committerJames Morris <jmorris@namei.org>2007-10-16 18:59:34 -0400
commit9fe79ad1e43d236bbbb8edb3cf634356de714c79 (patch)
tree91149cefa28baf692eb55f88f8c544a33e9126df /security/selinux
parent3f12070e27b4a213d62607d2bff139793089a77d (diff)
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: KaiGai Kohei <kaigai@ak.jp.nec.com> Acked-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/ss/ebitmap.c281
-rw-r--r--security/selinux/ss/ebitmap.h87
-rw-r--r--security/selinux/ss/mls.c156
-rw-r--r--security/selinux/ss/services.c16
4 files changed, 303 insertions, 237 deletions
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index ce492a6b38e..ae44c0c9401 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -10,6 +10,10 @@
10 * 10 *
11 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 11 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
12 */ 12 */
13/*
14 * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
15 * Applied standard bit operations to improve bitmap scanning.
16 */
13 17
14#include <linux/kernel.h> 18#include <linux/kernel.h>
15#include <linux/slab.h> 19#include <linux/slab.h>
@@ -29,7 +33,7 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
29 n2 = e2->node; 33 n2 = e2->node;
30 while (n1 && n2 && 34 while (n1 && n2 &&
31 (n1->startbit == n2->startbit) && 35 (n1->startbit == n2->startbit) &&
32 (n1->map == n2->map)) { 36 !memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) {
33 n1 = n1->next; 37 n1 = n1->next;
34 n2 = n2->next; 38 n2 = n2->next;
35 } 39 }
@@ -54,7 +58,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
54 return -ENOMEM; 58 return -ENOMEM;
55 } 59 }
56 new->startbit = n->startbit; 60 new->startbit = n->startbit;
57 new->map = n->map; 61 memcpy(new->maps, n->maps, EBITMAP_SIZE / 8);
58 new->next = NULL; 62 new->next = NULL;
59 if (prev) 63 if (prev)
60 prev->next = new; 64 prev->next = new;
@@ -84,13 +88,15 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
84{ 88{
85 struct ebitmap_node *e_iter = ebmap->node; 89 struct ebitmap_node *e_iter = ebmap->node;
86 struct netlbl_lsm_secattr_catmap *c_iter; 90 struct netlbl_lsm_secattr_catmap *c_iter;
87 u32 cmap_idx; 91 u32 cmap_idx, cmap_sft;
92 int i;
88 93
89 /* This function is a much simpler because SELinux's MAPTYPE happens 94 /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
90 * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is 95 * however, it is not always compatible with an array of unsigned long
91 * changed from a u64 this function will most likely need to be changed 96 * in ebitmap_node.
92 * as well. It's not ideal but I think the tradeoff in terms of 97 * In addition, you should pay attention the following implementation
93 * neatness and speed is worth it. */ 98 * assumes unsigned long has a width equal with or less than 64-bit.
99 */
94 100
95 if (e_iter == NULL) { 101 if (e_iter == NULL) {
96 *catmap = NULL; 102 *catmap = NULL;
@@ -104,19 +110,27 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
104 c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1); 110 c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1);
105 111
106 while (e_iter != NULL) { 112 while (e_iter != NULL) {
107 if (e_iter->startbit >= 113 for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
108 (c_iter->startbit + NETLBL_CATMAP_SIZE)) { 114 unsigned int delta, e_startbit, c_endbit;
109 c_iter->next = netlbl_secattr_catmap_alloc(GFP_ATOMIC); 115
110 if (c_iter->next == NULL) 116 e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE;
111 goto netlbl_export_failure; 117 c_endbit = c_iter->startbit + NETLBL_CATMAP_SIZE;
112 c_iter = c_iter->next; 118 if (e_startbit >= c_endbit) {
113 c_iter->startbit = e_iter->startbit & 119 c_iter->next
114 ~(NETLBL_CATMAP_SIZE - 1); 120 = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
121 if (c_iter->next == NULL)
122 goto netlbl_export_failure;
123 c_iter = c_iter->next;
124 c_iter->startbit
125 = e_startbit & ~(NETLBL_CATMAP_SIZE - 1);
126 }
127 delta = e_startbit - c_iter->startbit;
128 cmap_idx = delta / NETLBL_CATMAP_MAPSIZE;
129 cmap_sft = delta % NETLBL_CATMAP_MAPSIZE;
130 c_iter->bitmap[cmap_idx]
131 |= e_iter->maps[cmap_idx] << cmap_sft;
132 e_iter = e_iter->next;
115 } 133 }
116 cmap_idx = (e_iter->startbit - c_iter->startbit) /
117 NETLBL_CATMAP_MAPSIZE;
118 c_iter->bitmap[cmap_idx] = e_iter->map;
119 e_iter = e_iter->next;
120 } 134 }
121 135
122 return 0; 136 return 0;
@@ -128,7 +142,7 @@ netlbl_export_failure:
128 142
129/** 143/**
130 * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap 144 * ebitmap_netlbl_import - Import a NetLabel category bitmap into an ebitmap
131 * @ebmap: the ebitmap to export 145 * @ebmap: the ebitmap to import
132 * @catmap: the NetLabel category bitmap 146 * @catmap: the NetLabel category bitmap
133 * 147 *
134 * Description: 148 * Description:
@@ -142,36 +156,50 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
142 struct ebitmap_node *e_iter = NULL; 156 struct ebitmap_node *e_iter = NULL;
143 struct ebitmap_node *emap_prev = NULL; 157 struct ebitmap_node *emap_prev = NULL;
144 struct netlbl_lsm_secattr_catmap *c_iter = catmap; 158 struct netlbl_lsm_secattr_catmap *c_iter = catmap;
145 u32 c_idx; 159 u32 c_idx, c_pos, e_idx, e_sft;
146 160
147 /* This function is a much simpler because SELinux's MAPTYPE happens 161 /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64,
148 * to be the same as NetLabel's NETLBL_CATMAP_MAPTYPE, if MAPTYPE is 162 * however, it is not always compatible with an array of unsigned long
149 * changed from a u64 this function will most likely need to be changed 163 * in ebitmap_node.
150 * as well. It's not ideal but I think the tradeoff in terms of 164 * In addition, you should pay attention the following implementation
151 * neatness and speed is worth it. */ 165 * assumes unsigned long has a width equal with or less than 64-bit.
166 */
152 167
153 do { 168 do {
154 for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) { 169 for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) {
155 if (c_iter->bitmap[c_idx] == 0) 170 unsigned int delta;
171 u64 map = c_iter->bitmap[c_idx];
172
173 if (!map)
156 continue; 174 continue;
157 175
158 e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); 176 c_pos = c_iter->startbit
159 if (e_iter == NULL) 177 + c_idx * NETLBL_CATMAP_MAPSIZE;
160 goto netlbl_import_failure; 178 if (!e_iter
161 if (emap_prev == NULL) 179 || c_pos >= e_iter->startbit + EBITMAP_SIZE) {
162 ebmap->node = e_iter; 180 e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
163 else 181 if (!e_iter)
164 emap_prev->next = e_iter; 182 goto netlbl_import_failure;
165 emap_prev = e_iter; 183 e_iter->startbit
166 184 = c_pos - (c_pos % EBITMAP_SIZE);
167 e_iter->startbit = c_iter->startbit + 185 if (emap_prev == NULL)
168 NETLBL_CATMAP_MAPSIZE * c_idx; 186 ebmap->node = e_iter;
169 e_iter->map = c_iter->bitmap[c_idx]; 187 else
188 emap_prev->next = e_iter;
189 emap_prev = e_iter;
190 }
191 delta = c_pos - e_iter->startbit;
192 e_idx = delta / EBITMAP_UNIT_SIZE;
193 e_sft = delta % EBITMAP_UNIT_SIZE;
194 while (map) {
195 e_iter->maps[e_idx++] |= map & (-1UL);
196 map >>= EBITMAP_UNIT_SIZE;
197 }
170 } 198 }
171 c_iter = c_iter->next; 199 c_iter = c_iter->next;
172 } while (c_iter != NULL); 200 } while (c_iter != NULL);
173 if (e_iter != NULL) 201 if (e_iter != NULL)
174 ebmap->highbit = e_iter->startbit + MAPSIZE; 202 ebmap->highbit = e_iter->startbit + EBITMAP_SIZE;
175 else 203 else
176 ebitmap_destroy(ebmap); 204 ebitmap_destroy(ebmap);
177 205
@@ -186,6 +214,7 @@ netlbl_import_failure:
186int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) 214int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
187{ 215{
188 struct ebitmap_node *n1, *n2; 216 struct ebitmap_node *n1, *n2;
217 int i;
189 218
190 if (e1->highbit < e2->highbit) 219 if (e1->highbit < e2->highbit)
191 return 0; 220 return 0;
@@ -197,8 +226,10 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
197 n1 = n1->next; 226 n1 = n1->next;
198 continue; 227 continue;
199 } 228 }
200 if ((n1->map & n2->map) != n2->map) 229 for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
201 return 0; 230 if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
231 return 0;
232 }
202 233
203 n1 = n1->next; 234 n1 = n1->next;
204 n2 = n2->next; 235 n2 = n2->next;
@@ -219,12 +250,8 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
219 250
220 n = e->node; 251 n = e->node;
221 while (n && (n->startbit <= bit)) { 252 while (n && (n->startbit <= bit)) {
222 if ((n->startbit + MAPSIZE) > bit) { 253 if ((n->startbit + EBITMAP_SIZE) > bit)
223 if (n->map & (MAPBIT << (bit - n->startbit))) 254 return ebitmap_node_get_bit(n, bit);
224 return 1;
225 else
226 return 0;
227 }
228 n = n->next; 255 n = n->next;
229 } 256 }
230 257
@@ -238,31 +265,35 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
238 prev = NULL; 265 prev = NULL;
239 n = e->node; 266 n = e->node;
240 while (n && n->startbit <= bit) { 267 while (n && n->startbit <= bit) {
241 if ((n->startbit + MAPSIZE) > bit) { 268 if ((n->startbit + EBITMAP_SIZE) > bit) {
242 if (value) { 269 if (value) {
243 n->map |= (MAPBIT << (bit - n->startbit)); 270 ebitmap_node_set_bit(n, bit);
244 } else { 271 } else {
245 n->map &= ~(MAPBIT << (bit - n->startbit)); 272 unsigned int s;
246 if (!n->map) { 273
247 /* drop this node from the bitmap */ 274 ebitmap_node_clr_bit(n, bit);
248 275
249 if (!n->next) { 276 s = find_first_bit(n->maps, EBITMAP_SIZE);
250 /* 277 if (s < EBITMAP_SIZE)
251 * this was the highest map 278 return 0;
252 * within the bitmap 279
253 */ 280 /* drop this node from the bitmap */
254 if (prev) 281 if (!n->next) {
255 e->highbit = prev->startbit + MAPSIZE; 282 /*
256 else 283 * this was the highest map
257 e->highbit = 0; 284 * within the bitmap
258 } 285 */
259 if (prev) 286 if (prev)
260 prev->next = n->next; 287 e->highbit = prev->startbit
288 + EBITMAP_SIZE;
261 else 289 else
262 e->node = n->next; 290 e->highbit = 0;
263
264 kfree(n);
265 } 291 }
292 if (prev)
293 prev->next = n->next;
294 else
295 e->node = n->next;
296 kfree(n);
266 } 297 }
267 return 0; 298 return 0;
268 } 299 }
@@ -277,12 +308,12 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
277 if (!new) 308 if (!new)
278 return -ENOMEM; 309 return -ENOMEM;
279 310
280 new->startbit = bit & ~(MAPSIZE - 1); 311 new->startbit = bit - (bit % EBITMAP_SIZE);
281 new->map = (MAPBIT << (bit - new->startbit)); 312 ebitmap_node_set_bit(new, bit);
282 313
283 if (!n) 314 if (!n)
284 /* this node will be the highest map within the bitmap */ 315 /* this node will be the highest map within the bitmap */
285 e->highbit = new->startbit + MAPSIZE; 316 e->highbit = new->startbit + EBITMAP_SIZE;
286 317
287 if (prev) { 318 if (prev) {
288 new->next = prev->next; 319 new->next = prev->next;
@@ -316,11 +347,11 @@ void ebitmap_destroy(struct ebitmap *e)
316 347
317int ebitmap_read(struct ebitmap *e, void *fp) 348int ebitmap_read(struct ebitmap *e, void *fp)
318{ 349{
319 int rc; 350 struct ebitmap_node *n = NULL;
320 struct ebitmap_node *n, *l; 351 u32 mapunit, count, startbit, index;
352 u64 map;
321 __le32 buf[3]; 353 __le32 buf[3];
322 u32 mapsize, count, i; 354 int rc, i;
323 __le64 map;
324 355
325 ebitmap_init(e); 356 ebitmap_init(e);
326 357
@@ -328,85 +359,89 @@ int ebitmap_read(struct ebitmap *e, void *fp)
328 if (rc < 0) 359 if (rc < 0)
329 goto out; 360 goto out;
330 361
331 mapsize = le32_to_cpu(buf[0]); 362 mapunit = le32_to_cpu(buf[0]);
332 e->highbit = le32_to_cpu(buf[1]); 363 e->highbit = le32_to_cpu(buf[1]);
333 count = le32_to_cpu(buf[2]); 364 count = le32_to_cpu(buf[2]);
334 365
335 if (mapsize != MAPSIZE) { 366 if (mapunit != sizeof(u64) * 8) {
336 printk(KERN_ERR "security: ebitmap: map size %u does not " 367 printk(KERN_ERR "security: ebitmap: map size %u does not "
337 "match my size %Zd (high bit was %d)\n", mapsize, 368 "match my size %Zd (high bit was %d)\n",
338 MAPSIZE, e->highbit); 369 mapunit, sizeof(u64) * 8, e->highbit);
339 goto bad; 370 goto bad;
340 } 371 }
372
373 /* round up e->highbit */
374 e->highbit += EBITMAP_SIZE - 1;
375 e->highbit -= (e->highbit % EBITMAP_SIZE);
376
341 if (!e->highbit) { 377 if (!e->highbit) {
342 e->node = NULL; 378 e->node = NULL;
343 goto ok; 379 goto ok;
344 } 380 }
345 if (e->highbit & (MAPSIZE - 1)) { 381
346 printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
347 "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
348 goto bad;
349 }
350 l = NULL;
351 for (i = 0; i < count; i++) { 382 for (i = 0; i < count; i++) {
352 rc = next_entry(buf, fp, sizeof(u32)); 383 rc = next_entry(&startbit, fp, sizeof(u32));
353 if (rc < 0) { 384 if (rc < 0) {
354 printk(KERN_ERR "security: ebitmap: truncated map\n"); 385 printk(KERN_ERR "security: ebitmap: truncated map\n");
355 goto bad; 386 goto bad;
356 } 387 }
357 n = kzalloc(sizeof(*n), GFP_KERNEL); 388 startbit = le32_to_cpu(startbit);
358 if (!n) {
359 printk(KERN_ERR "security: ebitmap: out of memory\n");
360 rc = -ENOMEM;
361 goto bad;
362 }
363
364 n->startbit = le32_to_cpu(buf[0]);
365 389
366 if (n->startbit & (MAPSIZE - 1)) { 390 if (startbit & (mapunit - 1)) {
367 printk(KERN_ERR "security: ebitmap start bit (%d) is " 391 printk(KERN_ERR "security: ebitmap start bit (%d) is "
368 "not a multiple of the map size (%Zd)\n", 392 "not a multiple of the map unit size (%Zd)\n",
369 n->startbit, MAPSIZE); 393 startbit, mapunit);
370 goto bad_free; 394 goto bad;
371 } 395 }
372 if (n->startbit > (e->highbit - MAPSIZE)) { 396 if (startbit > e->highbit - mapunit) {
373 printk(KERN_ERR "security: ebitmap start bit (%d) is " 397 printk(KERN_ERR "security: ebitmap start bit (%d) is "
374 "beyond the end of the bitmap (%Zd)\n", 398 "beyond the end of the bitmap (%Zd)\n",
375 n->startbit, (e->highbit - MAPSIZE)); 399 startbit, (e->highbit - mapunit));
376 goto bad_free; 400 goto bad;
401 }
402
403 if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
404 struct ebitmap_node *tmp;
405 tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
406 if (!tmp) {
407 printk(KERN_ERR
408 "security: ebitmap: out of memory\n");
409 rc = -ENOMEM;
410 goto bad;
411 }
412 /* round down */
413 tmp->startbit = startbit - (startbit % EBITMAP_SIZE);
414 if (n) {
415 n->next = tmp;
416 } else {
417 e->node = tmp;
418 }
419 n = tmp;
420 } else if (startbit <= n->startbit) {
421 printk(KERN_ERR "security: ebitmap: start bit %d"
422 " comes after start bit %d\n",
423 startbit, n->startbit);
424 goto bad;
377 } 425 }
426
378 rc = next_entry(&map, fp, sizeof(u64)); 427 rc = next_entry(&map, fp, sizeof(u64));
379 if (rc < 0) { 428 if (rc < 0) {
380 printk(KERN_ERR "security: ebitmap: truncated map\n"); 429 printk(KERN_ERR "security: ebitmap: truncated map\n");
381 goto bad_free; 430 goto bad;
382 } 431 }
383 n->map = le64_to_cpu(map); 432 map = le64_to_cpu(map);
384 433
385 if (!n->map) { 434 index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
386 printk(KERN_ERR "security: ebitmap: null map in " 435 while (map) {
387 "ebitmap (startbit %d)\n", n->startbit); 436 n->maps[index] = map & (-1UL);
388 goto bad_free; 437 map = map >> EBITMAP_UNIT_SIZE;
438 index++;
389 } 439 }
390 if (l) {
391 if (n->startbit <= l->startbit) {
392 printk(KERN_ERR "security: ebitmap: start "
393 "bit %d comes after start bit %d\n",
394 n->startbit, l->startbit);
395 goto bad_free;
396 }
397 l->next = n;
398 } else
399 e->node = n;
400
401 l = n;
402 } 440 }
403
404ok: 441ok:
405 rc = 0; 442 rc = 0;
406out: 443out:
407 return rc; 444 return rc;
408bad_free:
409 kfree(n);
410bad: 445bad:
411 if (!rc) 446 if (!rc)
412 rc = -EINVAL; 447 rc = -EINVAL;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 1270e34b61c..e38a327dd70 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -16,14 +16,16 @@
16 16
17#include <net/netlabel.h> 17#include <net/netlabel.h>
18 18
19#define MAPTYPE u64 /* portion of bitmap in each node */ 19#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \
20#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */ 20 / sizeof(unsigned long))
21#define MAPBIT 1ULL /* a bit in the node bitmap */ 21#define EBITMAP_UNIT_SIZE BITS_PER_LONG
22#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
23#define EBITMAP_BIT 1ULL
22 24
23struct ebitmap_node { 25struct ebitmap_node {
24 u32 startbit; /* starting position in the total bitmap */
25 MAPTYPE map; /* this node's portion of the bitmap */
26 struct ebitmap_node *next; 26 struct ebitmap_node *next;
27 unsigned long maps[EBITMAP_UNIT_NUMS];
28 u32 startbit;
27}; 29};
28 30
29struct ebitmap { 31struct ebitmap {
@@ -34,11 +36,17 @@ struct ebitmap {
34#define ebitmap_length(e) ((e)->highbit) 36#define ebitmap_length(e) ((e)->highbit)
35#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0) 37#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
36 38
37static inline unsigned int ebitmap_start(struct ebitmap *e, 39static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
38 struct ebitmap_node **n) 40 struct ebitmap_node **n)
39{ 41{
40 *n = e->node; 42 unsigned int ofs;
41 return ebitmap_startbit(e); 43
44 for (*n = e->node; *n; *n = (*n)->next) {
45 ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
46 if (ofs < EBITMAP_SIZE)
47 return (*n)->startbit + ofs;
48 }
49 return ebitmap_length(e);
42} 50}
43 51
44static inline void ebitmap_init(struct ebitmap *e) 52static inline void ebitmap_init(struct ebitmap *e)
@@ -46,28 +54,65 @@ static inline void ebitmap_init(struct ebitmap *e)
46 memset(e, 0, sizeof(*e)); 54 memset(e, 0, sizeof(*e));
47} 55}
48 56
49static inline unsigned int ebitmap_next(struct ebitmap_node **n, 57static inline unsigned int ebitmap_next_positive(struct ebitmap *e,
50 unsigned int bit) 58 struct ebitmap_node **n,
59 unsigned int bit)
51{ 60{
52 if ((bit == ((*n)->startbit + MAPSIZE - 1)) && 61 unsigned int ofs;
53 (*n)->next) { 62
54 *n = (*n)->next; 63 ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
55 return (*n)->startbit; 64 if (ofs < EBITMAP_SIZE)
56 } 65 return ofs + (*n)->startbit;
57 66
58 return (bit+1); 67 for (*n = (*n)->next; *n; *n = (*n)->next) {
68 ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
69 if (ofs < EBITMAP_SIZE)
70 return ofs + (*n)->startbit;
71 }
72 return ebitmap_length(e);
59} 73}
60 74
61static inline int ebitmap_node_get_bit(struct ebitmap_node * n, 75#define EBITMAP_NODE_INDEX(node, bit) \
76 (((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE)
77#define EBITMAP_NODE_OFFSET(node, bit) \
78 (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
79
80static inline int ebitmap_node_get_bit(struct ebitmap_node *n,
62 unsigned int bit) 81 unsigned int bit)
63{ 82{
64 if (n->map & (MAPBIT << (bit - n->startbit))) 83 unsigned int index = EBITMAP_NODE_INDEX(n, bit);
84 unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
85
86 BUG_ON(index >= EBITMAP_UNIT_NUMS);
87 if ((n->maps[index] & (EBITMAP_BIT << ofs)))
65 return 1; 88 return 1;
66 return 0; 89 return 0;
67} 90}
68 91
69#define ebitmap_for_each_bit(e, n, bit) \ 92static inline void ebitmap_node_set_bit(struct ebitmap_node *n,
70 for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \ 93 unsigned int bit)
94{
95 unsigned int index = EBITMAP_NODE_INDEX(n, bit);
96 unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
97
98 BUG_ON(index >= EBITMAP_UNIT_NUMS);
99 n->maps[index] |= (EBITMAP_BIT << ofs);
100}
101
102static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
103 unsigned int bit)
104{
105 unsigned int index = EBITMAP_NODE_INDEX(n, bit);
106 unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
107
108 BUG_ON(index >= EBITMAP_UNIT_NUMS);
109 n->maps[index] &= ~(EBITMAP_BIT << ofs);
110}
111
112#define ebitmap_for_each_positive_bit(e, n, bit) \
113 for (bit = ebitmap_start_positive(e, &n); \
114 bit < ebitmap_length(e); \
115 bit = ebitmap_next_positive(e, &n, bit)) \
71 116
72int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); 117int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
73int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); 118int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 4a8bab2f3c7..9a11deaaa9e 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -34,7 +34,9 @@
34 */ 34 */
35int mls_compute_context_len(struct context * context) 35int mls_compute_context_len(struct context * context)
36{ 36{
37 int i, l, len, range; 37 int i, l, len, head, prev;
38 char *nm;
39 struct ebitmap *e;
38 struct ebitmap_node *node; 40 struct ebitmap_node *node;
39 41
40 if (!selinux_mls_enabled) 42 if (!selinux_mls_enabled)
@@ -42,31 +44,33 @@ int mls_compute_context_len(struct context * context)
42 44
43 len = 1; /* for the beginning ":" */ 45 len = 1; /* for the beginning ":" */
44 for (l = 0; l < 2; l++) { 46 for (l = 0; l < 2; l++) {
45 range = 0; 47 int index_sens = context->range.level[l].sens;
46 len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); 48 len += strlen(policydb.p_sens_val_to_name[index_sens - 1]);
47
48 ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
49 if (ebitmap_node_get_bit(node, i)) {
50 if (range) {
51 range++;
52 continue;
53 }
54 49
55 len += strlen(policydb.p_cat_val_to_name[i]) + 1; 50 /* categories */
56 range++; 51 head = -2;
57 } else { 52 prev = -2;
58 if (range > 1) 53 e = &context->range.level[l].cat;
59 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1; 54 ebitmap_for_each_positive_bit(e, node, i) {
60 range = 0; 55 if (i - prev > 1) {
56 /* one or more negative bits are skipped */
57 if (head != prev) {
58 nm = policydb.p_cat_val_to_name[prev];
59 len += strlen(nm) + 1;
60 }
61 nm = policydb.p_cat_val_to_name[i];
62 len += strlen(nm) + 1;
63 head = i;
61 } 64 }
65 prev = i;
66 }
67 if (prev != head) {
68 nm = policydb.p_cat_val_to_name[prev];
69 len += strlen(nm) + 1;
62 } 70 }
63 /* Handle case where last category is the end of range */
64 if (range > 1)
65 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
66
67 if (l == 0) { 71 if (l == 0) {
68 if (mls_level_eq(&context->range.level[0], 72 if (mls_level_eq(&context->range.level[0],
69 &context->range.level[1])) 73 &context->range.level[1]))
70 break; 74 break;
71 else 75 else
72 len++; 76 len++;
@@ -84,8 +88,9 @@ int mls_compute_context_len(struct context * context)
84void mls_sid_to_context(struct context *context, 88void mls_sid_to_context(struct context *context,
85 char **scontext) 89 char **scontext)
86{ 90{
87 char *scontextp; 91 char *scontextp, *nm;
88 int i, l, range, wrote_sep; 92 int i, l, head, prev;
93 struct ebitmap *e;
89 struct ebitmap_node *node; 94 struct ebitmap_node *node;
90 95
91 if (!selinux_mls_enabled) 96 if (!selinux_mls_enabled)
@@ -97,61 +102,54 @@ void mls_sid_to_context(struct context *context,
97 scontextp++; 102 scontextp++;
98 103
99 for (l = 0; l < 2; l++) { 104 for (l = 0; l < 2; l++) {
100 range = 0;
101 wrote_sep = 0;
102 strcpy(scontextp, 105 strcpy(scontextp,
103 policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); 106 policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
104 scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); 107 scontextp += strlen(scontextp);
105 108
106 /* categories */ 109 /* categories */
107 ebitmap_for_each_bit(&context->range.level[l].cat, node, i) { 110 head = -2;
108 if (ebitmap_node_get_bit(node, i)) { 111 prev = -2;
109 if (range) { 112 e = &context->range.level[l].cat;
110 range++; 113 ebitmap_for_each_positive_bit(e, node, i) {
111 continue; 114 if (i - prev > 1) {
112 } 115 /* one or more negative bits are skipped */
113 116 if (prev != head) {
114 if (!wrote_sep) { 117 if (prev - head > 1)
115 *scontextp++ = ':';
116 wrote_sep = 1;
117 } else
118 *scontextp++ = ',';
119 strcpy(scontextp, policydb.p_cat_val_to_name[i]);
120 scontextp += strlen(policydb.p_cat_val_to_name[i]);
121 range++;
122 } else {
123 if (range > 1) {
124 if (range > 2)
125 *scontextp++ = '.'; 118 *scontextp++ = '.';
126 else 119 else
127 *scontextp++ = ','; 120 *scontextp++ = ',';
128 121 nm = policydb.p_cat_val_to_name[prev];
129 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]); 122 strcpy(scontextp, nm);
130 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); 123 scontextp += strlen(nm);
131 } 124 }
132 range = 0; 125 if (prev < 0)
126 *scontextp++ = ':';
127 else
128 *scontextp++ = ',';
129 nm = policydb.p_cat_val_to_name[i];
130 strcpy(scontextp, nm);
131 scontextp += strlen(nm);
132 head = i;
133 } 133 }
134 prev = i;
134 } 135 }
135 136
136 /* Handle case where last category is the end of range */ 137 if (prev != head) {
137 if (range > 1) { 138 if (prev - head > 1)
138 if (range > 2)
139 *scontextp++ = '.'; 139 *scontextp++ = '.';
140 else 140 else
141 *scontextp++ = ','; 141 *scontextp++ = ',';
142 142 nm = policydb.p_cat_val_to_name[prev];
143 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]); 143 strcpy(scontextp, nm);
144 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); 144 scontextp += strlen(nm);
145 } 145 }
146 146
147 if (l == 0) { 147 if (l == 0) {
148 if (mls_level_eq(&context->range.level[0], 148 if (mls_level_eq(&context->range.level[0],
149 &context->range.level[1])) 149 &context->range.level[1]))
150 break; 150 break;
151 else { 151 else
152 *scontextp = '-'; 152 *scontextp++ = '-';
153 scontextp++;
154 }
155 } 153 }
156 } 154 }
157 155
@@ -190,17 +188,15 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
190 if (!levdatum) 188 if (!levdatum)
191 return 0; 189 return 0;
192 190
193 ebitmap_for_each_bit(&c->range.level[l].cat, node, i) { 191 ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
194 if (ebitmap_node_get_bit(node, i)) { 192 if (i > p->p_cats.nprim)
195 if (i > p->p_cats.nprim) 193 return 0;
196 return 0; 194 if (!ebitmap_get_bit(&levdatum->level->cat, i))
197 if (!ebitmap_get_bit(&levdatum->level->cat, i)) 195 /*
198 /* 196 * Category may not be associated with
199 * Category may not be associated with 197 * sensitivity in low level.
200 * sensitivity in low level. 198 */
201 */ 199 return 0;
202 return 0;
203 }
204 } 200 }
205 } 201 }
206 202
@@ -485,18 +481,16 @@ int mls_convert_context(struct policydb *oldp,
485 c->range.level[l].sens = levdatum->level->sens; 481 c->range.level[l].sens = levdatum->level->sens;
486 482
487 ebitmap_init(&bitmap); 483 ebitmap_init(&bitmap);
488 ebitmap_for_each_bit(&c->range.level[l].cat, node, i) { 484 ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
489 if (ebitmap_node_get_bit(node, i)) { 485 int rc;
490 int rc; 486
491 487 catdatum = hashtab_search(newp->p_cats.table,
492 catdatum = hashtab_search(newp->p_cats.table, 488 oldp->p_cat_val_to_name[i]);
493 oldp->p_cat_val_to_name[i]); 489 if (!catdatum)
494 if (!catdatum) 490 return -EINVAL;
495 return -EINVAL; 491 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
496 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); 492 if (rc)
497 if (rc) 493 return rc;
498 return rc;
499 }
500 } 494 }
501 ebitmap_destroy(&c->range.level[l].cat); 495 ebitmap_destroy(&c->range.level[l].cat);
502 c->range.level[l].cat = bitmap; 496 c->range.level[l].cat = bitmap;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 03140edf97a..d572dc908f3 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -353,12 +353,8 @@ static int context_struct_compute_av(struct context *scontext,
353 avkey.specified = AVTAB_AV; 353 avkey.specified = AVTAB_AV;
354 sattr = &policydb.type_attr_map[scontext->type - 1]; 354 sattr = &policydb.type_attr_map[scontext->type - 1];
355 tattr = &policydb.type_attr_map[tcontext->type - 1]; 355 tattr = &policydb.type_attr_map[tcontext->type - 1];
356 ebitmap_for_each_bit(sattr, snode, i) { 356 ebitmap_for_each_positive_bit(sattr, snode, i) {
357 if (!ebitmap_node_get_bit(snode, i)) 357 ebitmap_for_each_positive_bit(tattr, tnode, j) {
358 continue;
359 ebitmap_for_each_bit(tattr, tnode, j) {
360 if (!ebitmap_node_get_bit(tnode, j))
361 continue;
362 avkey.source_type = i + 1; 358 avkey.source_type = i + 1;
363 avkey.target_type = j + 1; 359 avkey.target_type = j + 1;
364 for (node = avtab_search_node(&policydb.te_avtab, &avkey); 360 for (node = avtab_search_node(&policydb.te_avtab, &avkey);
@@ -1668,14 +1664,10 @@ int security_get_user_sids(u32 fromsid,
1668 goto out_unlock; 1664 goto out_unlock;
1669 } 1665 }
1670 1666
1671 ebitmap_for_each_bit(&user->roles, rnode, i) { 1667 ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
1672 if (!ebitmap_node_get_bit(rnode, i))
1673 continue;
1674 role = policydb.role_val_to_struct[i]; 1668 role = policydb.role_val_to_struct[i];
1675 usercon.role = i+1; 1669 usercon.role = i+1;
1676 ebitmap_for_each_bit(&role->types, tnode, j) { 1670 ebitmap_for_each_positive_bit(&role->types, tnode, j) {
1677 if (!ebitmap_node_get_bit(tnode, j))
1678 continue;
1679 usercon.type = j+1; 1671 usercon.type = j+1;
1680 1672
1681 if (mls_setup_user_range(fromcon, user, &usercon)) 1673 if (mls_setup_user_range(fromcon, user, &usercon))