vserver 1.9.5.x5
[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[1];
406         int rc;
407
408         rc = next_entry(buf, fp, sizeof buf);
409         if (rc < 0)
410                 return -EINVAL;
411         perdatum->base_perms = le32_to_cpu(buf[0]);
412         return 0;
413 }
414
415 /*
416  * Read a MLS level structure from a policydb binary
417  * representation file.
418  */
419 struct mls_level *mls_read_level(void *fp)
420 {
421         struct mls_level *l;
422         u32 buf[1];
423         int rc;
424
425         l = kmalloc(sizeof(*l), GFP_ATOMIC);
426         if (!l) {
427                 printk(KERN_ERR "security: mls: out of memory\n");
428                 return NULL;
429         }
430         memset(l, 0, sizeof(*l));
431
432         rc = next_entry(buf, fp, sizeof buf);
433         if (rc < 0) {
434                 printk(KERN_ERR "security: mls: truncated level\n");
435                 goto bad;
436         }
437         l->sens = cpu_to_le32(buf[0]);
438
439         if (ebitmap_read(&l->cat, fp)) {
440                 printk(KERN_ERR "security: mls:  error reading level "
441                        "categories\n");
442                 goto bad;
443         }
444         return l;
445
446 bad:
447         kfree(l);
448         return NULL;
449 }
450
451
452 /*
453  * Read a MLS range structure from a policydb binary
454  * representation file.
455  */
456 static int mls_read_range_helper(struct mls_range *r, void *fp)
457 {
458         u32 buf[2], items;
459         int rc;
460
461         rc = next_entry(buf, fp, sizeof(u32));
462         if (rc < 0)
463                 goto out;
464
465         items = le32_to_cpu(buf[0]);
466         if (items > ARRAY_SIZE(buf)) {
467                 printk(KERN_ERR "security: mls:  range overflow\n");
468                 rc = -EINVAL;
469                 goto out;
470         }
471         rc = next_entry(buf, fp, sizeof(u32) * items);
472         if (rc < 0) {
473                 printk(KERN_ERR "security: mls:  truncated range\n");
474                 goto out;
475         }
476         r->level[0].sens = le32_to_cpu(buf[0]);
477         if (items > 1) {
478                 r->level[1].sens = le32_to_cpu(buf[1]);
479         } else {
480                 r->level[1].sens = r->level[0].sens;
481         }
482
483         rc = ebitmap_read(&r->level[0].cat, fp);
484         if (rc) {
485                 printk(KERN_ERR "security: mls:  error reading low "
486                        "categories\n");
487                 goto out;
488         }
489         if (items > 1) {
490                 rc = ebitmap_read(&r->level[1].cat, fp);
491                 if (rc) {
492                         printk(KERN_ERR "security: mls:  error reading high "
493                                "categories\n");
494                         goto bad_high;
495                 }
496         } else {
497                 rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
498                 if (rc) {
499                         printk(KERN_ERR "security: mls:  out of memory\n");
500                         goto bad_high;
501                 }
502         }
503
504         rc = 0;
505 out:
506         return rc;
507 bad_high:
508         ebitmap_destroy(&r->level[0].cat);
509         goto out;
510 }
511
512 int mls_read_range(struct context *c, void *fp)
513 {
514         return mls_read_range_helper(&c->range, fp);
515 }
516
517
518 /*
519  * Read a MLS perms structure from a policydb binary
520  * representation file.
521  */
522 int mls_read_class(struct class_datum *cladatum, void *fp)
523 {
524         struct mls_perms *p = &cladatum->mlsperms;
525         u32 buf[4];
526         int rc;
527
528         rc = next_entry(buf, fp, sizeof buf);
529         if (rc < 0) {
530                 printk(KERN_ERR "security: mls:  truncated mls permissions\n");
531                 return -EINVAL;
532         }
533         p->read = le32_to_cpu(buf[0]);
534         p->readby = le32_to_cpu(buf[1]);
535         p->write = le32_to_cpu(buf[2]);
536         p->writeby = le32_to_cpu(buf[3]);
537         return 0;
538 }
539
540 int mls_read_user(struct user_datum *usrdatum, void *fp)
541 {
542         struct mls_range_list *r, *l;
543         int rc;
544         u32 nel, i;
545         u32 buf[1];
546
547         rc = next_entry(buf, fp, sizeof buf);
548         if (rc < 0)
549                 goto out;
550         nel = le32_to_cpu(buf[0]);
551         l = NULL;
552         for (i = 0; i < nel; i++) {
553                 r = kmalloc(sizeof(*r), GFP_ATOMIC);
554                 if (!r) {
555                         rc = -ENOMEM;
556                         goto out;
557                 }
558                 memset(r, 0, sizeof(*r));
559
560                 rc = mls_read_range_helper(&r->range, fp);
561                 if (rc) {
562                         kfree(r);
563                         goto out;
564                 }
565
566                 if (l)
567                         l->next = r;
568                 else
569                         usrdatum->ranges = r;
570                 l = r;
571         }
572 out:
573         return rc;
574 }
575
576 int mls_read_nlevels(struct policydb *p, void *fp)
577 {
578         u32 buf[1];
579         int rc;
580
581         rc = next_entry(buf, fp, sizeof buf);
582         if (rc < 0)
583                 return -EINVAL;
584         p->nlevels = le32_to_cpu(buf[0]);
585         return 0;
586 }
587
588 int mls_read_trusted(struct policydb *p, void *fp)
589 {
590         int rc = 0;
591
592         rc = ebitmap_read(&p->trustedreaders, fp);
593         if (rc)
594                 goto out;
595         rc = ebitmap_read(&p->trustedwriters, fp);
596         if (rc)
597                 goto bad;
598         rc = ebitmap_read(&p->trustedobjects, fp);
599         if (rc)
600                 goto bad2;
601 out:
602         return rc;
603 bad2:
604         ebitmap_destroy(&p->trustedwriters);
605 bad:
606         ebitmap_destroy(&p->trustedreaders);
607         goto out;
608 }
609
610 int sens_index(void *key, void *datum, void *datap)
611 {
612         struct policydb *p;
613         struct level_datum *levdatum;
614
615
616         levdatum = datum;
617         p = datap;
618
619         if (!levdatum->isalias)
620                 p->p_sens_val_to_name[levdatum->level->sens - 1] = key;
621
622         return 0;
623 }
624
625 int cat_index(void *key, void *datum, void *datap)
626 {
627         struct policydb *p;
628         struct cat_datum *catdatum;
629
630
631         catdatum = datum;
632         p = datap;
633
634
635         if (!catdatum->isalias)
636                 p->p_cat_val_to_name[catdatum->value - 1] = key;
637
638         return 0;
639 }
640
641 int sens_destroy(void *key, void *datum, void *p)
642 {
643         struct level_datum *levdatum;
644
645         kfree(key);
646         levdatum = datum;
647         if (!levdatum->isalias) {
648                 ebitmap_destroy(&levdatum->level->cat);
649                 kfree(levdatum->level);
650         }
651         kfree(datum);
652         return 0;
653 }
654
655 int cat_destroy(void *key, void *datum, void *p)
656 {
657         kfree(key);
658         kfree(datum);
659         return 0;
660 }
661
662 int sens_read(struct policydb *p, struct hashtab *h, void *fp)
663 {
664         char *key = NULL;
665         struct level_datum *levdatum;
666         int rc;
667         u32 buf[2], len;
668
669         levdatum = kmalloc(sizeof(*levdatum), GFP_ATOMIC);
670         if (!levdatum) {
671                 rc = -ENOMEM;
672                 goto out;
673         }
674         memset(levdatum, 0, sizeof(*levdatum));
675
676         rc = next_entry(buf, fp, sizeof buf);
677         if (rc < 0)
678                 goto bad;
679
680         len = le32_to_cpu(buf[0]);
681         levdatum->isalias = le32_to_cpu(buf[1]);
682
683         key = kmalloc(len + 1,GFP_ATOMIC);
684         if (!key) {
685                 rc = -ENOMEM;
686                 goto bad;
687         }
688         rc = next_entry(key, fp, len);
689         if (rc < 0)
690                 goto bad;
691         key[len] = 0;
692
693         levdatum->level = mls_read_level(fp);
694         if (!levdatum->level) {
695                 rc = -EINVAL;
696                 goto bad;
697         }
698
699         rc = hashtab_insert(h, key, levdatum);
700         if (rc)
701                 goto bad;
702 out:
703         return rc;
704 bad:
705         sens_destroy(key, levdatum, NULL);
706         goto out;
707 }
708
709
710 int cat_read(struct policydb *p, struct hashtab *h, void *fp)
711 {
712         char *key = NULL;
713         struct cat_datum *catdatum;
714         int rc;
715         u32 buf[3], len;
716
717         catdatum = kmalloc(sizeof(*catdatum), GFP_ATOMIC);
718         if (!catdatum) {
719                 rc = -ENOMEM;
720                 goto out;
721         }
722         memset(catdatum, 0, sizeof(*catdatum));
723
724         rc = next_entry(buf, fp, sizeof buf);
725         if (rc < 0)
726                 goto bad;
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         key = kmalloc(len + 1,GFP_ATOMIC);
733         if (!key) {
734                 rc = -ENOMEM;
735                 goto bad;
736         }
737         rc = next_entry(key, fp, len);
738         if (rc < 0)
739                 goto bad;
740         key[len] = 0;
741
742         rc = hashtab_insert(h, key, catdatum);
743         if (rc)
744                 goto bad;
745 out:
746         return rc;
747
748 bad:
749         cat_destroy(key, catdatum, NULL);
750         goto out;
751 }