aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--security/selinux/ss/avtab.c91
-rw-r--r--security/selinux/ss/avtab.h16
-rw-r--r--security/selinux/ss/conditional.c4
-rw-r--r--security/selinux/ss/policydb.c7
4 files changed, 82 insertions, 36 deletions
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index 85705eb289e0..7551af1f7899 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -12,24 +12,25 @@
12 * This program is free software; you can redistribute it and/or modify 12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by 13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, version 2. 14 * the Free Software Foundation, version 2.
15 *
16 * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
17 * Tuned number of hash slots for avtab to reduce memory usage
15 */ 18 */
16 19
17#include <linux/kernel.h> 20#include <linux/kernel.h>
18#include <linux/slab.h> 21#include <linux/slab.h>
19#include <linux/vmalloc.h>
20#include <linux/errno.h> 22#include <linux/errno.h>
21
22#include "avtab.h" 23#include "avtab.h"
23#include "policydb.h" 24#include "policydb.h"
24 25
25#define AVTAB_HASH(keyp) \
26((keyp->target_class + \
27 (keyp->target_type << 2) + \
28 (keyp->source_type << 9)) & \
29 AVTAB_HASH_MASK)
30
31static struct kmem_cache *avtab_node_cachep; 26static struct kmem_cache *avtab_node_cachep;
32 27
28static inline int avtab_hash(struct avtab_key *keyp, u16 mask)
29{
30 return ((keyp->target_class + (keyp->target_type << 2) +
31 (keyp->source_type << 9)) & mask);
32}
33
33static struct avtab_node* 34static struct avtab_node*
34avtab_insert_node(struct avtab *h, int hvalue, 35avtab_insert_node(struct avtab *h, int hvalue,
35 struct avtab_node * prev, struct avtab_node * cur, 36 struct avtab_node * prev, struct avtab_node * cur,
@@ -59,10 +60,10 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat
59 struct avtab_node *prev, *cur, *newnode; 60 struct avtab_node *prev, *cur, *newnode;
60 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); 61 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
61 62
62 if (!h) 63 if (!h || !h->htable)
63 return -EINVAL; 64 return -EINVAL;
64 65
65 hvalue = AVTAB_HASH(key); 66 hvalue = avtab_hash(key, h->mask);
66 for (prev = NULL, cur = h->htable[hvalue]; 67 for (prev = NULL, cur = h->htable[hvalue];
67 cur; 68 cur;
68 prev = cur, cur = cur->next) { 69 prev = cur, cur = cur->next) {
@@ -100,9 +101,9 @@ avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_da
100 struct avtab_node *prev, *cur, *newnode; 101 struct avtab_node *prev, *cur, *newnode;
101 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); 102 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
102 103
103 if (!h) 104 if (!h || !h->htable)
104 return NULL; 105 return NULL;
105 hvalue = AVTAB_HASH(key); 106 hvalue = avtab_hash(key, h->mask);
106 for (prev = NULL, cur = h->htable[hvalue]; 107 for (prev = NULL, cur = h->htable[hvalue];
107 cur; 108 cur;
108 prev = cur, cur = cur->next) { 109 prev = cur, cur = cur->next) {
@@ -132,10 +133,10 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
132 struct avtab_node *cur; 133 struct avtab_node *cur;
133 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); 134 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
134 135
135 if (!h) 136 if (!h || !h->htable)
136 return NULL; 137 return NULL;
137 138
138 hvalue = AVTAB_HASH(key); 139 hvalue = avtab_hash(key, h->mask);
139 for (cur = h->htable[hvalue]; cur; cur = cur->next) { 140 for (cur = h->htable[hvalue]; cur; cur = cur->next) {
140 if (key->source_type == cur->key.source_type && 141 if (key->source_type == cur->key.source_type &&
141 key->target_type == cur->key.target_type && 142 key->target_type == cur->key.target_type &&
@@ -167,10 +168,10 @@ avtab_search_node(struct avtab *h, struct avtab_key *key)
167 struct avtab_node *cur; 168 struct avtab_node *cur;
168 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); 169 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
169 170
170 if (!h) 171 if (!h || !h->htable)
171 return NULL; 172 return NULL;
172 173
173 hvalue = AVTAB_HASH(key); 174 hvalue = avtab_hash(key, h->mask);
174 for (cur = h->htable[hvalue]; cur; cur = cur->next) { 175 for (cur = h->htable[hvalue]; cur; cur = cur->next) {
175 if (key->source_type == cur->key.source_type && 176 if (key->source_type == cur->key.source_type &&
176 key->target_type == cur->key.target_type && 177 key->target_type == cur->key.target_type &&
@@ -228,7 +229,7 @@ void avtab_destroy(struct avtab *h)
228 if (!h || !h->htable) 229 if (!h || !h->htable)
229 return; 230 return;
230 231
231 for (i = 0; i < AVTAB_SIZE; i++) { 232 for (i = 0; i < h->nslot; i++) {
232 cur = h->htable[i]; 233 cur = h->htable[i];
233 while (cur != NULL) { 234 while (cur != NULL) {
234 temp = cur; 235 temp = cur;
@@ -237,32 +238,63 @@ void avtab_destroy(struct avtab *h)
237 } 238 }
238 h->htable[i] = NULL; 239 h->htable[i] = NULL;
239 } 240 }
240 vfree(h->htable); 241 kfree(h->htable);
241 h->htable = NULL; 242 h->htable = NULL;
243 h->nslot = 0;
244 h->mask = 0;
242} 245}
243 246
244
245int avtab_init(struct avtab *h) 247int avtab_init(struct avtab *h)
246{ 248{
247 int i; 249 h->htable = NULL;
250 h->nel = 0;
251 return 0;
252}
253
254int avtab_alloc(struct avtab *h, u32 nrules)
255{
256 u16 mask = 0;
257 u32 shift = 0;
258 u32 work = nrules;
259 u32 nslot = 0;
260
261 if (nrules == 0)
262 goto avtab_alloc_out;
248 263
249 h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE); 264 while (work) {
265 work = work >> 1;
266 shift++;
267 }
268 if (shift > 2)
269 shift = shift - 2;
270 nslot = 1 << shift;
271 if (nslot > MAX_AVTAB_SIZE)
272 nslot = MAX_AVTAB_SIZE;
273 mask = nslot - 1;
274
275 h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL);
250 if (!h->htable) 276 if (!h->htable)
251 return -ENOMEM; 277 return -ENOMEM;
252 for (i = 0; i < AVTAB_SIZE; i++) 278
253 h->htable[i] = NULL; 279 avtab_alloc_out:
254 h->nel = 0; 280 h->nel = 0;
281 h->nslot = nslot;
282 h->mask = mask;
283 printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated."
284 "Num of rules:%d\n", h->nslot, nrules);
255 return 0; 285 return 0;
256} 286}
257 287
258void avtab_hash_eval(struct avtab *h, char *tag) 288void avtab_hash_eval(struct avtab *h, char *tag)
259{ 289{
260 int i, chain_len, slots_used, max_chain_len; 290 int i, chain_len, slots_used, max_chain_len;
291 unsigned long long chain2_len_sum;
261 struct avtab_node *cur; 292 struct avtab_node *cur;
262 293
263 slots_used = 0; 294 slots_used = 0;
264 max_chain_len = 0; 295 max_chain_len = 0;
265 for (i = 0; i < AVTAB_SIZE; i++) { 296 chain2_len_sum = 0;
297 for (i = 0; i < h->nslot; i++) {
266 cur = h->htable[i]; 298 cur = h->htable[i];
267 if (cur) { 299 if (cur) {
268 slots_used++; 300 slots_used++;
@@ -274,12 +306,14 @@ void avtab_hash_eval(struct avtab *h, char *tag)
274 306
275 if (chain_len > max_chain_len) 307 if (chain_len > max_chain_len)
276 max_chain_len = chain_len; 308 max_chain_len = chain_len;
309 chain2_len_sum += chain_len * chain_len;
277 } 310 }
278 } 311 }
279 312
280 printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest " 313 printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest "
281 "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE, 314 "chain length %d sum of chain length^2 %Lu\n",
282 max_chain_len); 315 tag, h->nel, slots_used, h->nslot, max_chain_len,
316 chain2_len_sum);
283} 317}
284 318
285static uint16_t spec_order[] = { 319static uint16_t spec_order[] = {
@@ -419,6 +453,11 @@ int avtab_read(struct avtab *a, void *fp, u32 vers)
419 rc = -EINVAL; 453 rc = -EINVAL;
420 goto bad; 454 goto bad;
421 } 455 }
456
457 rc = avtab_alloc(a, nel);
458 if (rc)
459 goto bad;
460
422 for (i = 0; i < nel; i++) { 461 for (i = 0; i < nel; i++) {
423 rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL); 462 rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
424 if (rc) { 463 if (rc) {
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
index 0a90d939af93..d8edf8ca56d1 100644
--- a/security/selinux/ss/avtab.h
+++ b/security/selinux/ss/avtab.h
@@ -16,6 +16,9 @@
16 * This program is free software; you can redistribute it and/or modify 16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, version 2. 18 * the Free Software Foundation, version 2.
19 *
20 * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
21 * Tuned number of hash slots for avtab to reduce memory usage
19 */ 22 */
20#ifndef _SS_AVTAB_H_ 23#ifndef _SS_AVTAB_H_
21#define _SS_AVTAB_H_ 24#define _SS_AVTAB_H_
@@ -50,9 +53,13 @@ struct avtab_node {
50struct avtab { 53struct avtab {
51 struct avtab_node **htable; 54 struct avtab_node **htable;
52 u32 nel; /* number of elements */ 55 u32 nel; /* number of elements */
56 u32 nslot; /* number of hash slots */
57 u16 mask; /* mask to compute hash func */
58
53}; 59};
54 60
55int avtab_init(struct avtab *); 61int avtab_init(struct avtab *);
62int avtab_alloc(struct avtab *, u32);
56struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k); 63struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
57void avtab_destroy(struct avtab *h); 64void avtab_destroy(struct avtab *h);
58void avtab_hash_eval(struct avtab *h, char *tag); 65void avtab_hash_eval(struct avtab *h, char *tag);
@@ -74,11 +81,10 @@ struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified
74void avtab_cache_init(void); 81void avtab_cache_init(void);
75void avtab_cache_destroy(void); 82void avtab_cache_destroy(void);
76 83
77#define AVTAB_HASH_BITS 15 84#define MAX_AVTAB_HASH_BITS 13
78#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS) 85#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
79#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1) 86#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
80 87#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
81#define AVTAB_SIZE AVTAB_HASH_BUCKETS
82 88
83#endif /* _SS_AVTAB_H_ */ 89#endif /* _SS_AVTAB_H_ */
84 90
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index d2737edba541..45b93a827c80 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -456,6 +456,10 @@ int cond_read_list(struct policydb *p, void *fp)
456 456
457 len = le32_to_cpu(buf[0]); 457 len = le32_to_cpu(buf[0]);
458 458
459 rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
460 if (rc)
461 goto err;
462
459 for (i = 0; i < len; i++) { 463 for (i = 0; i < len; i++) {
460 node = kzalloc(sizeof(struct cond_node), GFP_KERNEL); 464 node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
461 if (!node) 465 if (!node)
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index f05f97a2bc3a..5ecbad7d8b9f 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -177,18 +177,15 @@ static int policydb_init(struct policydb *p)
177 177
178 rc = roles_init(p); 178 rc = roles_init(p);
179 if (rc) 179 if (rc)
180 goto out_free_avtab; 180 goto out_free_symtab;
181 181
182 rc = cond_policydb_init(p); 182 rc = cond_policydb_init(p);
183 if (rc) 183 if (rc)
184 goto out_free_avtab; 184 goto out_free_symtab;
185 185
186out: 186out:
187 return rc; 187 return rc;
188 188
189out_free_avtab:
190 avtab_destroy(&p->te_avtab);
191
192out_free_symtab: 189out_free_symtab:
193 for (i = 0; i < SYM_NUM; i++) 190 for (i = 0; i < SYM_NUM; i++)
194 hashtab_destroy(p->symtab[i].table); 191 hashtab_destroy(p->symtab[i].table);