Merge mulgrave-w:git/linux-2.6
[linux-2.6] / 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 /*
7  * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
8  *
9  *      Support for enhanced MLS infrastructure.
10  *
11  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
12  */
13 /*
14  * Updated: Hewlett-Packard <paul.moore@hp.com>
15  *
16  *      Added support to import/export the MLS label
17  *
18  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
19  */
20
21 #include <linux/kernel.h>
22 #include <linux/slab.h>
23 #include <linux/string.h>
24 #include <linux/errno.h>
25 #include "sidtab.h"
26 #include "mls.h"
27 #include "policydb.h"
28 #include "services.h"
29
30 /*
31  * Return the length in bytes for the MLS fields of the
32  * security context string representation of `context'.
33  */
34 int mls_compute_context_len(struct context * context)
35 {
36         int i, l, len, range;
37         struct ebitmap_node *node;
38
39         if (!selinux_mls_enabled)
40                 return 0;
41
42         len = 1; /* for the beginning ":" */
43         for (l = 0; l < 2; l++) {
44                 range = 0;
45                 len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
46
47                 ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
48                         if (ebitmap_node_get_bit(node, i)) {
49                                 if (range) {
50                                         range++;
51                                         continue;
52                                 }
53
54                                 len += strlen(policydb.p_cat_val_to_name[i]) + 1;
55                                 range++;
56                         } else {
57                                 if (range > 1)
58                                         len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
59                                 range = 0;
60                         }
61                 }
62                 /* Handle case where last category is the end of range */
63                 if (range > 1)
64                         len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
65
66                 if (l == 0) {
67                         if (mls_level_eq(&context->range.level[0],
68                                          &context->range.level[1]))
69                                 break;
70                         else
71                                 len++;
72                 }
73         }
74
75         return len;
76 }
77
78 /*
79  * Write the security context string representation of
80  * the MLS fields of `context' into the string `*scontext'.
81  * Update `*scontext' to point to the end of the MLS fields.
82  */
83 void mls_sid_to_context(struct context *context,
84                         char **scontext)
85 {
86         char *scontextp;
87         int i, l, range, wrote_sep;
88         struct ebitmap_node *node;
89
90         if (!selinux_mls_enabled)
91                 return;
92
93         scontextp = *scontext;
94
95         *scontextp = ':';
96         scontextp++;
97
98         for (l = 0; l < 2; l++) {
99                 range = 0;
100                 wrote_sep = 0;
101                 strcpy(scontextp,
102                        policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
103                 scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
104
105                 /* categories */
106                 ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
107                         if (ebitmap_node_get_bit(node, i)) {
108                                 if (range) {
109                                         range++;
110                                         continue;
111                                 }
112
113                                 if (!wrote_sep) {
114                                         *scontextp++ = ':';
115                                         wrote_sep = 1;
116                                 } else
117                                         *scontextp++ = ',';
118                                 strcpy(scontextp, policydb.p_cat_val_to_name[i]);
119                                 scontextp += strlen(policydb.p_cat_val_to_name[i]);
120                                 range++;
121                         } else {
122                                 if (range > 1) {
123                                         if (range > 2)
124                                                 *scontextp++ = '.';
125                                         else
126                                                 *scontextp++ = ',';
127
128                                         strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
129                                         scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
130                                 }
131                                 range = 0;
132                         }
133                 }
134
135                 /* Handle case where last category is the end of range */
136                 if (range > 1) {
137                         if (range > 2)
138                                 *scontextp++ = '.';
139                         else
140                                 *scontextp++ = ',';
141
142                         strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
143                         scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
144                 }
145
146                 if (l == 0) {
147                         if (mls_level_eq(&context->range.level[0],
148                                          &context->range.level[1]))
149                                 break;
150                         else {
151                                 *scontextp = '-';
152                                 scontextp++;
153                         }
154                 }
155         }
156
157         *scontext = scontextp;
158         return;
159 }
160
161 /*
162  * Return 1 if the MLS fields in the security context
163  * structure `c' are valid.  Return 0 otherwise.
164  */
165 int mls_context_isvalid(struct policydb *p, struct context *c)
166 {
167         struct level_datum *levdatum;
168         struct user_datum *usrdatum;
169         struct ebitmap_node *node;
170         int i, l;
171
172         if (!selinux_mls_enabled)
173                 return 1;
174
175         /*
176          * MLS range validity checks: high must dominate low, low level must
177          * be valid (category set <-> sensitivity check), and high level must
178          * be valid (category set <-> sensitivity check)
179          */
180         if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
181                 /* High does not dominate low. */
182                 return 0;
183
184         for (l = 0; l < 2; l++) {
185                 if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
186                         return 0;
187                 levdatum = hashtab_search(p->p_levels.table,
188                         p->p_sens_val_to_name[c->range.level[l].sens - 1]);
189                 if (!levdatum)
190                         return 0;
191
192                 ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
193                         if (ebitmap_node_get_bit(node, i)) {
194                                 if (i > p->p_cats.nprim)
195                                         return 0;
196                                 if (!ebitmap_get_bit(&levdatum->level->cat, i))
197                                         /*
198                                          * Category may not be associated with
199                                          * sensitivity in low level.
200                                          */
201                                         return 0;
202                         }
203                 }
204         }
205
206         if (c->role == OBJECT_R_VAL)
207                 return 1;
208
209         /*
210          * User must be authorized for the MLS range.
211          */
212         if (!c->user || c->user > p->p_users.nprim)
213                 return 0;
214         usrdatum = p->user_val_to_struct[c->user - 1];
215         if (!mls_range_contains(usrdatum->range, c->range))
216                 return 0; /* user may not be associated with range */
217
218         return 1;
219 }
220
221 /*
222  * Set the MLS fields in the security context structure
223  * `context' based on the string representation in
224  * the string `*scontext'.  Update `*scontext' to
225  * point to the end of the string representation of
226  * the MLS fields.
227  *
228  * This function modifies the string in place, inserting
229  * NULL characters to terminate the MLS fields.
230  *
231  * If a def_sid is provided and no MLS field is present,
232  * copy the MLS field of the associated default context.
233  * Used for upgraded to MLS systems where objects may lack
234  * MLS fields.
235  *
236  * Policy read-lock must be held for sidtab lookup.
237  *
238  */
239 int mls_context_to_sid(char oldc,
240                        char **scontext,
241                        struct context *context,
242                        struct sidtab *s,
243                        u32 def_sid)
244 {
245
246         char delim;
247         char *scontextp, *p, *rngptr;
248         struct level_datum *levdatum;
249         struct cat_datum *catdatum, *rngdatum;
250         int l, rc = -EINVAL;
251
252         if (!selinux_mls_enabled) {
253                 if (def_sid != SECSID_NULL && oldc)
254                         *scontext += strlen(*scontext)+1;
255                 return 0;
256         }
257
258         /*
259          * No MLS component to the security context, try and map to
260          * default if provided.
261          */
262         if (!oldc) {
263                 struct context *defcon;
264
265                 if (def_sid == SECSID_NULL)
266                         goto out;
267
268                 defcon = sidtab_search(s, def_sid);
269                 if (!defcon)
270                         goto out;
271
272                 rc = mls_copy_context(context, defcon);
273                 goto out;
274         }
275
276         /* Extract low sensitivity. */
277         scontextp = p = *scontext;
278         while (*p && *p != ':' && *p != '-')
279                 p++;
280
281         delim = *p;
282         if (delim != 0)
283                 *p++ = 0;
284
285         for (l = 0; l < 2; l++) {
286                 levdatum = hashtab_search(policydb.p_levels.table, scontextp);
287                 if (!levdatum) {
288                         rc = -EINVAL;
289                         goto out;
290                 }
291
292                 context->range.level[l].sens = levdatum->level->sens;
293
294                 if (delim == ':') {
295                         /* Extract category set. */
296                         while (1) {
297                                 scontextp = p;
298                                 while (*p && *p != ',' && *p != '-')
299                                         p++;
300                                 delim = *p;
301                                 if (delim != 0)
302                                         *p++ = 0;
303
304                                 /* Separate into range if exists */
305                                 if ((rngptr = strchr(scontextp, '.')) != NULL) {
306                                         /* Remove '.' */
307                                         *rngptr++ = 0;
308                                 }
309
310                                 catdatum = hashtab_search(policydb.p_cats.table,
311                                                           scontextp);
312                                 if (!catdatum) {
313                                         rc = -EINVAL;
314                                         goto out;
315                                 }
316
317                                 rc = ebitmap_set_bit(&context->range.level[l].cat,
318                                                      catdatum->value - 1, 1);
319                                 if (rc)
320                                         goto out;
321
322                                 /* If range, set all categories in range */
323                                 if (rngptr) {
324                                         int i;
325
326                                         rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
327                                         if (!rngdatum) {
328                                                 rc = -EINVAL;
329                                                 goto out;
330                                         }
331
332                                         if (catdatum->value >= rngdatum->value) {
333                                                 rc = -EINVAL;
334                                                 goto out;
335                                         }
336
337                                         for (i = catdatum->value; i < rngdatum->value; i++) {
338                                                 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
339                                                 if (rc)
340                                                         goto out;
341                                         }
342                                 }
343
344                                 if (delim != ',')
345                                         break;
346                         }
347                 }
348                 if (delim == '-') {
349                         /* Extract high sensitivity. */
350                         scontextp = p;
351                         while (*p && *p != ':')
352                                 p++;
353
354                         delim = *p;
355                         if (delim != 0)
356                                 *p++ = 0;
357                 } else
358                         break;
359         }
360
361         if (l == 0) {
362                 context->range.level[1].sens = context->range.level[0].sens;
363                 rc = ebitmap_cpy(&context->range.level[1].cat,
364                                  &context->range.level[0].cat);
365                 if (rc)
366                         goto out;
367         }
368         *scontext = ++p;
369         rc = 0;
370 out:
371         return rc;
372 }
373
374 /*
375  * Set the MLS fields in the security context structure
376  * `context' based on the string representation in
377  * the string `str'.  This function will allocate temporary memory with the
378  * given constraints of gfp_mask.
379  */
380 int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
381 {
382         char *tmpstr, *freestr;
383         int rc;
384
385         if (!selinux_mls_enabled)
386                 return -EINVAL;
387
388         /* we need freestr because mls_context_to_sid will change
389            the value of tmpstr */
390         tmpstr = freestr = kstrdup(str, gfp_mask);
391         if (!tmpstr) {
392                 rc = -ENOMEM;
393         } else {
394                 rc = mls_context_to_sid(':', &tmpstr, context,
395                                         NULL, SECSID_NULL);
396                 kfree(freestr);
397         }
398
399         return rc;
400 }
401
402 /*
403  * Copies the effective MLS range from `src' into `dst'.
404  */
405 static inline int mls_scopy_context(struct context *dst,
406                                     struct context *src)
407 {
408         int l, rc = 0;
409
410         /* Copy the MLS range from the source context */
411         for (l = 0; l < 2; l++) {
412                 dst->range.level[l].sens = src->range.level[0].sens;
413                 rc = ebitmap_cpy(&dst->range.level[l].cat,
414                                  &src->range.level[0].cat);
415                 if (rc)
416                         break;
417         }
418
419         return rc;
420 }
421
422 /*
423  * Copies the MLS range `range' into `context'.
424  */
425 static inline int mls_range_set(struct context *context,
426                                 struct mls_range *range)
427 {
428         int l, rc = 0;
429
430         /* Copy the MLS range into the  context */
431         for (l = 0; l < 2; l++) {
432                 context->range.level[l].sens = range->level[l].sens;
433                 rc = ebitmap_cpy(&context->range.level[l].cat,
434                                  &range->level[l].cat);
435                 if (rc)
436                         break;
437         }
438
439         return rc;
440 }
441
442 int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
443                          struct context *usercon)
444 {
445         if (selinux_mls_enabled) {
446                 struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
447                 struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
448                 struct mls_level *user_low = &(user->range.level[0]);
449                 struct mls_level *user_clr = &(user->range.level[1]);
450                 struct mls_level *user_def = &(user->dfltlevel);
451                 struct mls_level *usercon_sen = &(usercon->range.level[0]);
452                 struct mls_level *usercon_clr = &(usercon->range.level[1]);
453
454                 /* Honor the user's default level if we can */
455                 if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
456                         *usercon_sen = *user_def;
457                 } else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
458                         *usercon_sen = *fromcon_sen;
459                 } else if (mls_level_between(fromcon_clr, user_low, user_def)) {
460                         *usercon_sen = *user_low;
461                 } else
462                         return -EINVAL;
463
464                 /* Lower the clearance of available contexts
465                    if the clearance of "fromcon" is lower than
466                    that of the user's default clearance (but
467                    only if the "fromcon" clearance dominates
468                    the user's computed sensitivity level) */
469                 if (mls_level_dom(user_clr, fromcon_clr)) {
470                         *usercon_clr = *fromcon_clr;
471                 } else if (mls_level_dom(fromcon_clr, user_clr)) {
472                         *usercon_clr = *user_clr;
473                 } else
474                         return -EINVAL;
475         }
476
477         return 0;
478 }
479
480 /*
481  * Convert the MLS fields in the security context
482  * structure `c' from the values specified in the
483  * policy `oldp' to the values specified in the policy `newp'.
484  */
485 int mls_convert_context(struct policydb *oldp,
486                         struct policydb *newp,
487                         struct context *c)
488 {
489         struct level_datum *levdatum;
490         struct cat_datum *catdatum;
491         struct ebitmap bitmap;
492         struct ebitmap_node *node;
493         int l, i;
494
495         if (!selinux_mls_enabled)
496                 return 0;
497
498         for (l = 0; l < 2; l++) {
499                 levdatum = hashtab_search(newp->p_levels.table,
500                         oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
501
502                 if (!levdatum)
503                         return -EINVAL;
504                 c->range.level[l].sens = levdatum->level->sens;
505
506                 ebitmap_init(&bitmap);
507                 ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
508                         if (ebitmap_node_get_bit(node, i)) {
509                                 int rc;
510
511                                 catdatum = hashtab_search(newp->p_cats.table,
512                                                 oldp->p_cat_val_to_name[i]);
513                                 if (!catdatum)
514                                         return -EINVAL;
515                                 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
516                                 if (rc)
517                                         return rc;
518                         }
519                 }
520                 ebitmap_destroy(&c->range.level[l].cat);
521                 c->range.level[l].cat = bitmap;
522         }
523
524         return 0;
525 }
526
527 int mls_compute_sid(struct context *scontext,
528                     struct context *tcontext,
529                     u16 tclass,
530                     u32 specified,
531                     struct context *newcontext)
532 {
533         if (!selinux_mls_enabled)
534                 return 0;
535
536         switch (specified) {
537         case AVTAB_TRANSITION:
538                 if (tclass == SECCLASS_PROCESS) {
539                         struct range_trans *rangetr;
540                         /* Look for a range transition rule. */
541                         for (rangetr = policydb.range_tr; rangetr;
542                              rangetr = rangetr->next) {
543                                 if (rangetr->dom == scontext->type &&
544                                     rangetr->type == tcontext->type) {
545                                         /* Set the range from the rule */
546                                         return mls_range_set(newcontext,
547                                                              &rangetr->range);
548                                 }
549                         }
550                 }
551                 /* Fallthrough */
552         case AVTAB_CHANGE:
553                 if (tclass == SECCLASS_PROCESS)
554                         /* Use the process MLS attributes. */
555                         return mls_copy_context(newcontext, scontext);
556                 else
557                         /* Use the process effective MLS attributes. */
558                         return mls_scopy_context(newcontext, scontext);
559         case AVTAB_MEMBER:
560                 /* Only polyinstantiate the MLS attributes if
561                    the type is being polyinstantiated */
562                 if (newcontext->type != tcontext->type) {
563                         /* Use the process effective MLS attributes. */
564                         return mls_scopy_context(newcontext, scontext);
565                 } else {
566                         /* Use the related object MLS attributes. */
567                         return mls_copy_context(newcontext, tcontext);
568                 }
569         default:
570                 return -EINVAL;
571         }
572         return -EINVAL;
573 }
574
575 /**
576  * mls_export_lvl - Export the MLS sensitivity levels
577  * @context: the security context
578  * @low: the low sensitivity level
579  * @high: the high sensitivity level
580  *
581  * Description:
582  * Given the security context copy the low MLS sensitivity level into lvl_low
583  * and the high sensitivity level in lvl_high.  The MLS levels are only
584  * exported if the pointers are not NULL, if they are NULL then that level is
585  * not exported.
586  *
587  */
588 void mls_export_lvl(const struct context *context, u32 *low, u32 *high)
589 {
590         if (!selinux_mls_enabled)
591                 return;
592
593         if (low != NULL)
594                 *low = context->range.level[0].sens - 1;
595         if (high != NULL)
596                 *high = context->range.level[1].sens - 1;
597 }
598
599 /**
600  * mls_import_lvl - Import the MLS sensitivity levels
601  * @context: the security context
602  * @low: the low sensitivity level
603  * @high: the high sensitivity level
604  *
605  * Description:
606  * Given the security context and the two sensitivty levels, set the MLS levels
607  * in the context according the two given as parameters.  Returns zero on
608  * success, negative values on failure.
609  *
610  */
611 void mls_import_lvl(struct context *context, u32 low, u32 high)
612 {
613         if (!selinux_mls_enabled)
614                 return;
615
616         context->range.level[0].sens = low + 1;
617         context->range.level[1].sens = high + 1;
618 }
619
620 /**
621  * mls_export_cat - Export the MLS categories
622  * @context: the security context
623  * @low: the low category
624  * @low_len: length of the cat_low bitmap in bytes
625  * @high: the high category
626  * @high_len: length of the cat_high bitmap in bytes
627  *
628  * Description:
629  * Given the security context export the low MLS category bitmap into cat_low
630  * and the high category bitmap into cat_high.  The MLS categories are only
631  * exported if the pointers are not NULL, if they are NULL then that level is
632  * not exported.  The caller is responsibile for freeing the memory when
633  * finished.  Returns zero on success, negative values on failure.
634  *
635  */
636 int mls_export_cat(const struct context *context,
637                    unsigned char **low,
638                    size_t *low_len,
639                    unsigned char **high,
640                    size_t *high_len)
641 {
642         int rc = -EPERM;
643
644         if (!selinux_mls_enabled)
645                 return 0;
646
647         if (low != NULL) {
648                 rc = ebitmap_export(&context->range.level[0].cat,
649                                     low,
650                                     low_len);
651                 if (rc != 0)
652                         goto export_cat_failure;
653         }
654         if (high != NULL) {
655                 rc = ebitmap_export(&context->range.level[1].cat,
656                                     high,
657                                     high_len);
658                 if (rc != 0)
659                         goto export_cat_failure;
660         }
661
662         return 0;
663
664 export_cat_failure:
665         if (low != NULL)
666                 kfree(*low);
667         if (high != NULL)
668                 kfree(*high);
669         return rc;
670 }
671
672 /**
673  * mls_import_cat - Import the MLS categories
674  * @context: the security context
675  * @low: the low category
676  * @low_len: length of the cat_low bitmap in bytes
677  * @high: the high category
678  * @high_len: length of the cat_high bitmap in bytes
679  *
680  * Description:
681  * Given the security context and the two category bitmap strings import the
682  * categories into the security context.  The MLS categories are only imported
683  * if the pointers are not NULL, if they are NULL they are skipped.  Returns
684  * zero on success, negative values on failure.
685  *
686  */
687 int mls_import_cat(struct context *context,
688                    const unsigned char *low,
689                    size_t low_len,
690                    const unsigned char *high,
691                    size_t high_len)
692 {
693         int rc = -EPERM;
694
695         if (!selinux_mls_enabled)
696                 return 0;
697
698         if (low != NULL) {
699                 rc = ebitmap_import(low,
700                                     low_len,
701                                     &context->range.level[0].cat);
702                 if (rc != 0)
703                         goto import_cat_failure;
704         }
705         if (high != NULL) {
706                 if (high == low)
707                         rc = ebitmap_cpy(&context->range.level[1].cat,
708                                          &context->range.level[0].cat);
709                 else
710                         rc = ebitmap_import(high,
711                                             high_len,
712                                             &context->range.level[1].cat);
713                 if (rc != 0)
714                         goto import_cat_failure;
715         }
716
717         return 0;
718
719 import_cat_failure:
720         ebitmap_destroy(&context->range.level[0].cat);
721         ebitmap_destroy(&context->range.level[1].cat);
722         return rc;
723 }