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 | |
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>
-rw-r--r-- | security/selinux/include/security.h | 3 | ||||
-rw-r--r-- | security/selinux/ss/avtab.c | 192 | ||||
-rw-r--r-- | security/selinux/ss/avtab.h | 37 | ||||
-rw-r--r-- | security/selinux/ss/conditional.c | 205 | ||||
-rw-r--r-- | security/selinux/ss/ebitmap.h | 30 | ||||
-rw-r--r-- | security/selinux/ss/mls.c | 42 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 47 | ||||
-rw-r--r-- | security/selinux/ss/policydb.h | 3 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 76 |
9 files changed, 400 insertions, 235 deletions
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 71c0a19c9753..5f016c98056f 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -23,10 +23,11 @@ | |||
23 | #define POLICYDB_VERSION_NLCLASS 18 | 23 | #define POLICYDB_VERSION_NLCLASS 18 |
24 | #define POLICYDB_VERSION_VALIDATETRANS 19 | 24 | #define POLICYDB_VERSION_VALIDATETRANS 19 |
25 | #define POLICYDB_VERSION_MLS 19 | 25 | #define POLICYDB_VERSION_MLS 19 |
26 | #define POLICYDB_VERSION_AVTAB 20 | ||
26 | 27 | ||
27 | /* Range of policy versions we understand*/ | 28 | /* Range of policy versions we understand*/ |
28 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE | 29 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE |
29 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_MLS | 30 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_AVTAB |
30 | 31 | ||
31 | #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM | 32 | #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM |
32 | extern int selinux_enabled; | 33 | extern int selinux_enabled; |
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 | } |
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index 519d4f6dc655..0a90d939af93 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h | |||
@@ -21,12 +21,9 @@ | |||
21 | #define _SS_AVTAB_H_ | 21 | #define _SS_AVTAB_H_ |
22 | 22 | ||
23 | struct avtab_key { | 23 | struct avtab_key { |
24 | u32 source_type; /* source type */ | 24 | u16 source_type; /* source type */ |
25 | u32 target_type; /* target type */ | 25 | u16 target_type; /* target type */ |
26 | u32 target_class; /* target object class */ | 26 | u16 target_class; /* target object class */ |
27 | }; | ||
28 | |||
29 | struct avtab_datum { | ||
30 | #define AVTAB_ALLOWED 1 | 27 | #define AVTAB_ALLOWED 1 |
31 | #define AVTAB_AUDITALLOW 2 | 28 | #define AVTAB_AUDITALLOW 2 |
32 | #define AVTAB_AUDITDENY 4 | 29 | #define AVTAB_AUDITDENY 4 |
@@ -35,15 +32,13 @@ struct avtab_datum { | |||
35 | #define AVTAB_MEMBER 32 | 32 | #define AVTAB_MEMBER 32 |
36 | #define AVTAB_CHANGE 64 | 33 | #define AVTAB_CHANGE 64 |
37 | #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) | 34 | #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) |
38 | #define AVTAB_ENABLED 0x80000000 /* reserved for used in cond_avtab */ | 35 | #define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ |
39 | u32 specified; /* what fields are specified */ | 36 | #define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ |
40 | u32 data[3]; /* access vectors or types */ | 37 | u16 specified; /* what field is specified */ |
41 | #define avtab_allowed(x) (x)->data[0] | 38 | }; |
42 | #define avtab_auditdeny(x) (x)->data[1] | 39 | |
43 | #define avtab_auditallow(x) (x)->data[2] | 40 | struct avtab_datum { |
44 | #define avtab_transition(x) (x)->data[0] | 41 | u32 data; /* access vector or type value */ |
45 | #define avtab_change(x) (x)->data[1] | ||
46 | #define avtab_member(x) (x)->data[2] | ||
47 | }; | 42 | }; |
48 | 43 | ||
49 | struct avtab_node { | 44 | struct avtab_node { |
@@ -58,17 +53,21 @@ struct avtab { | |||
58 | }; | 53 | }; |
59 | 54 | ||
60 | int avtab_init(struct avtab *); | 55 | int avtab_init(struct avtab *); |
61 | struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k, int specified); | 56 | struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k); |
62 | void avtab_destroy(struct avtab *h); | 57 | void avtab_destroy(struct avtab *h); |
63 | void avtab_hash_eval(struct avtab *h, char *tag); | 58 | void avtab_hash_eval(struct avtab *h, char *tag); |
64 | 59 | ||
65 | int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey); | 60 | int avtab_read_item(void *fp, uint32_t vers, struct avtab *a, |
66 | int avtab_read(struct avtab *a, void *fp, u32 config); | 61 | int (*insert)(struct avtab *a, struct avtab_key *k, |
62 | struct avtab_datum *d, void *p), | ||
63 | void *p); | ||
64 | |||
65 | int avtab_read(struct avtab *a, void *fp, u32 vers); | ||
67 | 66 | ||
68 | struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, | 67 | struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, |
69 | struct avtab_datum *datum); | 68 | struct avtab_datum *datum); |
70 | 69 | ||
71 | struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key, int specified); | 70 | struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key); |
72 | 71 | ||
73 | struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified); | 72 | struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified); |
74 | 73 | ||
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index e2057f5a411a..b81cd6688978 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c | |||
@@ -100,18 +100,18 @@ int evaluate_cond_node(struct policydb *p, struct cond_node *node) | |||
100 | /* turn the rules on or off */ | 100 | /* turn the rules on or off */ |
101 | for (cur = node->true_list; cur != NULL; cur = cur->next) { | 101 | for (cur = node->true_list; cur != NULL; cur = cur->next) { |
102 | if (new_state <= 0) { | 102 | if (new_state <= 0) { |
103 | cur->node->datum.specified &= ~AVTAB_ENABLED; | 103 | cur->node->key.specified &= ~AVTAB_ENABLED; |
104 | } else { | 104 | } else { |
105 | cur->node->datum.specified |= AVTAB_ENABLED; | 105 | cur->node->key.specified |= AVTAB_ENABLED; |
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | for (cur = node->false_list; cur != NULL; cur = cur->next) { | 109 | for (cur = node->false_list; cur != NULL; cur = cur->next) { |
110 | /* -1 or 1 */ | 110 | /* -1 or 1 */ |
111 | if (new_state) { | 111 | if (new_state) { |
112 | cur->node->datum.specified &= ~AVTAB_ENABLED; | 112 | cur->node->key.specified &= ~AVTAB_ENABLED; |
113 | } else { | 113 | } else { |
114 | cur->node->datum.specified |= AVTAB_ENABLED; | 114 | cur->node->key.specified |= AVTAB_ENABLED; |
115 | } | 115 | } |
116 | } | 116 | } |
117 | } | 117 | } |
@@ -252,104 +252,126 @@ err: | |||
252 | return -1; | 252 | return -1; |
253 | } | 253 | } |
254 | 254 | ||
255 | static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, | 255 | struct cond_insertf_data |
256 | struct cond_av_list *other) | ||
257 | { | 256 | { |
258 | struct cond_av_list *list, *last = NULL, *cur; | 257 | struct policydb *p; |
259 | struct avtab_key key; | 258 | struct cond_av_list *other; |
260 | struct avtab_datum datum; | 259 | struct cond_av_list *head; |
260 | struct cond_av_list *tail; | ||
261 | }; | ||
262 | |||
263 | static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr) | ||
264 | { | ||
265 | struct cond_insertf_data *data = ptr; | ||
266 | struct policydb *p = data->p; | ||
267 | struct cond_av_list *other = data->other, *list, *cur; | ||
261 | struct avtab_node *node_ptr; | 268 | struct avtab_node *node_ptr; |
262 | int rc; | ||
263 | u32 buf[1], i, len; | ||
264 | u8 found; | 269 | u8 found; |
265 | 270 | ||
266 | *ret_list = NULL; | ||
267 | |||
268 | len = 0; | ||
269 | rc = next_entry(buf, fp, sizeof buf); | ||
270 | if (rc < 0) | ||
271 | return -1; | ||
272 | |||
273 | len = le32_to_cpu(buf[0]); | ||
274 | if (len == 0) { | ||
275 | return 0; | ||
276 | } | ||
277 | 271 | ||
278 | for (i = 0; i < len; i++) { | 272 | /* |
279 | if (avtab_read_item(fp, &datum, &key)) | 273 | * For type rules we have to make certain there aren't any |
274 | * conflicting rules by searching the te_avtab and the | ||
275 | * cond_te_avtab. | ||
276 | */ | ||
277 | if (k->specified & AVTAB_TYPE) { | ||
278 | if (avtab_search(&p->te_avtab, k)) { | ||
279 | printk("security: type rule already exists outside of a conditional."); | ||
280 | goto err; | 280 | goto err; |
281 | 281 | } | |
282 | /* | 282 | /* |
283 | * For type rules we have to make certain there aren't any | 283 | * If we are reading the false list other will be a pointer to |
284 | * conflicting rules by searching the te_avtab and the | 284 | * the true list. We can have duplicate entries if there is only |
285 | * cond_te_avtab. | 285 | * 1 other entry and it is in our true list. |
286 | * | ||
287 | * If we are reading the true list (other == NULL) there shouldn't | ||
288 | * be any other entries. | ||
286 | */ | 289 | */ |
287 | if (datum.specified & AVTAB_TYPE) { | 290 | if (other) { |
288 | if (avtab_search(&p->te_avtab, &key, AVTAB_TYPE)) { | 291 | node_ptr = avtab_search_node(&p->te_cond_avtab, k); |
289 | printk("security: type rule already exists outside of a conditional."); | 292 | if (node_ptr) { |
290 | goto err; | 293 | if (avtab_search_node_next(node_ptr, k->specified)) { |
291 | } | 294 | printk("security: too many conflicting type rules."); |
292 | /* | 295 | goto err; |
293 | * If we are reading the false list other will be a pointer to | 296 | } |
294 | * the true list. We can have duplicate entries if there is only | 297 | found = 0; |
295 | * 1 other entry and it is in our true list. | 298 | for (cur = other; cur != NULL; cur = cur->next) { |
296 | * | 299 | if (cur->node == node_ptr) { |
297 | * If we are reading the true list (other == NULL) there shouldn't | 300 | found = 1; |
298 | * be any other entries. | 301 | break; |
299 | */ | ||
300 | if (other) { | ||
301 | node_ptr = avtab_search_node(&p->te_cond_avtab, &key, AVTAB_TYPE); | ||
302 | if (node_ptr) { | ||
303 | if (avtab_search_node_next(node_ptr, AVTAB_TYPE)) { | ||
304 | printk("security: too many conflicting type rules."); | ||
305 | goto err; | ||
306 | } | ||
307 | found = 0; | ||
308 | for (cur = other; cur != NULL; cur = cur->next) { | ||
309 | if (cur->node == node_ptr) { | ||
310 | found = 1; | ||
311 | break; | ||
312 | } | ||
313 | } | ||
314 | if (!found) { | ||
315 | printk("security: conflicting type rules."); | ||
316 | goto err; | ||
317 | } | 302 | } |
318 | } | 303 | } |
319 | } else { | 304 | if (!found) { |
320 | if (avtab_search(&p->te_cond_avtab, &key, AVTAB_TYPE)) { | 305 | printk("security: conflicting type rules.\n"); |
321 | printk("security: conflicting type rules when adding type rule for true."); | ||
322 | goto err; | 306 | goto err; |
323 | } | 307 | } |
324 | } | 308 | } |
309 | } else { | ||
310 | if (avtab_search(&p->te_cond_avtab, k)) { | ||
311 | printk("security: conflicting type rules when adding type rule for true.\n"); | ||
312 | goto err; | ||
313 | } | ||
325 | } | 314 | } |
326 | node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, &key, &datum); | 315 | } |
327 | if (!node_ptr) { | ||
328 | printk("security: could not insert rule."); | ||
329 | goto err; | ||
330 | } | ||
331 | |||
332 | list = kmalloc(sizeof(struct cond_av_list), GFP_KERNEL); | ||
333 | if (!list) | ||
334 | goto err; | ||
335 | memset(list, 0, sizeof(struct cond_av_list)); | ||
336 | |||
337 | list->node = node_ptr; | ||
338 | if (i == 0) | ||
339 | *ret_list = list; | ||
340 | else | ||
341 | last->next = list; | ||
342 | last = list; | ||
343 | 316 | ||
317 | node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d); | ||
318 | if (!node_ptr) { | ||
319 | printk("security: could not insert rule."); | ||
320 | goto err; | ||
344 | } | 321 | } |
345 | 322 | ||
323 | list = kmalloc(sizeof(struct cond_av_list), GFP_KERNEL); | ||
324 | if (!list) | ||
325 | goto err; | ||
326 | memset(list, 0, sizeof(*list)); | ||
327 | |||
328 | list->node = node_ptr; | ||
329 | if (!data->head) | ||
330 | data->head = list; | ||
331 | else | ||
332 | data->tail->next = list; | ||
333 | data->tail = list; | ||
346 | return 0; | 334 | return 0; |
335 | |||
347 | err: | 336 | err: |
348 | cond_av_list_destroy(*ret_list); | 337 | cond_av_list_destroy(data->head); |
349 | *ret_list = NULL; | 338 | data->head = NULL; |
350 | return -1; | 339 | return -1; |
351 | } | 340 | } |
352 | 341 | ||
342 | static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other) | ||
343 | { | ||
344 | int i, rc; | ||
345 | u32 buf[1], len; | ||
346 | struct cond_insertf_data data; | ||
347 | |||
348 | *ret_list = NULL; | ||
349 | |||
350 | len = 0; | ||
351 | rc = next_entry(buf, fp, sizeof(u32)); | ||
352 | if (rc < 0) | ||
353 | return -1; | ||
354 | |||
355 | len = le32_to_cpu(buf[0]); | ||
356 | if (len == 0) { | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | data.p = p; | ||
361 | data.other = other; | ||
362 | data.head = NULL; | ||
363 | data.tail = NULL; | ||
364 | for (i = 0; i < len; i++) { | ||
365 | rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab, cond_insertf, &data); | ||
366 | if (rc) | ||
367 | return rc; | ||
368 | |||
369 | } | ||
370 | |||
371 | *ret_list = data.head; | ||
372 | return 0; | ||
373 | } | ||
374 | |||
353 | static int expr_isvalid(struct policydb *p, struct cond_expr *expr) | 375 | static int expr_isvalid(struct policydb *p, struct cond_expr *expr) |
354 | { | 376 | { |
355 | if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) { | 377 | if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) { |
@@ -452,6 +474,7 @@ int cond_read_list(struct policydb *p, void *fp) | |||
452 | return 0; | 474 | return 0; |
453 | err: | 475 | err: |
454 | cond_list_destroy(p->cond_list); | 476 | cond_list_destroy(p->cond_list); |
477 | p->cond_list = NULL; | ||
455 | return -1; | 478 | return -1; |
456 | } | 479 | } |
457 | 480 | ||
@@ -465,22 +488,22 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decisi | |||
465 | if(!ctab || !key || !avd) | 488 | if(!ctab || !key || !avd) |
466 | return; | 489 | return; |
467 | 490 | ||
468 | for(node = avtab_search_node(ctab, key, AVTAB_AV); node != NULL; | 491 | for(node = avtab_search_node(ctab, key); node != NULL; |
469 | node = avtab_search_node_next(node, AVTAB_AV)) { | 492 | node = avtab_search_node_next(node, key->specified)) { |
470 | if ( (__u32) (AVTAB_ALLOWED|AVTAB_ENABLED) == | 493 | if ( (u16) (AVTAB_ALLOWED|AVTAB_ENABLED) == |
471 | (node->datum.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) | 494 | (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) |
472 | avd->allowed |= avtab_allowed(&node->datum); | 495 | avd->allowed |= node->datum.data; |
473 | if ( (__u32) (AVTAB_AUDITDENY|AVTAB_ENABLED) == | 496 | if ( (u16) (AVTAB_AUDITDENY|AVTAB_ENABLED) == |
474 | (node->datum.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) | 497 | (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) |
475 | /* Since a '0' in an auditdeny mask represents a | 498 | /* Since a '0' in an auditdeny mask represents a |
476 | * permission we do NOT want to audit (dontaudit), we use | 499 | * permission we do NOT want to audit (dontaudit), we use |
477 | * the '&' operand to ensure that all '0's in the mask | 500 | * the '&' operand to ensure that all '0's in the mask |
478 | * are retained (much unlike the allow and auditallow cases). | 501 | * are retained (much unlike the allow and auditallow cases). |
479 | */ | 502 | */ |
480 | avd->auditdeny &= avtab_auditdeny(&node->datum); | 503 | avd->auditdeny &= node->datum.data; |
481 | if ( (__u32) (AVTAB_AUDITALLOW|AVTAB_ENABLED) == | 504 | if ( (u16) (AVTAB_AUDITALLOW|AVTAB_ENABLED) == |
482 | (node->datum.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) | 505 | (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) |
483 | avd->auditallow |= avtab_auditallow(&node->datum); | 506 | avd->auditallow |= node->datum.data; |
484 | } | 507 | } |
485 | return; | 508 | return; |
486 | } | 509 | } |
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index 471370233fd9..8bf41055a6cb 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h | |||
@@ -32,11 +32,41 @@ struct ebitmap { | |||
32 | #define ebitmap_length(e) ((e)->highbit) | 32 | #define ebitmap_length(e) ((e)->highbit) |
33 | #define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0) | 33 | #define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0) |
34 | 34 | ||
35 | static inline unsigned int ebitmap_start(struct ebitmap *e, | ||
36 | struct ebitmap_node **n) | ||
37 | { | ||
38 | *n = e->node; | ||
39 | return ebitmap_startbit(e); | ||
40 | } | ||
41 | |||
35 | static inline void ebitmap_init(struct ebitmap *e) | 42 | static inline void ebitmap_init(struct ebitmap *e) |
36 | { | 43 | { |
37 | memset(e, 0, sizeof(*e)); | 44 | memset(e, 0, sizeof(*e)); |
38 | } | 45 | } |
39 | 46 | ||
47 | static inline unsigned int ebitmap_next(struct ebitmap_node **n, | ||
48 | unsigned int bit) | ||
49 | { | ||
50 | if ((bit == ((*n)->startbit + MAPSIZE - 1)) && | ||
51 | (*n)->next) { | ||
52 | *n = (*n)->next; | ||
53 | return (*n)->startbit; | ||
54 | } | ||
55 | |||
56 | return (bit+1); | ||
57 | } | ||
58 | |||
59 | static inline int ebitmap_node_get_bit(struct ebitmap_node * n, | ||
60 | unsigned int bit) | ||
61 | { | ||
62 | if (n->map & (MAPBIT << (bit - n->startbit))) | ||
63 | return 1; | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | #define ebitmap_for_each_bit(e, n, bit) \ | ||
68 | for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \ | ||
69 | |||
40 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); | 70 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); |
41 | int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); | 71 | int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); |
42 | int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2); | 72 | int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2); |
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index d4c32c39ccc9..aaefac2921f1 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c | |||
@@ -27,6 +27,7 @@ | |||
27 | int mls_compute_context_len(struct context * context) | 27 | int mls_compute_context_len(struct context * context) |
28 | { | 28 | { |
29 | int i, l, len, range; | 29 | int i, l, len, range; |
30 | struct ebitmap_node *node; | ||
30 | 31 | ||
31 | if (!selinux_mls_enabled) | 32 | if (!selinux_mls_enabled) |
32 | return 0; | 33 | return 0; |
@@ -36,24 +37,24 @@ int mls_compute_context_len(struct context * context) | |||
36 | range = 0; | 37 | range = 0; |
37 | len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); | 38 | len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); |
38 | 39 | ||
39 | for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) { | 40 | ebitmap_for_each_bit(&context->range.level[l].cat, node, i) { |
40 | if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) { | 41 | if (ebitmap_node_get_bit(node, i)) { |
41 | if (range) { | 42 | if (range) { |
42 | range++; | 43 | range++; |
43 | continue; | 44 | continue; |
44 | } | 45 | } |
45 | 46 | ||
46 | len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1; | 47 | len += strlen(policydb.p_cat_val_to_name[i]) + 1; |
47 | range++; | 48 | range++; |
48 | } else { | 49 | } else { |
49 | if (range > 1) | 50 | if (range > 1) |
50 | len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1; | 51 | len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1; |
51 | range = 0; | 52 | range = 0; |
52 | } | 53 | } |
53 | } | 54 | } |
54 | /* Handle case where last category is the end of range */ | 55 | /* Handle case where last category is the end of range */ |
55 | if (range > 1) | 56 | if (range > 1) |
56 | len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1; | 57 | len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1; |
57 | 58 | ||
58 | if (l == 0) { | 59 | if (l == 0) { |
59 | if (mls_level_eq(&context->range.level[0], | 60 | if (mls_level_eq(&context->range.level[0], |
@@ -77,6 +78,7 @@ void mls_sid_to_context(struct context *context, | |||
77 | { | 78 | { |
78 | char *scontextp; | 79 | char *scontextp; |
79 | int i, l, range, wrote_sep; | 80 | int i, l, range, wrote_sep; |
81 | struct ebitmap_node *node; | ||
80 | 82 | ||
81 | if (!selinux_mls_enabled) | 83 | if (!selinux_mls_enabled) |
82 | return; | 84 | return; |
@@ -94,8 +96,8 @@ void mls_sid_to_context(struct context *context, | |||
94 | scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); | 96 | scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); |
95 | 97 | ||
96 | /* categories */ | 98 | /* categories */ |
97 | for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) { | 99 | ebitmap_for_each_bit(&context->range.level[l].cat, node, i) { |
98 | if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) { | 100 | if (ebitmap_node_get_bit(node, i)) { |
99 | if (range) { | 101 | if (range) { |
100 | range++; | 102 | range++; |
101 | continue; | 103 | continue; |
@@ -106,8 +108,8 @@ void mls_sid_to_context(struct context *context, | |||
106 | wrote_sep = 1; | 108 | wrote_sep = 1; |
107 | } else | 109 | } else |
108 | *scontextp++ = ','; | 110 | *scontextp++ = ','; |
109 | strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]); | 111 | strcpy(scontextp, policydb.p_cat_val_to_name[i]); |
110 | scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); | 112 | scontextp += strlen(policydb.p_cat_val_to_name[i]); |
111 | range++; | 113 | range++; |
112 | } else { | 114 | } else { |
113 | if (range > 1) { | 115 | if (range > 1) { |
@@ -116,8 +118,8 @@ void mls_sid_to_context(struct context *context, | |||
116 | else | 118 | else |
117 | *scontextp++ = ','; | 119 | *scontextp++ = ','; |
118 | 120 | ||
119 | strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]); | 121 | strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]); |
120 | scontextp += strlen(policydb.p_cat_val_to_name[i - 2]); | 122 | scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); |
121 | } | 123 | } |
122 | range = 0; | 124 | range = 0; |
123 | } | 125 | } |
@@ -130,8 +132,8 @@ void mls_sid_to_context(struct context *context, | |||
130 | else | 132 | else |
131 | *scontextp++ = ','; | 133 | *scontextp++ = ','; |
132 | 134 | ||
133 | strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]); | 135 | strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]); |
134 | scontextp += strlen(policydb.p_cat_val_to_name[i - 2]); | 136 | scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); |
135 | } | 137 | } |
136 | 138 | ||
137 | if (l == 0) { | 139 | if (l == 0) { |
@@ -157,6 +159,7 @@ int mls_context_isvalid(struct policydb *p, struct context *c) | |||
157 | { | 159 | { |
158 | struct level_datum *levdatum; | 160 | struct level_datum *levdatum; |
159 | struct user_datum *usrdatum; | 161 | struct user_datum *usrdatum; |
162 | struct ebitmap_node *node; | ||
160 | int i, l; | 163 | int i, l; |
161 | 164 | ||
162 | if (!selinux_mls_enabled) | 165 | if (!selinux_mls_enabled) |
@@ -179,11 +182,11 @@ int mls_context_isvalid(struct policydb *p, struct context *c) | |||
179 | if (!levdatum) | 182 | if (!levdatum) |
180 | return 0; | 183 | return 0; |
181 | 184 | ||
182 | for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) { | 185 | ebitmap_for_each_bit(&c->range.level[l].cat, node, i) { |
183 | if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) { | 186 | if (ebitmap_node_get_bit(node, i)) { |
184 | if (i > p->p_cats.nprim) | 187 | if (i > p->p_cats.nprim) |
185 | return 0; | 188 | return 0; |
186 | if (!ebitmap_get_bit(&levdatum->level->cat, i - 1)) | 189 | if (!ebitmap_get_bit(&levdatum->level->cat, i)) |
187 | /* | 190 | /* |
188 | * Category may not be associated with | 191 | * Category may not be associated with |
189 | * sensitivity in low level. | 192 | * sensitivity in low level. |
@@ -468,6 +471,7 @@ int mls_convert_context(struct policydb *oldp, | |||
468 | struct level_datum *levdatum; | 471 | struct level_datum *levdatum; |
469 | struct cat_datum *catdatum; | 472 | struct cat_datum *catdatum; |
470 | struct ebitmap bitmap; | 473 | struct ebitmap bitmap; |
474 | struct ebitmap_node *node; | ||
471 | int l, i; | 475 | int l, i; |
472 | 476 | ||
473 | if (!selinux_mls_enabled) | 477 | if (!selinux_mls_enabled) |
@@ -482,12 +486,12 @@ int mls_convert_context(struct policydb *oldp, | |||
482 | c->range.level[l].sens = levdatum->level->sens; | 486 | c->range.level[l].sens = levdatum->level->sens; |
483 | 487 | ||
484 | ebitmap_init(&bitmap); | 488 | ebitmap_init(&bitmap); |
485 | for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) { | 489 | ebitmap_for_each_bit(&c->range.level[l].cat, node, i) { |
486 | if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) { | 490 | if (ebitmap_node_get_bit(node, i)) { |
487 | int rc; | 491 | int rc; |
488 | 492 | ||
489 | catdatum = hashtab_search(newp->p_cats.table, | 493 | catdatum = hashtab_search(newp->p_cats.table, |
490 | oldp->p_cat_val_to_name[i - 1]); | 494 | oldp->p_cat_val_to_name[i]); |
491 | if (!catdatum) | 495 | if (!catdatum) |
492 | return -EINVAL; | 496 | return -EINVAL; |
493 | rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); | 497 | rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 785c33cf4864..7b03fa0f92b0 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -91,6 +91,11 @@ static struct policydb_compat_info policydb_compat[] = { | |||
91 | .sym_num = SYM_NUM, | 91 | .sym_num = SYM_NUM, |
92 | .ocon_num = OCON_NUM, | 92 | .ocon_num = OCON_NUM, |
93 | }, | 93 | }, |
94 | { | ||
95 | .version = POLICYDB_VERSION_AVTAB, | ||
96 | .sym_num = SYM_NUM, | ||
97 | .ocon_num = OCON_NUM, | ||
98 | }, | ||
94 | }; | 99 | }; |
95 | 100 | ||
96 | static struct policydb_compat_info *policydb_lookup_compat(int version) | 101 | static struct policydb_compat_info *policydb_lookup_compat(int version) |
@@ -584,6 +589,9 @@ void policydb_destroy(struct policydb *p) | |||
584 | struct ocontext *c, *ctmp; | 589 | struct ocontext *c, *ctmp; |
585 | struct genfs *g, *gtmp; | 590 | struct genfs *g, *gtmp; |
586 | int i; | 591 | int i; |
592 | struct role_allow *ra, *lra = NULL; | ||
593 | struct role_trans *tr, *ltr = NULL; | ||
594 | struct range_trans *rt, *lrt = NULL; | ||
587 | 595 | ||
588 | for (i = 0; i < SYM_NUM; i++) { | 596 | for (i = 0; i < SYM_NUM; i++) { |
589 | hashtab_map(p->symtab[i].table, destroy_f[i], NULL); | 597 | hashtab_map(p->symtab[i].table, destroy_f[i], NULL); |
@@ -624,6 +632,28 @@ void policydb_destroy(struct policydb *p) | |||
624 | 632 | ||
625 | cond_policydb_destroy(p); | 633 | cond_policydb_destroy(p); |
626 | 634 | ||
635 | for (tr = p->role_tr; tr; tr = tr->next) { | ||
636 | if (ltr) kfree(ltr); | ||
637 | ltr = tr; | ||
638 | } | ||
639 | if (ltr) kfree(ltr); | ||
640 | |||
641 | for (ra = p->role_allow; ra; ra = ra -> next) { | ||
642 | if (lra) kfree(lra); | ||
643 | lra = ra; | ||
644 | } | ||
645 | if (lra) kfree(lra); | ||
646 | |||
647 | for (rt = p->range_tr; rt; rt = rt -> next) { | ||
648 | if (lrt) kfree(lrt); | ||
649 | lrt = rt; | ||
650 | } | ||
651 | if (lrt) kfree(lrt); | ||
652 | |||
653 | for (i = 0; i < p->p_types.nprim; i++) | ||
654 | ebitmap_destroy(&p->type_attr_map[i]); | ||
655 | kfree(p->type_attr_map); | ||
656 | |||
627 | return; | 657 | return; |
628 | } | 658 | } |
629 | 659 | ||
@@ -1511,7 +1541,7 @@ int policydb_read(struct policydb *p, void *fp) | |||
1511 | p->symtab[i].nprim = nprim; | 1541 | p->symtab[i].nprim = nprim; |
1512 | } | 1542 | } |
1513 | 1543 | ||
1514 | rc = avtab_read(&p->te_avtab, fp, config); | 1544 | rc = avtab_read(&p->te_avtab, fp, p->policyvers); |
1515 | if (rc) | 1545 | if (rc) |
1516 | goto bad; | 1546 | goto bad; |
1517 | 1547 | ||
@@ -1825,6 +1855,21 @@ int policydb_read(struct policydb *p, void *fp) | |||
1825 | } | 1855 | } |
1826 | } | 1856 | } |
1827 | 1857 | ||
1858 | p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); | ||
1859 | if (!p->type_attr_map) | ||
1860 | goto bad; | ||
1861 | |||
1862 | for (i = 0; i < p->p_types.nprim; i++) { | ||
1863 | ebitmap_init(&p->type_attr_map[i]); | ||
1864 | if (p->policyvers >= POLICYDB_VERSION_AVTAB) { | ||
1865 | if (ebitmap_read(&p->type_attr_map[i], fp)) | ||
1866 | goto bad; | ||
1867 | } | ||
1868 | /* add the type itself as the degenerate case */ | ||
1869 | if (ebitmap_set_bit(&p->type_attr_map[i], i, 1)) | ||
1870 | goto bad; | ||
1871 | } | ||
1872 | |||
1828 | rc = 0; | 1873 | rc = 0; |
1829 | out: | 1874 | out: |
1830 | return rc; | 1875 | return rc; |
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 2470e2a1a1c3..b1340711f721 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
@@ -237,6 +237,9 @@ struct policydb { | |||
237 | /* range transitions */ | 237 | /* range transitions */ |
238 | struct range_trans *range_tr; | 238 | struct range_trans *range_tr; |
239 | 239 | ||
240 | /* type -> attribute reverse mapping */ | ||
241 | struct ebitmap *type_attr_map; | ||
242 | |||
240 | unsigned int policyvers; | 243 | unsigned int policyvers; |
241 | }; | 244 | }; |
242 | 245 | ||
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 014120474e69..92b89dc99bcd 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -266,8 +266,11 @@ static int context_struct_compute_av(struct context *scontext, | |||
266 | struct constraint_node *constraint; | 266 | struct constraint_node *constraint; |
267 | struct role_allow *ra; | 267 | struct role_allow *ra; |
268 | struct avtab_key avkey; | 268 | struct avtab_key avkey; |
269 | struct avtab_datum *avdatum; | 269 | struct avtab_node *node; |
270 | struct class_datum *tclass_datum; | 270 | struct class_datum *tclass_datum; |
271 | struct ebitmap *sattr, *tattr; | ||
272 | struct ebitmap_node *snode, *tnode; | ||
273 | unsigned int i, j; | ||
271 | 274 | ||
272 | /* | 275 | /* |
273 | * Remap extended Netlink classes for old policy versions. | 276 | * Remap extended Netlink classes for old policy versions. |
@@ -300,21 +303,34 @@ static int context_struct_compute_av(struct context *scontext, | |||
300 | * If a specific type enforcement rule was defined for | 303 | * If a specific type enforcement rule was defined for |
301 | * this permission check, then use it. | 304 | * this permission check, then use it. |
302 | */ | 305 | */ |
303 | avkey.source_type = scontext->type; | ||
304 | avkey.target_type = tcontext->type; | ||
305 | avkey.target_class = tclass; | 306 | avkey.target_class = tclass; |
306 | avdatum = avtab_search(&policydb.te_avtab, &avkey, AVTAB_AV); | 307 | avkey.specified = AVTAB_AV; |
307 | if (avdatum) { | 308 | sattr = &policydb.type_attr_map[scontext->type - 1]; |
308 | if (avdatum->specified & AVTAB_ALLOWED) | 309 | tattr = &policydb.type_attr_map[tcontext->type - 1]; |
309 | avd->allowed = avtab_allowed(avdatum); | 310 | ebitmap_for_each_bit(sattr, snode, i) { |
310 | if (avdatum->specified & AVTAB_AUDITDENY) | 311 | if (!ebitmap_node_get_bit(snode, i)) |
311 | avd->auditdeny = avtab_auditdeny(avdatum); | 312 | continue; |
312 | if (avdatum->specified & AVTAB_AUDITALLOW) | 313 | ebitmap_for_each_bit(tattr, tnode, j) { |
313 | avd->auditallow = avtab_auditallow(avdatum); | 314 | if (!ebitmap_node_get_bit(tnode, j)) |
314 | } | 315 | continue; |
316 | avkey.source_type = i + 1; | ||
317 | avkey.target_type = j + 1; | ||
318 | for (node = avtab_search_node(&policydb.te_avtab, &avkey); | ||
319 | node != NULL; | ||
320 | node = avtab_search_node_next(node, avkey.specified)) { | ||
321 | if (node->key.specified == AVTAB_ALLOWED) | ||
322 | avd->allowed |= node->datum.data; | ||
323 | else if (node->key.specified == AVTAB_AUDITALLOW) | ||
324 | avd->auditallow |= node->datum.data; | ||
325 | else if (node->key.specified == AVTAB_AUDITDENY) | ||
326 | avd->auditdeny &= node->datum.data; | ||
327 | } | ||
315 | 328 | ||
316 | /* Check conditional av table for additional permissions */ | 329 | /* Check conditional av table for additional permissions */ |
317 | cond_compute_av(&policydb.te_cond_avtab, &avkey, avd); | 330 | cond_compute_av(&policydb.te_cond_avtab, &avkey, avd); |
331 | |||
332 | } | ||
333 | } | ||
318 | 334 | ||
319 | /* | 335 | /* |
320 | * Remove any permissions prohibited by a constraint (this includes | 336 | * Remove any permissions prohibited by a constraint (this includes |
@@ -797,7 +813,6 @@ static int security_compute_sid(u32 ssid, | |||
797 | struct avtab_key avkey; | 813 | struct avtab_key avkey; |
798 | struct avtab_datum *avdatum; | 814 | struct avtab_datum *avdatum; |
799 | struct avtab_node *node; | 815 | struct avtab_node *node; |
800 | unsigned int type_change = 0; | ||
801 | int rc = 0; | 816 | int rc = 0; |
802 | 817 | ||
803 | if (!ss_initialized) { | 818 | if (!ss_initialized) { |
@@ -862,33 +877,23 @@ static int security_compute_sid(u32 ssid, | |||
862 | avkey.source_type = scontext->type; | 877 | avkey.source_type = scontext->type; |
863 | avkey.target_type = tcontext->type; | 878 | avkey.target_type = tcontext->type; |
864 | avkey.target_class = tclass; | 879 | avkey.target_class = tclass; |
865 | avdatum = avtab_search(&policydb.te_avtab, &avkey, AVTAB_TYPE); | 880 | avkey.specified = specified; |
881 | avdatum = avtab_search(&policydb.te_avtab, &avkey); | ||
866 | 882 | ||
867 | /* If no permanent rule, also check for enabled conditional rules */ | 883 | /* If no permanent rule, also check for enabled conditional rules */ |
868 | if(!avdatum) { | 884 | if(!avdatum) { |
869 | node = avtab_search_node(&policydb.te_cond_avtab, &avkey, specified); | 885 | node = avtab_search_node(&policydb.te_cond_avtab, &avkey); |
870 | for (; node != NULL; node = avtab_search_node_next(node, specified)) { | 886 | for (; node != NULL; node = avtab_search_node_next(node, specified)) { |
871 | if (node->datum.specified & AVTAB_ENABLED) { | 887 | if (node->key.specified & AVTAB_ENABLED) { |
872 | avdatum = &node->datum; | 888 | avdatum = &node->datum; |
873 | break; | 889 | break; |
874 | } | 890 | } |
875 | } | 891 | } |
876 | } | 892 | } |
877 | 893 | ||
878 | type_change = (avdatum && (avdatum->specified & specified)); | 894 | if (avdatum) { |
879 | if (type_change) { | ||
880 | /* Use the type from the type transition/member/change rule. */ | 895 | /* Use the type from the type transition/member/change rule. */ |
881 | switch (specified) { | 896 | newcontext.type = avdatum->data; |
882 | case AVTAB_TRANSITION: | ||
883 | newcontext.type = avtab_transition(avdatum); | ||
884 | break; | ||
885 | case AVTAB_MEMBER: | ||
886 | newcontext.type = avtab_member(avdatum); | ||
887 | break; | ||
888 | case AVTAB_CHANGE: | ||
889 | newcontext.type = avtab_change(avdatum); | ||
890 | break; | ||
891 | } | ||
892 | } | 897 | } |
893 | 898 | ||
894 | /* Check for class-specific changes. */ | 899 | /* Check for class-specific changes. */ |
@@ -1502,6 +1507,7 @@ int security_get_user_sids(u32 fromsid, | |||
1502 | struct user_datum *user; | 1507 | struct user_datum *user; |
1503 | struct role_datum *role; | 1508 | struct role_datum *role; |
1504 | struct av_decision avd; | 1509 | struct av_decision avd; |
1510 | struct ebitmap_node *rnode, *tnode; | ||
1505 | int rc = 0, i, j; | 1511 | int rc = 0, i, j; |
1506 | 1512 | ||
1507 | if (!ss_initialized) { | 1513 | if (!ss_initialized) { |
@@ -1532,13 +1538,13 @@ int security_get_user_sids(u32 fromsid, | |||
1532 | } | 1538 | } |
1533 | memset(mysids, 0, maxnel*sizeof(*mysids)); | 1539 | memset(mysids, 0, maxnel*sizeof(*mysids)); |
1534 | 1540 | ||
1535 | for (i = ebitmap_startbit(&user->roles); i < ebitmap_length(&user->roles); i++) { | 1541 | ebitmap_for_each_bit(&user->roles, rnode, i) { |
1536 | if (!ebitmap_get_bit(&user->roles, i)) | 1542 | if (!ebitmap_node_get_bit(rnode, i)) |
1537 | continue; | 1543 | continue; |
1538 | role = policydb.role_val_to_struct[i]; | 1544 | role = policydb.role_val_to_struct[i]; |
1539 | usercon.role = i+1; | 1545 | usercon.role = i+1; |
1540 | for (j = ebitmap_startbit(&role->types); j < ebitmap_length(&role->types); j++) { | 1546 | ebitmap_for_each_bit(&role->types, tnode, j) { |
1541 | if (!ebitmap_get_bit(&role->types, j)) | 1547 | if (!ebitmap_node_get_bit(tnode, j)) |
1542 | continue; | 1548 | continue; |
1543 | usercon.type = j+1; | 1549 | usercon.type = j+1; |
1544 | 1550 | ||