diff options
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 | } |