initial commit with v2.6.9
[linux-2.6.9-moxart.git] / security / selinux / ss / mls.c
blob9f06141509b5a8a38f66589b87a5376b1c1faf61
1 /*
2 * Implementation of the multi-level security (MLS) policy.
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
6 #include <linux/kernel.h>
7 #include <linux/slab.h>
8 #include <linux/string.h>
9 #include <linux/errno.h>
10 #include "mls.h"
11 #include "policydb.h"
12 #include "services.h"
15 * Remove any permissions from `allowed' that are
16 * denied by the MLS policy.
18 void mls_compute_av(struct context *scontext,
19 struct context *tcontext,
20 struct class_datum *tclass,
21 u32 *allowed)
23 unsigned int rel[2];
24 int l;
26 for (l = 0; l < 2; l++)
27 rel[l] = mls_level_relation(scontext->range.level[l],
28 tcontext->range.level[l]);
30 if (rel[1] != MLS_RELATION_EQ) {
31 if (rel[1] != MLS_RELATION_DOM &&
32 !ebitmap_get_bit(&policydb.trustedreaders, scontext->type - 1) &&
33 !ebitmap_get_bit(&policydb.trustedobjects, tcontext->type - 1)) {
34 /* read(s,t) = (s.high >= t.high) = False */
35 *allowed = (*allowed) & ~(tclass->mlsperms.read);
37 if (rel[1] != MLS_RELATION_DOMBY &&
38 !ebitmap_get_bit(&policydb.trustedreaders, tcontext->type - 1) &&
39 !ebitmap_get_bit(&policydb.trustedobjects, scontext->type - 1)) {
40 /* readby(s,t) = read(t,s) = False */
41 *allowed = (*allowed) & ~(tclass->mlsperms.readby);
44 if (((rel[0] != MLS_RELATION_DOMBY && rel[0] != MLS_RELATION_EQ) ||
45 ((!mls_level_eq(tcontext->range.level[0],
46 tcontext->range.level[1])) &&
47 (rel[1] != MLS_RELATION_DOM && rel[1] != MLS_RELATION_EQ))) &&
48 !ebitmap_get_bit(&policydb.trustedwriters, scontext->type - 1) &&
49 !ebitmap_get_bit(&policydb.trustedobjects, tcontext->type - 1)) {
51 * write(s,t) = ((s.low <= t.low = t.high) or (s.low
52 * <= t.low <= t.high <= s.high)) = False
54 *allowed = (*allowed) & ~(tclass->mlsperms.write);
57 if (((rel[0] != MLS_RELATION_DOM && rel[0] != MLS_RELATION_EQ) ||
58 ((!mls_level_eq(scontext->range.level[0],
59 scontext->range.level[1])) &&
60 (rel[1] != MLS_RELATION_DOMBY && rel[1] != MLS_RELATION_EQ))) &&
61 !ebitmap_get_bit(&policydb.trustedwriters, tcontext->type - 1) &&
62 !ebitmap_get_bit(&policydb.trustedobjects, scontext->type - 1)) {
63 /* writeby(s,t) = write(t,s) = False */
64 *allowed = (*allowed) & ~(tclass->mlsperms.writeby);
69 * Return the length in bytes for the MLS fields of the
70 * security context string representation of `context'.
72 int mls_compute_context_len(struct context * context)
74 int i, l, len;
77 len = 0;
78 for (l = 0; l < 2; l++) {
79 len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]) + 1;
81 for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++)
82 if (ebitmap_get_bit(&context->range.level[l].cat, i - 1))
83 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
85 if (mls_level_relation(context->range.level[0], context->range.level[1])
86 == MLS_RELATION_EQ)
87 break;
90 return len;
94 * Write the security context string representation of
95 * the MLS fields of `context' into the string `*scontext'.
96 * Update `*scontext' to point to the end of the MLS fields.
98 int mls_sid_to_context(struct context *context,
99 char **scontext)
101 char *scontextp;
102 int i, l;
104 scontextp = *scontext;
106 for (l = 0; l < 2; l++) {
107 strcpy(scontextp,
108 policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
109 scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
110 *scontextp = ':';
111 scontextp++;
112 for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++)
113 if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
114 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
115 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
116 *scontextp = ',';
117 scontextp++;
119 if (mls_level_relation(context->range.level[0], context->range.level[1])
120 != MLS_RELATION_EQ) {
121 scontextp--;
122 sprintf(scontextp, "-");
123 scontextp++;
125 } else {
126 break;
130 *scontext = scontextp;
131 return 0;
135 * Return 1 if the MLS fields in the security context
136 * structure `c' are valid. Return 0 otherwise.
138 int mls_context_isvalid(struct policydb *p, struct context *c)
140 unsigned int relation;
141 struct level_datum *levdatum;
142 struct user_datum *usrdatum;
143 struct mls_range_list *rnode;
144 int i, l;
147 * MLS range validity checks: high must dominate low, low level must
148 * be valid (category set <-> sensitivity check), and high level must
149 * be valid (category set <-> sensitivity check)
151 relation = mls_level_relation(c->range.level[1],
152 c->range.level[0]);
153 if (!(relation & (MLS_RELATION_DOM | MLS_RELATION_EQ)))
154 /* High does not dominate low. */
155 return 0;
157 for (l = 0; l < 2; l++) {
158 if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
159 return 0;
160 levdatum = hashtab_search(p->p_levels.table,
161 p->p_sens_val_to_name[c->range.level[l].sens - 1]);
162 if (!levdatum)
163 return 0;
165 for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
166 if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
167 if (i > p->p_cats.nprim)
168 return 0;
169 if (!ebitmap_get_bit(&levdatum->level->cat, i - 1))
171 * Category may not be associated with
172 * sensitivity in low level.
174 return 0;
179 if (c->role == OBJECT_R_VAL)
180 return 1;
183 * User must be authorized for the MLS range.
185 if (!c->user || c->user > p->p_users.nprim)
186 return 0;
187 usrdatum = p->user_val_to_struct[c->user - 1];
188 for (rnode = usrdatum->ranges; rnode; rnode = rnode->next) {
189 if (mls_range_contains(rnode->range, c->range))
190 break;
192 if (!rnode)
193 /* user may not be associated with range */
194 return 0;
196 return 1;
201 * Set the MLS fields in the security context structure
202 * `context' based on the string representation in
203 * the string `*scontext'. Update `*scontext' to
204 * point to the end of the string representation of
205 * the MLS fields.
207 * This function modifies the string in place, inserting
208 * NULL characters to terminate the MLS fields.
210 int mls_context_to_sid(char oldc,
211 char **scontext,
212 struct context *context)
215 char delim;
216 char *scontextp, *p;
217 struct level_datum *levdatum;
218 struct cat_datum *catdatum;
219 int l, rc = -EINVAL;
221 if (!oldc) {
222 /* No MLS component to the security context. Try
223 to use a default 'unclassified' value. */
224 levdatum = hashtab_search(policydb.p_levels.table,
225 "unclassified");
226 if (!levdatum)
227 goto out;
228 context->range.level[0].sens = levdatum->level->sens;
229 context->range.level[1].sens = context->range.level[0].sens;
230 rc = 0;
231 goto out;
234 /* Extract low sensitivity. */
235 scontextp = p = *scontext;
236 while (*p && *p != ':' && *p != '-')
237 p++;
239 delim = *p;
240 if (delim != 0)
241 *p++ = 0;
243 for (l = 0; l < 2; l++) {
244 levdatum = hashtab_search(policydb.p_levels.table, scontextp);
245 if (!levdatum)
246 goto out;
248 context->range.level[l].sens = levdatum->level->sens;
250 if (delim == ':') {
251 /* Extract low category set. */
252 while (1) {
253 scontextp = p;
254 while (*p && *p != ',' && *p != '-')
255 p++;
256 delim = *p;
257 if (delim != 0)
258 *p++ = 0;
260 catdatum = hashtab_search(policydb.p_cats.table,
261 scontextp);
262 if (!catdatum)
263 goto out;
265 rc = ebitmap_set_bit(&context->range.level[l].cat,
266 catdatum->value - 1, 1);
267 if (rc)
268 goto out;
269 if (delim != ',')
270 break;
273 if (delim == '-') {
274 /* Extract high sensitivity. */
275 scontextp = p;
276 while (*p && *p != ':')
277 p++;
279 delim = *p;
280 if (delim != 0)
281 *p++ = 0;
282 } else
283 break;
286 if (l == 0) {
287 context->range.level[1].sens = context->range.level[0].sens;
288 rc = ebitmap_cpy(&context->range.level[1].cat,
289 &context->range.level[0].cat);
290 if (rc)
291 goto out;
293 *scontext = ++p;
294 rc = 0;
295 out:
296 return rc;
300 * Copies the MLS range from `src' into `dst'.
302 static inline int mls_copy_context(struct context *dst,
303 struct context *src)
305 int l, rc = 0;
307 /* Copy the MLS range from the source context */
308 for (l = 0; l < 2; l++) {
310 dst->range.level[l].sens = src->range.level[l].sens;
311 rc = ebitmap_cpy(&dst->range.level[l].cat,
312 &src->range.level[l].cat);
313 if (rc)
314 break;
317 return rc;
321 * Convert the MLS fields in the security context
322 * structure `c' from the values specified in the
323 * policy `oldp' to the values specified in the policy `newp'.
325 int mls_convert_context(struct policydb *oldp,
326 struct policydb *newp,
327 struct context *c)
329 struct level_datum *levdatum;
330 struct cat_datum *catdatum;
331 struct ebitmap bitmap;
332 int l, i;
334 for (l = 0; l < 2; l++) {
335 levdatum = hashtab_search(newp->p_levels.table,
336 oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
338 if (!levdatum)
339 return -EINVAL;
340 c->range.level[l].sens = levdatum->level->sens;
342 ebitmap_init(&bitmap);
343 for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
344 if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
345 int rc;
347 catdatum = hashtab_search(newp->p_cats.table,
348 oldp->p_cat_val_to_name[i - 1]);
349 if (!catdatum)
350 return -EINVAL;
351 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
352 if (rc)
353 return rc;
356 ebitmap_destroy(&c->range.level[l].cat);
357 c->range.level[l].cat = bitmap;
360 return 0;
363 int mls_compute_sid(struct context *scontext,
364 struct context *tcontext,
365 u16 tclass,
366 u32 specified,
367 struct context *newcontext)
369 switch (specified) {
370 case AVTAB_TRANSITION:
371 case AVTAB_CHANGE:
372 /* Use the process MLS attributes. */
373 return mls_copy_context(newcontext, scontext);
374 case AVTAB_MEMBER:
375 /* Only polyinstantiate the MLS attributes if
376 the type is being polyinstantiated */
377 if (newcontext->type != tcontext->type) {
378 /* Use the process MLS attributes. */
379 return mls_copy_context(newcontext, scontext);
380 } else {
381 /* Use the related object MLS attributes. */
382 return mls_copy_context(newcontext, tcontext);
384 default:
385 return -EINVAL;
387 return -EINVAL;
390 void mls_user_destroy(struct user_datum *usrdatum)
392 struct mls_range_list *rnode, *rtmp;
393 rnode = usrdatum->ranges;
394 while (rnode) {
395 rtmp = rnode;
396 rnode = rnode->next;
397 ebitmap_destroy(&rtmp->range.level[0].cat);
398 ebitmap_destroy(&rtmp->range.level[1].cat);
399 kfree(rtmp);
403 int mls_read_perm(struct perm_datum *perdatum, void *fp)
405 u32 *buf;
407 buf = next_entry(fp, sizeof(u32));
408 if (!buf)
409 return -EINVAL;
410 perdatum->base_perms = le32_to_cpu(buf[0]);
411 return 0;
415 * Read a MLS level structure from a policydb binary
416 * representation file.
418 struct mls_level *mls_read_level(void *fp)
420 struct mls_level *l;
421 u32 *buf;
423 l = kmalloc(sizeof(*l), GFP_ATOMIC);
424 if (!l) {
425 printk(KERN_ERR "security: mls: out of memory\n");
426 return NULL;
428 memset(l, 0, sizeof(*l));
430 buf = next_entry(fp, sizeof(u32));
431 if (!buf) {
432 printk(KERN_ERR "security: mls: truncated level\n");
433 goto bad;
435 l->sens = cpu_to_le32(buf[0]);
437 if (ebitmap_read(&l->cat, fp)) {
438 printk(KERN_ERR "security: mls: error reading level "
439 "categories\n");
440 goto bad;
442 return l;
444 bad:
445 kfree(l);
446 return NULL;
451 * Read a MLS range structure from a policydb binary
452 * representation file.
454 static int mls_read_range_helper(struct mls_range *r, void *fp)
456 u32 *buf;
457 int items, rc = -EINVAL;
459 buf = next_entry(fp, sizeof(u32));
460 if (!buf)
461 goto out;
463 items = le32_to_cpu(buf[0]);
464 buf = next_entry(fp, sizeof(u32) * items);
465 if (!buf) {
466 printk(KERN_ERR "security: mls: truncated range\n");
467 goto out;
469 r->level[0].sens = le32_to_cpu(buf[0]);
470 if (items > 1) {
471 r->level[1].sens = le32_to_cpu(buf[1]);
472 } else {
473 r->level[1].sens = r->level[0].sens;
476 rc = ebitmap_read(&r->level[0].cat, fp);
477 if (rc) {
478 printk(KERN_ERR "security: mls: error reading low "
479 "categories\n");
480 goto out;
482 if (items > 1) {
483 rc = ebitmap_read(&r->level[1].cat, fp);
484 if (rc) {
485 printk(KERN_ERR "security: mls: error reading high "
486 "categories\n");
487 goto bad_high;
489 } else {
490 rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
491 if (rc) {
492 printk(KERN_ERR "security: mls: out of memory\n");
493 goto bad_high;
497 rc = 0;
498 out:
499 return rc;
500 bad_high:
501 ebitmap_destroy(&r->level[0].cat);
502 goto out;
505 int mls_read_range(struct context *c, void *fp)
507 return mls_read_range_helper(&c->range, fp);
512 * Read a MLS perms structure from a policydb binary
513 * representation file.
515 int mls_read_class(struct class_datum *cladatum, void *fp)
517 struct mls_perms *p = &cladatum->mlsperms;
518 u32 *buf;
520 buf = next_entry(fp, sizeof(u32)*4);
521 if (!buf) {
522 printk(KERN_ERR "security: mls: truncated mls permissions\n");
523 return -EINVAL;
525 p->read = le32_to_cpu(buf[0]);
526 p->readby = le32_to_cpu(buf[1]);
527 p->write = le32_to_cpu(buf[2]);
528 p->writeby = le32_to_cpu(buf[3]);
529 return 0;
532 int mls_read_user(struct user_datum *usrdatum, void *fp)
534 struct mls_range_list *r, *l;
535 int rc = 0;
536 u32 nel, i;
537 u32 *buf;
539 buf = next_entry(fp, sizeof(u32));
540 if (!buf) {
541 rc = -EINVAL;
542 goto out;
544 nel = le32_to_cpu(buf[0]);
545 l = NULL;
546 for (i = 0; i < nel; i++) {
547 r = kmalloc(sizeof(*r), GFP_ATOMIC);
548 if (!r) {
549 rc = -ENOMEM;
550 goto out;
552 memset(r, 0, sizeof(*r));
554 rc = mls_read_range_helper(&r->range, fp);
555 if (rc) {
556 kfree(r);
557 goto out;
560 if (l)
561 l->next = r;
562 else
563 usrdatum->ranges = r;
564 l = r;
566 out:
567 return rc;
570 int mls_read_nlevels(struct policydb *p, void *fp)
572 u32 *buf;
574 buf = next_entry(fp, sizeof(u32));
575 if (!buf)
576 return -EINVAL;
577 p->nlevels = le32_to_cpu(buf[0]);
578 return 0;
581 int mls_read_trusted(struct policydb *p, void *fp)
583 int rc = 0;
585 rc = ebitmap_read(&p->trustedreaders, fp);
586 if (rc)
587 goto out;
588 rc = ebitmap_read(&p->trustedwriters, fp);
589 if (rc)
590 goto bad;
591 rc = ebitmap_read(&p->trustedobjects, fp);
592 if (rc)
593 goto bad2;
594 out:
595 return rc;
596 bad2:
597 ebitmap_destroy(&p->trustedwriters);
598 bad:
599 ebitmap_destroy(&p->trustedreaders);
600 goto out;
603 int sens_index(void *key, void *datum, void *datap)
605 struct policydb *p;
606 struct level_datum *levdatum;
609 levdatum = datum;
610 p = datap;
612 if (!levdatum->isalias)
613 p->p_sens_val_to_name[levdatum->level->sens - 1] = key;
615 return 0;
618 int cat_index(void *key, void *datum, void *datap)
620 struct policydb *p;
621 struct cat_datum *catdatum;
624 catdatum = datum;
625 p = datap;
628 if (!catdatum->isalias)
629 p->p_cat_val_to_name[catdatum->value - 1] = key;
631 return 0;
634 int sens_destroy(void *key, void *datum, void *p)
636 struct level_datum *levdatum;
638 kfree(key);
639 levdatum = datum;
640 if (!levdatum->isalias) {
641 ebitmap_destroy(&levdatum->level->cat);
642 kfree(levdatum->level);
644 kfree(datum);
645 return 0;
648 int cat_destroy(void *key, void *datum, void *p)
650 kfree(key);
651 kfree(datum);
652 return 0;
655 int sens_read(struct policydb *p, struct hashtab *h, void *fp)
657 char *key = NULL;
658 struct level_datum *levdatum;
659 int rc;
660 u32 *buf, len;
662 levdatum = kmalloc(sizeof(*levdatum), GFP_ATOMIC);
663 if (!levdatum) {
664 rc = -ENOMEM;
665 goto out;
667 memset(levdatum, 0, sizeof(*levdatum));
669 buf = next_entry(fp, sizeof(u32)*2);
670 if (!buf) {
671 rc = -EINVAL;
672 goto bad;
675 len = le32_to_cpu(buf[0]);
676 levdatum->isalias = le32_to_cpu(buf[1]);
678 buf = next_entry(fp, len);
679 if (!buf) {
680 rc = -EINVAL;
681 goto bad;
683 key = kmalloc(len + 1,GFP_ATOMIC);
684 if (!key) {
685 rc = -ENOMEM;
686 goto bad;
688 memcpy(key, buf, len);
689 key[len] = 0;
691 levdatum->level = mls_read_level(fp);
692 if (!levdatum->level) {
693 rc = -EINVAL;
694 goto bad;
697 rc = hashtab_insert(h, key, levdatum);
698 if (rc)
699 goto bad;
700 out:
701 return rc;
702 bad:
703 sens_destroy(key, levdatum, NULL);
704 goto out;
708 int cat_read(struct policydb *p, struct hashtab *h, void *fp)
710 char *key = NULL;
711 struct cat_datum *catdatum;
712 int rc;
713 u32 *buf, len;
715 catdatum = kmalloc(sizeof(*catdatum), GFP_ATOMIC);
716 if (!catdatum) {
717 rc = -ENOMEM;
718 goto out;
720 memset(catdatum, 0, sizeof(*catdatum));
722 buf = next_entry(fp, sizeof(u32)*3);
723 if (!buf) {
724 rc = -EINVAL;
725 goto bad;
728 len = le32_to_cpu(buf[0]);
729 catdatum->value = le32_to_cpu(buf[1]);
730 catdatum->isalias = le32_to_cpu(buf[2]);
732 buf = next_entry(fp, len);
733 if (!buf) {
734 rc = -EINVAL;
735 goto bad;
737 key = kmalloc(len + 1,GFP_ATOMIC);
738 if (!key) {
739 rc = -ENOMEM;
740 goto bad;
742 memcpy(key, buf, len);
743 key[len] = 0;
745 rc = hashtab_insert(h, key, catdatum);
746 if (rc)
747 goto bad;
748 out:
749 return rc;
751 bad:
752 cat_destroy(key, catdatum, NULL);
753 goto out;