patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / security / selinux / ss / mls.c
1 /*
2  * Implementation of the multi-level security (MLS) policy.
3  *
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"
13
14 /*
15  * Remove any permissions from `allowed' that are
16  * denied by the MLS policy.
17  */
18 void mls_compute_av(struct context *scontext,
19                     struct context *tcontext,
20                     struct class_datum *tclass,
21                     u32 *allowed)
22 {
23         unsigned int rel[2];
24         int l;
25
26         for (l = 0; l < 2; l++)
27                 rel[l] = mls_level_relation(scontext->range.level[l],
28                                             tcontext->range.level[l]);
29
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);
36                 }
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);
42                 }
43         }
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)) {
50                 /*
51                  * write(s,t) = ((s.low <= t.low = t.high) or (s.low
52                  * <= t.low <= t.high <= s.high)) = False
53                  */
54                 *allowed = (*allowed) & ~(tclass->mlsperms.write);
55         }
56
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);
65         }
66 }
67
68 /*
69  * Return the length in bytes for the MLS fields of the
70  * security context string representation of `context'.
71  */
72 int mls_compute_context_len(struct context * context)
73 {
74         int i, l, len;
75
76
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;
80
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;
84
85                 if (mls_level_relation(context->range.level[0], context->range.level[1])
86                                 == MLS_RELATION_EQ)
87                         break;
88         }
89
90         return len;
91 }
92
93 /*
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.
97  */
98 int mls_sid_to_context(struct context *context,
99                        char **scontext)
100 {
101         char *scontextp;
102         int i, l;
103
104         scontextp = *scontext;
105
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++;
118                         }
119                 if (mls_level_relation(context->range.level[0], context->range.level[1])
120                                 != MLS_RELATION_EQ) {
121                         scontextp--;
122                         sprintf(scontextp, "-");
123                         scontextp++;
124
125                 } else {
126                         break;
127                 }
128         }
129
130         *scontext = scontextp;
131         return 0;
132 }
133
134 /*
135  * Return 1 if the MLS fields in the security context
136  * structure `c' are valid.  Return 0 otherwise.
137  */
138 int mls_context_isvalid(struct policydb *p, struct context *c)
139 {
140         unsigned int relation;
141         struct level_datum *levdatum;
142         struct user_datum *usrdatum;
143         struct mls_range_list *rnode;
144         int i, l;
145
146         /*
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)
150          */
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;
156
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;
164
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))
170                                         /*
171                                          * Category may not be associated with
172                                          * sensitivity in low level.
173                                          */
174                                         return 0;
175                         }
176                 }
177         }
178
179         if (c->role == OBJECT_R_VAL)
180                 return 1;
181
182         /*
183          * User must be authorized for the MLS range.
184          */
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;
191         }
192         if (!rnode)
193                 /* user may not be associated with range */
194                 return 0;
195
196         return 1;
197 }
198
199
200 /*
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.
206  *
207  * This function modifies the string in place, inserting
208  * NULL characters to terminate the MLS fields.
209  */
210 int mls_context_to_sid(char oldc,
211                        char **scontext,
212                        struct context *context)
213 {
214
215         char delim;
216         char *scontextp, *p;
217         struct level_datum *levdatum;
218         struct cat_datum *catdatum;
219         int l, rc = -EINVAL;
220
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;
232         }
233
234         /* Extract low sensitivity. */
235         scontextp = p = *scontext;
236         while (*p && *p != ':' && *p != '-')
237                 p++;
238
239         delim = *p;
240         if (delim != 0)
241                 *p++ = 0;
242
243         for (l = 0; l < 2; l++) {
244                 levdatum = hashtab_search(policydb.p_levels.table, scontextp);
245                 if (!levdatum)
246                         goto out;
247
248                 context->range.level[l].sens = levdatum->level->sens;
249
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;
259
260                                 catdatum = hashtab_search(policydb.p_cats.table,
261                                                           scontextp);
262                                 if (!catdatum)
263                                         goto out;
264
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;
271                         }
272                 }
273                 if (delim == '-') {
274                         /* Extract high sensitivity. */
275                         scontextp = p;
276                         while (*p && *p != ':')
277                                 p++;
278
279                         delim = *p;
280                         if (delim != 0)
281                                 *p++ = 0;
282                 } else
283                         break;
284         }
285
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;
292         }
293         *scontext = ++p;
294         rc = 0;
295 out:
296         return rc;
297 }
298
299 /*
300  * Copies the MLS range from `src' into `dst'.
301  */
302 static inline int mls_copy_context(struct context *dst,
303                                    struct context *src)
304 {
305         int l, rc = 0;
306
307         /* Copy the MLS range from the source context */
308         for (l = 0; l < 2; l++) {
309
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;
315         }
316
317         return rc;
318 }
319
320 /*
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'.
324  */
325 int mls_convert_context(struct policydb *oldp,
326                         struct policydb *newp,
327                         struct context *c)
328 {
329         struct level_datum *levdatum;
330         struct cat_datum *catdatum;
331         struct ebitmap bitmap;
332         int l, i;
333
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]);
337
338                 if (!levdatum)
339                         return -EINVAL;
340                 c->range.level[l].sens = levdatum->level->sens;
341
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;
346
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;
354                         }
355                 }
356                 ebitmap_destroy(&c->range.level[l].cat);
357                 c->range.level[l].cat = bitmap;
358         }
359
360         return 0;
361 }
362
363 int mls_compute_sid(struct context *scontext,
364                     struct context *tcontext,
365                     u16 tclass,
366                     u32 specified,
367                     struct context *newcontext)
368 {
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);
383                 }
384         default:
385                 return -EINVAL;
386         }
387         return -EINVAL;
388 }
389
390 void mls_user_destroy(struct user_datum *usrdatum)
391 {
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);
400         }
401 }
402
403 int mls_read_perm(struct perm_datum *perdatum, void *fp)
404 {
405         u32 *buf;
406
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;
412 }
413
414 /*
415  * Read a MLS level structure from a policydb binary
416  * representation file.
417  */
418 struct mls_level *mls_read_level(void *fp)
419 {
420         struct mls_level *l;
421         u32 *buf;
422
423         l = kmalloc(sizeof(*l), GFP_ATOMIC);
424         if (!l) {
425                 printk(KERN_ERR "security: mls: out of memory\n");
426                 return NULL;
427         }
428         memset(l, 0, sizeof(*l));
429
430         buf = next_entry(fp, sizeof(u32));
431         if (!buf) {
432                 printk(KERN_ERR "security: mls: truncated level\n");
433                 goto bad;
434         }
435         l->sens = cpu_to_le32(buf[0]);
436
437         if (ebitmap_read(&l->cat, fp)) {
438                 printk(KERN_ERR "security: mls:  error reading level "
439                        "categories\n");
440                 goto bad;
441         }
442         return l;
443
444 bad:
445         kfree(l);
446         return NULL;
447 }
448
449
450 /*
451  * Read a MLS range structure from a policydb binary
452  * representation file.
453  */
454 static int mls_read_range_helper(struct mls_range *r, void *fp)
455 {
456         u32 *buf;
457         int items, rc = -EINVAL;
458
459         buf = next_entry(fp, sizeof(u32));
460         if (!buf)
461                 goto out;
462
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;
468         }
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;
474         }
475
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;
481         }
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;
488                 }
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;
494                 }
495         }
496
497         rc = 0;
498 out:
499         return rc;
500 bad_high:
501         ebitmap_destroy(&r->level[0].cat);
502         goto out;
503 }
504
505 int mls_read_range(struct context *c, void *fp)
506 {
507         return mls_read_range_helper(&c->range, fp);
508 }
509
510
511 /*
512  * Read a MLS perms structure from a policydb binary
513  * representation file.
514  */
515 int mls_read_class(struct class_datum *cladatum, void *fp)
516 {
517         struct mls_perms *p = &cladatum->mlsperms;
518         u32 *buf;
519
520         buf = next_entry(fp, sizeof(u32)*4);
521         if (!buf) {
522                 printk(KERN_ERR "security: mls:  truncated mls permissions\n");
523                 return -EINVAL;
524         }
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;
530 }
531
532 int mls_read_user(struct user_datum *usrdatum, void *fp)
533 {
534         struct mls_range_list *r, *l;
535         int rc = 0;
536         u32 nel, i;
537         u32 *buf;
538
539         buf = next_entry(fp, sizeof(u32));
540         if (!buf) {
541                 rc = -EINVAL;
542                 goto out;
543         }
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;
551                 }
552                 memset(r, 0, sizeof(*r));
553
554                 rc = mls_read_range_helper(&r->range, fp);
555                 if (rc) {
556                         kfree(r);
557                         goto out;
558                 }
559
560                 if (l)
561                         l->next = r;
562                 else
563                         usrdatum->ranges = r;
564                 l = r;
565         }
566 out:
567         return rc;
568 }
569
570 int mls_read_nlevels(struct policydb *p, void *fp)
571 {
572         u32 *buf;
573
574         buf = next_entry(fp, sizeof(u32));
575         if (!buf)
576                 return -EINVAL;
577         p->nlevels = le32_to_cpu(buf[0]);
578         return 0;
579 }
580
581 int mls_read_trusted(struct policydb *p, void *fp)
582 {
583         int rc = 0;
584
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;
601 }
602
603 int sens_index(void *key, void *datum, void *datap)
604 {
605         struct policydb *p;
606         struct level_datum *levdatum;
607
608
609         levdatum = datum;
610         p = datap;
611
612         if (!levdatum->isalias)
613                 p->p_sens_val_to_name[levdatum->level->sens - 1] = key;
614
615         return 0;
616 }
617
618 int cat_index(void *key, void *datum, void *datap)
619 {
620         struct policydb *p;
621         struct cat_datum *catdatum;
622
623
624         catdatum = datum;
625         p = datap;
626
627
628         if (!catdatum->isalias)
629                 p->p_cat_val_to_name[catdatum->value - 1] = key;
630
631         return 0;
632 }
633
634 int sens_destroy(void *key, void *datum, void *p)
635 {
636         struct level_datum *levdatum;
637
638         kfree(key);
639         levdatum = datum;
640         if (!levdatum->isalias) {
641                 ebitmap_destroy(&levdatum->level->cat);
642                 kfree(levdatum->level);
643         }
644         kfree(datum);
645         return 0;
646 }
647
648 int cat_destroy(void *key, void *datum, void *p)
649 {
650         kfree(key);
651         kfree(datum);
652         return 0;
653 }
654
655 int sens_read(struct policydb *p, struct hashtab *h, void *fp)
656 {
657         char *key = 0;
658         struct level_datum *levdatum;
659         int rc;
660         u32 *buf, len;
661
662         levdatum = kmalloc(sizeof(*levdatum), GFP_ATOMIC);
663         if (!levdatum) {
664                 rc = -ENOMEM;
665                 goto out;
666         }
667         memset(levdatum, 0, sizeof(*levdatum));
668
669         buf = next_entry(fp, sizeof(u32)*2);
670         if (!buf) {
671                 rc = -EINVAL;
672                 goto bad;
673         }
674
675         len = le32_to_cpu(buf[0]);
676         levdatum->isalias = le32_to_cpu(buf[1]);
677
678         buf = next_entry(fp, len);
679         if (!buf) {
680                 rc = -EINVAL;
681                 goto bad;
682         }
683         key = kmalloc(len + 1,GFP_ATOMIC);
684         if (!key) {
685                 rc = -ENOMEM;
686                 goto bad;
687         }
688         memcpy(key, buf, len);
689         key[len] = 0;
690
691         levdatum->level = mls_read_level(fp);
692         if (!levdatum->level) {
693                 rc = -EINVAL;
694                 goto bad;
695         }
696
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;
705 }
706
707
708 int cat_read(struct policydb *p, struct hashtab *h, void *fp)
709 {
710         char *key = 0;
711         struct cat_datum *catdatum;
712         int rc;
713         u32 *buf, len;
714
715         catdatum = kmalloc(sizeof(*catdatum), GFP_ATOMIC);
716         if (!catdatum) {
717                 rc = -ENOMEM;
718                 goto out;
719         }
720         memset(catdatum, 0, sizeof(*catdatum));
721
722         buf = next_entry(fp, sizeof(u32)*3);
723         if (!buf) {
724                 rc = -EINVAL;
725                 goto bad;
726         }
727
728         len = le32_to_cpu(buf[0]);
729         catdatum->value = le32_to_cpu(buf[1]);
730         catdatum->isalias = le32_to_cpu(buf[2]);
731
732         buf = next_entry(fp, len);
733         if (!buf) {
734                 rc = -EINVAL;
735                 goto bad;
736         }
737         key = kmalloc(len + 1,GFP_ATOMIC);
738         if (!key) {
739                 rc = -ENOMEM;
740                 goto bad;
741         }
742         memcpy(key, buf, len);
743         key[len] = 0;
744
745         rc = hashtab_insert(h, key, catdatum);
746         if (rc)
747                 goto bad;
748 out:
749         return rc;
750
751 bad:
752         cat_destroy(key, catdatum, NULL);
753         goto out;
754 }