aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/ss/avtab.c
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2005-09-03 18:55:16 -0400
committerLinus Torvalds <torvalds@evo.osdl.org>2005-09-05 03:05:50 -0400
commit782ebb992ec20b5afdd5786ee8c2f1b58b631f24 (patch)
treeadf0af44fa591d803ec6b9ab7541ff3e5745dd93 /security/selinux/ss/avtab.c
parent720d6c29e146e96cca858057469951e91e0e6850 (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.c192
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
128struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int specified) 130struct 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 */
161struct avtab_node* 164struct avtab_node*
162avtab_search_node(struct avtab *h, struct avtab_key *key, int specified) 165avtab_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
281int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey) 286static uint16_t spec_order[] = {
287 AVTAB_ALLOWED,
288 AVTAB_AUDITDENY,
289 AVTAB_AUDITALLOW,
290 AVTAB_TRANSITION,
291 AVTAB_CHANGE,
292 AVTAB_MEMBER
293};
294
295int 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; 397static int avtab_insertf(struct avtab *a, struct avtab_key *k,
341bad: 398 struct avtab_datum *d, void *p)
342 return -1; 399{
400 return avtab_insert(a, k, d);
343} 401}
344 402
345int avtab_read(struct avtab *a, void *fp, u32 config) 403int 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 }