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