aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/ss/mls.c
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/ss/mls.c
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/ss/mls.c')
-rw-r--r--security/selinux/ss/mls.c156
1 files changed, 75 insertions, 81 deletions
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 4a8bab2f3c71..9a11deaaa9e7 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;