diff options
Diffstat (limited to 'security/selinux/ss/avtab.c')
-rw-r--r-- | security/selinux/ss/avtab.c | 196 |
1 files changed, 126 insertions, 70 deletions
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index f238c034c44..dde094feb20 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,76 +283,129 @@ 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 | __le16 buf16[4]; |
284 | u32 items, items2; | 301 | u16 enabled; |
285 | int rc; | 302 | __le32 buf32[7]; |
303 | u32 items, items2, val; | ||
304 | struct avtab_key key; | ||
305 | struct avtab_datum datum; | ||
306 | int i, rc; | ||
307 | |||
308 | memset(&key, 0, sizeof(struct avtab_key)); | ||
309 | memset(&datum, 0, sizeof(struct avtab_datum)); | ||
310 | |||
311 | if (vers < POLICYDB_VERSION_AVTAB) { | ||
312 | rc = next_entry(buf32, fp, sizeof(u32)); | ||
313 | if (rc < 0) { | ||
314 | printk(KERN_ERR "security: avtab: truncated entry\n"); | ||
315 | return -1; | ||
316 | } | ||
317 | items2 = le32_to_cpu(buf32[0]); | ||
318 | if (items2 > ARRAY_SIZE(buf32)) { | ||
319 | printk(KERN_ERR "security: avtab: entry overflow\n"); | ||
320 | return -1; | ||
286 | 321 | ||
287 | memset(avkey, 0, sizeof(struct avtab_key)); | 322 | } |
288 | memset(avdatum, 0, sizeof(struct avtab_datum)); | 323 | rc = next_entry(buf32, fp, sizeof(u32)*items2); |
324 | if (rc < 0) { | ||
325 | printk(KERN_ERR "security: avtab: truncated entry\n"); | ||
326 | return -1; | ||
327 | } | ||
328 | items = 0; | ||
289 | 329 | ||
290 | rc = next_entry(buf, fp, sizeof(u32)); | 330 | val = le32_to_cpu(buf32[items++]); |
291 | if (rc < 0) { | 331 | key.source_type = (u16)val; |
292 | printk(KERN_ERR "security: avtab: truncated entry\n"); | 332 | if (key.source_type != val) { |
293 | goto bad; | 333 | printk("security: avtab: truncated source type\n"); |
294 | } | 334 | return -1; |
295 | items2 = le32_to_cpu(buf[0]); | 335 | } |
296 | if (items2 > ARRAY_SIZE(buf)) { | 336 | val = le32_to_cpu(buf32[items++]); |
297 | printk(KERN_ERR "security: avtab: entry overflow\n"); | 337 | key.target_type = (u16)val; |
298 | goto bad; | 338 | if (key.target_type != val) { |
339 | printk("security: avtab: truncated target type\n"); | ||
340 | return -1; | ||
341 | } | ||
342 | val = le32_to_cpu(buf32[items++]); | ||
343 | key.target_class = (u16)val; | ||
344 | if (key.target_class != val) { | ||
345 | printk("security: avtab: truncated target class\n"); | ||
346 | return -1; | ||
347 | } | ||
348 | |||
349 | val = le32_to_cpu(buf32[items++]); | ||
350 | enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0; | ||
351 | |||
352 | if (!(val & (AVTAB_AV | AVTAB_TYPE))) { | ||
353 | printk("security: avtab: null entry\n"); | ||
354 | return -1; | ||
355 | } | ||
356 | if ((val & AVTAB_AV) && | ||
357 | (val & AVTAB_TYPE)) { | ||
358 | printk("security: avtab: entry has both access vectors and types\n"); | ||
359 | return -1; | ||
360 | } | ||
361 | |||
362 | for (i = 0; i < sizeof(spec_order)/sizeof(u16); i++) { | ||
363 | if (val & spec_order[i]) { | ||
364 | key.specified = spec_order[i] | enabled; | ||
365 | datum.data = le32_to_cpu(buf32[items++]); | ||
366 | rc = insertf(a, &key, &datum, p); | ||
367 | if (rc) return rc; | ||
368 | } | ||
369 | } | ||
370 | |||
371 | if (items != items2) { | ||
372 | printk("security: avtab: entry only had %d items, expected %d\n", items2, items); | ||
373 | return -1; | ||
374 | } | ||
375 | return 0; | ||
299 | } | 376 | } |
300 | rc = next_entry(buf, fp, sizeof(u32)*items2); | 377 | |
378 | rc = next_entry(buf16, fp, sizeof(u16)*4); | ||
301 | if (rc < 0) { | 379 | if (rc < 0) { |
302 | printk(KERN_ERR "security: avtab: truncated entry\n"); | 380 | printk("security: avtab: truncated entry\n"); |
303 | goto bad; | 381 | return -1; |
304 | } | 382 | } |
383 | |||
305 | items = 0; | 384 | items = 0; |
306 | avkey->source_type = le32_to_cpu(buf[items++]); | 385 | key.source_type = le16_to_cpu(buf16[items++]); |
307 | avkey->target_type = le32_to_cpu(buf[items++]); | 386 | key.target_type = le16_to_cpu(buf16[items++]); |
308 | avkey->target_class = le32_to_cpu(buf[items++]); | 387 | key.target_class = le16_to_cpu(buf16[items++]); |
309 | avdatum->specified = le32_to_cpu(buf[items++]); | 388 | key.specified = le16_to_cpu(buf16[items++]); |
310 | if (!(avdatum->specified & (AVTAB_AV | AVTAB_TYPE))) { | 389 | |
311 | printk(KERN_ERR "security: avtab: null entry\n"); | 390 | rc = next_entry(buf32, fp, sizeof(u32)); |
312 | goto bad; | 391 | if (rc < 0) { |
313 | } | 392 | printk("security: avtab: truncated entry\n"); |
314 | if ((avdatum->specified & AVTAB_AV) && | 393 | 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 | } | 394 | } |
395 | datum.data = le32_to_cpu(*buf32); | ||
396 | return insertf(a, &key, &datum, p); | ||
397 | } | ||
339 | 398 | ||
340 | return 0; | 399 | static int avtab_insertf(struct avtab *a, struct avtab_key *k, |
341 | bad: | 400 | struct avtab_datum *d, void *p) |
342 | return -1; | 401 | { |
402 | return avtab_insert(a, k, d); | ||
343 | } | 403 | } |
344 | 404 | ||
345 | int avtab_read(struct avtab *a, void *fp, u32 config) | 405 | int avtab_read(struct avtab *a, void *fp, u32 vers) |
346 | { | 406 | { |
347 | int rc; | 407 | int rc; |
348 | struct avtab_key avkey; | 408 | __le32 buf[1]; |
349 | struct avtab_datum avdatum; | ||
350 | u32 buf[1]; | ||
351 | u32 nel, i; | 409 | u32 nel, i; |
352 | 410 | ||
353 | 411 | ||
@@ -363,16 +421,14 @@ int avtab_read(struct avtab *a, void *fp, u32 config) | |||
363 | goto bad; | 421 | goto bad; |
364 | } | 422 | } |
365 | for (i = 0; i < nel; i++) { | 423 | for (i = 0; i < nel; i++) { |
366 | if (avtab_read_item(fp, &avdatum, &avkey)) { | 424 | 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) { | 425 | if (rc) { |
372 | if (rc == -ENOMEM) | 426 | if (rc == -ENOMEM) |
373 | printk(KERN_ERR "security: avtab: out of memory\n"); | 427 | printk(KERN_ERR "security: avtab: out of memory\n"); |
374 | if (rc == -EEXIST) | 428 | else if (rc == -EEXIST) |
375 | printk(KERN_ERR "security: avtab: duplicate entry\n"); | 429 | printk(KERN_ERR "security: avtab: duplicate entry\n"); |
430 | else | ||
431 | rc = -EINVAL; | ||
376 | goto bad; | 432 | goto bad; |
377 | } | 433 | } |
378 | } | 434 | } |