diff options
author | Stephen Smalley <sds@tycho.nsa.gov> | 2005-09-03 18:55:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@evo.osdl.org> | 2005-09-05 03:05:50 -0400 |
commit | 782ebb992ec20b5afdd5786ee8c2f1b58b631f24 (patch) | |
tree | adf0af44fa591d803ec6b9ab7541ff3e5745dd93 /security/selinux/ss/avtab.c | |
parent | 720d6c29e146e96cca858057469951e91e0e6850 (diff) |
[PATCH] selinux: Reduce memory use by avtab
This patch improves memory use by SELinux by both reducing the avtab node
size and reducing the number of avtab nodes. The memory savings are
substantial, e.g. on a 64-bit system after boot, James Morris reported the
following data for the targeted and strict policies:
#objs objsize kernmem
Targeted:
Before: 237888 40 9.1MB
After: 19968 24 468KB
Strict:
Before: 571680 40 21.81MB
After: 221052 24 5.06MB
The improvement in memory use comes at a cost in the speed of security
server computations of access vectors, but these computations are only
required on AVC cache misses, and performance measurements by James Morris
using a number of benchmarks have shown that the change does not cause any
significant degradation.
Note that a rebuilt policy via an updated policy toolchain
(libsepol/checkpolicy) is required in order to gain the full benefits of
this patch, although some memory savings benefits are immediately applied
even to older policies (in particular, the reduction in avtab node size).
Sources for the updated toolchain are presently available from the
sourceforge CVS tree (http://sourceforge.net/cvs/?group_id=21266), and
tarballs are available from http://www.flux.utah.edu/~sds.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'security/selinux/ss/avtab.c')
-rw-r--r-- | security/selinux/ss/avtab.c | 192 |
1 files changed, 123 insertions, 69 deletions
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index f238c034c44e..2e71af67b5d8 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c | |||
@@ -58,6 +58,7 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat | |||
58 | { | 58 | { |
59 | int hvalue; | 59 | int hvalue; |
60 | struct avtab_node *prev, *cur, *newnode; | 60 | struct avtab_node *prev, *cur, *newnode; |
61 | u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); | ||
61 | 62 | ||
62 | if (!h) | 63 | if (!h) |
63 | return -EINVAL; | 64 | return -EINVAL; |
@@ -69,7 +70,7 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat | |||
69 | if (key->source_type == cur->key.source_type && | 70 | if (key->source_type == cur->key.source_type && |
70 | key->target_type == cur->key.target_type && | 71 | key->target_type == cur->key.target_type && |
71 | key->target_class == cur->key.target_class && | 72 | key->target_class == cur->key.target_class && |
72 | (datum->specified & cur->datum.specified)) | 73 | (specified & cur->key.specified)) |
73 | return -EEXIST; | 74 | return -EEXIST; |
74 | if (key->source_type < cur->key.source_type) | 75 | if (key->source_type < cur->key.source_type) |
75 | break; | 76 | break; |
@@ -98,6 +99,7 @@ avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_da | |||
98 | { | 99 | { |
99 | int hvalue; | 100 | int hvalue; |
100 | struct avtab_node *prev, *cur, *newnode; | 101 | struct avtab_node *prev, *cur, *newnode; |
102 | u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); | ||
101 | 103 | ||
102 | if (!h) | 104 | if (!h) |
103 | return NULL; | 105 | return NULL; |
@@ -108,7 +110,7 @@ avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_da | |||
108 | if (key->source_type == cur->key.source_type && | 110 | if (key->source_type == cur->key.source_type && |
109 | key->target_type == cur->key.target_type && | 111 | key->target_type == cur->key.target_type && |
110 | key->target_class == cur->key.target_class && | 112 | key->target_class == cur->key.target_class && |
111 | (datum->specified & cur->datum.specified)) | 113 | (specified & cur->key.specified)) |
112 | break; | 114 | break; |
113 | if (key->source_type < cur->key.source_type) | 115 | if (key->source_type < cur->key.source_type) |
114 | break; | 116 | break; |
@@ -125,10 +127,11 @@ avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_da | |||
125 | return newnode; | 127 | return newnode; |
126 | } | 128 | } |
127 | 129 | ||
128 | struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int specified) | 130 | struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key) |
129 | { | 131 | { |
130 | int hvalue; | 132 | int hvalue; |
131 | struct avtab_node *cur; | 133 | struct avtab_node *cur; |
134 | u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); | ||
132 | 135 | ||
133 | if (!h) | 136 | if (!h) |
134 | return NULL; | 137 | return NULL; |
@@ -138,7 +141,7 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int spe | |||
138 | if (key->source_type == cur->key.source_type && | 141 | if (key->source_type == cur->key.source_type && |
139 | key->target_type == cur->key.target_type && | 142 | key->target_type == cur->key.target_type && |
140 | key->target_class == cur->key.target_class && | 143 | key->target_class == cur->key.target_class && |
141 | (specified & cur->datum.specified)) | 144 | (specified & cur->key.specified)) |
142 | return &cur->datum; | 145 | return &cur->datum; |
143 | 146 | ||
144 | if (key->source_type < cur->key.source_type) | 147 | if (key->source_type < cur->key.source_type) |
@@ -159,10 +162,11 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int spe | |||
159 | * conjunction with avtab_search_next_node() | 162 | * conjunction with avtab_search_next_node() |
160 | */ | 163 | */ |
161 | struct avtab_node* | 164 | struct avtab_node* |
162 | avtab_search_node(struct avtab *h, struct avtab_key *key, int specified) | 165 | avtab_search_node(struct avtab *h, struct avtab_key *key) |
163 | { | 166 | { |
164 | int hvalue; | 167 | int hvalue; |
165 | struct avtab_node *cur; | 168 | struct avtab_node *cur; |
169 | u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); | ||
166 | 170 | ||
167 | if (!h) | 171 | if (!h) |
168 | return NULL; | 172 | return NULL; |
@@ -172,7 +176,7 @@ avtab_search_node(struct avtab *h, struct avtab_key *key, int specified) | |||
172 | if (key->source_type == cur->key.source_type && | 176 | if (key->source_type == cur->key.source_type && |
173 | key->target_type == cur->key.target_type && | 177 | key->target_type == cur->key.target_type && |
174 | key->target_class == cur->key.target_class && | 178 | key->target_class == cur->key.target_class && |
175 | (specified & cur->datum.specified)) | 179 | (specified & cur->key.specified)) |
176 | return cur; | 180 | return cur; |
177 | 181 | ||
178 | if (key->source_type < cur->key.source_type) | 182 | if (key->source_type < cur->key.source_type) |
@@ -196,11 +200,12 @@ avtab_search_node_next(struct avtab_node *node, int specified) | |||
196 | if (!node) | 200 | if (!node) |
197 | return NULL; | 201 | return NULL; |
198 | 202 | ||
203 | specified &= ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); | ||
199 | for (cur = node->next; cur; cur = cur->next) { | 204 | for (cur = node->next; cur; cur = cur->next) { |
200 | if (node->key.source_type == cur->key.source_type && | 205 | if (node->key.source_type == cur->key.source_type && |
201 | node->key.target_type == cur->key.target_type && | 206 | node->key.target_type == cur->key.target_type && |
202 | node->key.target_class == cur->key.target_class && | 207 | node->key.target_class == cur->key.target_class && |
203 | (specified & cur->datum.specified)) | 208 | (specified & cur->key.specified)) |
204 | return cur; | 209 | return cur; |
205 | 210 | ||
206 | if (node->key.source_type < cur->key.source_type) | 211 | if (node->key.source_type < cur->key.source_type) |
@@ -278,75 +283,126 @@ void avtab_hash_eval(struct avtab *h, char *tag) | |||
278 | max_chain_len); | 283 | max_chain_len); |
279 | } | 284 | } |
280 | 285 | ||
281 | int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey) | 286 | static uint16_t spec_order[] = { |
287 | AVTAB_ALLOWED, | ||
288 | AVTAB_AUDITDENY, | ||
289 | AVTAB_AUDITALLOW, | ||
290 | AVTAB_TRANSITION, | ||
291 | AVTAB_CHANGE, | ||
292 | AVTAB_MEMBER | ||
293 | }; | ||
294 | |||
295 | int avtab_read_item(void *fp, u32 vers, struct avtab *a, | ||
296 | int (*insertf)(struct avtab *a, struct avtab_key *k, | ||
297 | struct avtab_datum *d, void *p), | ||
298 | void *p) | ||
282 | { | 299 | { |
283 | u32 buf[7]; | 300 | u16 buf16[4], enabled; |
284 | u32 items, items2; | 301 | u32 buf32[7], items, items2, val; |
285 | int rc; | 302 | struct avtab_key key; |
303 | struct avtab_datum datum; | ||
304 | int i, rc; | ||
305 | |||
306 | memset(&key, 0, sizeof(struct avtab_key)); | ||
307 | memset(&datum, 0, sizeof(struct avtab_datum)); | ||
308 | |||
309 | if (vers < POLICYDB_VERSION_AVTAB) { | ||
310 | rc = next_entry(buf32, fp, sizeof(u32)); | ||
311 | if (rc < 0) { | ||
312 | printk(KERN_ERR "security: avtab: truncated entry\n"); | ||
313 | return -1; | ||
314 | } | ||
315 | items2 = le32_to_cpu(buf32[0]); | ||
316 | if (items2 > ARRAY_SIZE(buf32)) { | ||
317 | printk(KERN_ERR "security: avtab: entry overflow\n"); | ||
318 | return -1; | ||
286 | 319 | ||
287 | memset(avkey, 0, sizeof(struct avtab_key)); | 320 | } |
288 | memset(avdatum, 0, sizeof(struct avtab_datum)); | 321 | rc = next_entry(buf32, fp, sizeof(u32)*items2); |
322 | if (rc < 0) { | ||
323 | printk(KERN_ERR "security: avtab: truncated entry\n"); | ||
324 | return -1; | ||
325 | } | ||
326 | items = 0; | ||
289 | 327 | ||
290 | rc = next_entry(buf, fp, sizeof(u32)); | 328 | val = le32_to_cpu(buf32[items++]); |
291 | if (rc < 0) { | 329 | key.source_type = (u16)val; |
292 | printk(KERN_ERR "security: avtab: truncated entry\n"); | 330 | if (key.source_type != val) { |
293 | goto bad; | 331 | printk("security: avtab: truncated source type\n"); |
294 | } | 332 | return -1; |
295 | items2 = le32_to_cpu(buf[0]); | 333 | } |
296 | if (items2 > ARRAY_SIZE(buf)) { | 334 | val = le32_to_cpu(buf32[items++]); |
297 | printk(KERN_ERR "security: avtab: entry overflow\n"); | 335 | key.target_type = (u16)val; |
298 | goto bad; | 336 | if (key.target_type != val) { |
337 | printk("security: avtab: truncated target type\n"); | ||
338 | return -1; | ||
339 | } | ||
340 | val = le32_to_cpu(buf32[items++]); | ||
341 | key.target_class = (u16)val; | ||
342 | if (key.target_class != val) { | ||
343 | printk("security: avtab: truncated target class\n"); | ||
344 | return -1; | ||
345 | } | ||
346 | |||
347 | val = le32_to_cpu(buf32[items++]); | ||
348 | enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0; | ||
349 | |||
350 | if (!(val & (AVTAB_AV | AVTAB_TYPE))) { | ||
351 | printk("security: avtab: null entry\n"); | ||
352 | return -1; | ||
353 | } | ||
354 | if ((val & AVTAB_AV) && | ||
355 | (val & AVTAB_TYPE)) { | ||
356 | printk("security: avtab: entry has both access vectors and types\n"); | ||
357 | return -1; | ||
358 | } | ||
359 | |||
360 | for (i = 0; i < sizeof(spec_order)/sizeof(u16); i++) { | ||
361 | if (val & spec_order[i]) { | ||
362 | key.specified = spec_order[i] | enabled; | ||
363 | datum.data = le32_to_cpu(buf32[items++]); | ||
364 | rc = insertf(a, &key, &datum, p); | ||
365 | if (rc) return rc; | ||
366 | } | ||
367 | } | ||
368 | |||
369 | if (items != items2) { | ||
370 | printk("security: avtab: entry only had %d items, expected %d\n", items2, items); | ||
371 | return -1; | ||
372 | } | ||
373 | return 0; | ||
299 | } | 374 | } |
300 | rc = next_entry(buf, fp, sizeof(u32)*items2); | 375 | |
376 | rc = next_entry(buf16, fp, sizeof(u16)*4); | ||
301 | if (rc < 0) { | 377 | if (rc < 0) { |
302 | printk(KERN_ERR "security: avtab: truncated entry\n"); | 378 | printk("security: avtab: truncated entry\n"); |
303 | goto bad; | 379 | return -1; |
304 | } | 380 | } |
381 | |||
305 | items = 0; | 382 | items = 0; |
306 | avkey->source_type = le32_to_cpu(buf[items++]); | 383 | key.source_type = le16_to_cpu(buf16[items++]); |
307 | avkey->target_type = le32_to_cpu(buf[items++]); | 384 | key.target_type = le16_to_cpu(buf16[items++]); |
308 | avkey->target_class = le32_to_cpu(buf[items++]); | 385 | key.target_class = le16_to_cpu(buf16[items++]); |
309 | avdatum->specified = le32_to_cpu(buf[items++]); | 386 | key.specified = le16_to_cpu(buf16[items++]); |
310 | if (!(avdatum->specified & (AVTAB_AV | AVTAB_TYPE))) { | 387 | |
311 | printk(KERN_ERR "security: avtab: null entry\n"); | 388 | rc = next_entry(buf32, fp, sizeof(u32)); |
312 | goto bad; | 389 | if (rc < 0) { |
313 | } | 390 | printk("security: avtab: truncated entry\n"); |
314 | if ((avdatum->specified & AVTAB_AV) && | 391 | return -1; |
315 | (avdatum->specified & AVTAB_TYPE)) { | ||
316 | printk(KERN_ERR "security: avtab: entry has both access vectors and types\n"); | ||
317 | goto bad; | ||
318 | } | ||
319 | if (avdatum->specified & AVTAB_AV) { | ||
320 | if (avdatum->specified & AVTAB_ALLOWED) | ||
321 | avtab_allowed(avdatum) = le32_to_cpu(buf[items++]); | ||
322 | if (avdatum->specified & AVTAB_AUDITDENY) | ||
323 | avtab_auditdeny(avdatum) = le32_to_cpu(buf[items++]); | ||
324 | if (avdatum->specified & AVTAB_AUDITALLOW) | ||
325 | avtab_auditallow(avdatum) = le32_to_cpu(buf[items++]); | ||
326 | } else { | ||
327 | if (avdatum->specified & AVTAB_TRANSITION) | ||
328 | avtab_transition(avdatum) = le32_to_cpu(buf[items++]); | ||
329 | if (avdatum->specified & AVTAB_CHANGE) | ||
330 | avtab_change(avdatum) = le32_to_cpu(buf[items++]); | ||
331 | if (avdatum->specified & AVTAB_MEMBER) | ||
332 | avtab_member(avdatum) = le32_to_cpu(buf[items++]); | ||
333 | } | ||
334 | if (items != items2) { | ||
335 | printk(KERN_ERR "security: avtab: entry only had %d items, expected %d\n", | ||
336 | items2, items); | ||
337 | goto bad; | ||
338 | } | 392 | } |
393 | datum.data = le32_to_cpu(*buf32); | ||
394 | return insertf(a, &key, &datum, p); | ||
395 | } | ||
339 | 396 | ||
340 | return 0; | 397 | static int avtab_insertf(struct avtab *a, struct avtab_key *k, |
341 | bad: | 398 | struct avtab_datum *d, void *p) |
342 | return -1; | 399 | { |
400 | return avtab_insert(a, k, d); | ||
343 | } | 401 | } |
344 | 402 | ||
345 | int avtab_read(struct avtab *a, void *fp, u32 config) | 403 | int avtab_read(struct avtab *a, void *fp, u32 vers) |
346 | { | 404 | { |
347 | int rc; | 405 | int rc; |
348 | struct avtab_key avkey; | ||
349 | struct avtab_datum avdatum; | ||
350 | u32 buf[1]; | 406 | u32 buf[1]; |
351 | u32 nel, i; | 407 | u32 nel, i; |
352 | 408 | ||
@@ -363,16 +419,14 @@ int avtab_read(struct avtab *a, void *fp, u32 config) | |||
363 | goto bad; | 419 | goto bad; |
364 | } | 420 | } |
365 | for (i = 0; i < nel; i++) { | 421 | for (i = 0; i < nel; i++) { |
366 | if (avtab_read_item(fp, &avdatum, &avkey)) { | 422 | rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL); |
367 | rc = -EINVAL; | ||
368 | goto bad; | ||
369 | } | ||
370 | rc = avtab_insert(a, &avkey, &avdatum); | ||
371 | if (rc) { | 423 | if (rc) { |
372 | if (rc == -ENOMEM) | 424 | if (rc == -ENOMEM) |
373 | printk(KERN_ERR "security: avtab: out of memory\n"); | 425 | printk(KERN_ERR "security: avtab: out of memory\n"); |
374 | if (rc == -EEXIST) | 426 | else if (rc == -EEXIST) |
375 | printk(KERN_ERR "security: avtab: duplicate entry\n"); | 427 | printk(KERN_ERR "security: avtab: duplicate entry\n"); |
428 | else | ||
429 | rc = -EINVAL; | ||
376 | goto bad; | 430 | goto bad; |
377 | } | 431 | } |
378 | } | 432 | } |