diff options
author | KaiGai Kohei <kaigai@ak.jp.nec.com> | 2007-09-28 13:20:55 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2007-10-16 18:59:34 -0400 |
commit | 9fe79ad1e43d236bbbb8edb3cf634356de714c79 (patch) | |
tree | 91149cefa28baf692eb55f88f8c544a33e9126df /security/selinux/ss/mls.c | |
parent | 3f12070e27b4a213d62607d2bff139793089a77d (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.c | 156 |
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 | */ |
35 | int mls_compute_context_len(struct context * context) | 35 | int 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) | |||
84 | void mls_sid_to_context(struct context *context, | 88 | void 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; |