]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - security/selinux/ss/mls.c
NetLabel: convert to an extensibile/sparse category bitmap
[linux-2.6-omap-h63xx.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_copy_context(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 effective MLS range from `src' into `dst'.
405  */
406 static inline int mls_scopy_context(struct context *dst,
407                                     struct context *src)
408 {
409         int l, rc = 0;
410
411         /* Copy the MLS range from the source context */
412         for (l = 0; l < 2; l++) {
413                 dst->range.level[l].sens = src->range.level[0].sens;
414                 rc = ebitmap_cpy(&dst->range.level[l].cat,
415                                  &src->range.level[0].cat);
416                 if (rc)
417                         break;
418         }
419
420         return rc;
421 }
422
423 /*
424  * Copies the MLS range `range' into `context'.
425  */
426 static inline int mls_range_set(struct context *context,
427                                 struct mls_range *range)
428 {
429         int l, rc = 0;
430
431         /* Copy the MLS range into the  context */
432         for (l = 0; l < 2; l++) {
433                 context->range.level[l].sens = range->level[l].sens;
434                 rc = ebitmap_cpy(&context->range.level[l].cat,
435                                  &range->level[l].cat);
436                 if (rc)
437                         break;
438         }
439
440         return rc;
441 }
442
443 int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
444                          struct context *usercon)
445 {
446         if (selinux_mls_enabled) {
447                 struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
448                 struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
449                 struct mls_level *user_low = &(user->range.level[0]);
450                 struct mls_level *user_clr = &(user->range.level[1]);
451                 struct mls_level *user_def = &(user->dfltlevel);
452                 struct mls_level *usercon_sen = &(usercon->range.level[0]);
453                 struct mls_level *usercon_clr = &(usercon->range.level[1]);
454
455                 /* Honor the user's default level if we can */
456                 if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
457                         *usercon_sen = *user_def;
458                 } else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
459                         *usercon_sen = *fromcon_sen;
460                 } else if (mls_level_between(fromcon_clr, user_low, user_def)) {
461                         *usercon_sen = *user_low;
462                 } else
463                         return -EINVAL;
464
465                 /* Lower the clearance of available contexts
466                    if the clearance of "fromcon" is lower than
467                    that of the user's default clearance (but
468                    only if the "fromcon" clearance dominates
469                    the user's computed sensitivity level) */
470                 if (mls_level_dom(user_clr, fromcon_clr)) {
471                         *usercon_clr = *fromcon_clr;
472                 } else if (mls_level_dom(fromcon_clr, user_clr)) {
473                         *usercon_clr = *user_clr;
474                 } else
475                         return -EINVAL;
476         }
477
478         return 0;
479 }
480
481 /*
482  * Convert the MLS fields in the security context
483  * structure `c' from the values specified in the
484  * policy `oldp' to the values specified in the policy `newp'.
485  */
486 int mls_convert_context(struct policydb *oldp,
487                         struct policydb *newp,
488                         struct context *c)
489 {
490         struct level_datum *levdatum;
491         struct cat_datum *catdatum;
492         struct ebitmap bitmap;
493         struct ebitmap_node *node;
494         int l, i;
495
496         if (!selinux_mls_enabled)
497                 return 0;
498
499         for (l = 0; l < 2; l++) {
500                 levdatum = hashtab_search(newp->p_levels.table,
501                         oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
502
503                 if (!levdatum)
504                         return -EINVAL;
505                 c->range.level[l].sens = levdatum->level->sens;
506
507                 ebitmap_init(&bitmap);
508                 ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
509                         if (ebitmap_node_get_bit(node, i)) {
510                                 int rc;
511
512                                 catdatum = hashtab_search(newp->p_cats.table,
513                                                 oldp->p_cat_val_to_name[i]);
514                                 if (!catdatum)
515                                         return -EINVAL;
516                                 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
517                                 if (rc)
518                                         return rc;
519                         }
520                 }
521                 ebitmap_destroy(&c->range.level[l].cat);
522                 c->range.level[l].cat = bitmap;
523         }
524
525         return 0;
526 }
527
528 int mls_compute_sid(struct context *scontext,
529                     struct context *tcontext,
530                     u16 tclass,
531                     u32 specified,
532                     struct context *newcontext)
533 {
534         struct range_trans *rtr;
535
536         if (!selinux_mls_enabled)
537                 return 0;
538
539         switch (specified) {
540         case AVTAB_TRANSITION:
541                 /* Look for a range transition rule. */
542                 for (rtr = policydb.range_tr; rtr; rtr = rtr->next) {
543                         if (rtr->source_type == scontext->type &&
544                             rtr->target_type == tcontext->type &&
545                             rtr->target_class == tclass) {
546                                 /* Set the range from the rule */
547                                 return mls_range_set(newcontext,
548                                                      &rtr->target_range);
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 #ifdef CONFIG_NETLABEL
576 /**
577  * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
578  * @context: the security context
579  * @secattr: the NetLabel security attributes
580  *
581  * Description:
582  * Given the security context copy the low MLS sensitivity level into the
583  * NetLabel MLS sensitivity level field.
584  *
585  */
586 void mls_export_netlbl_lvl(struct context *context,
587                            struct netlbl_lsm_secattr *secattr)
588 {
589         if (!selinux_mls_enabled)
590                 return;
591
592         secattr->mls_lvl = context->range.level[0].sens - 1;
593         secattr->flags |= NETLBL_SECATTR_MLS_LVL;
594 }
595
596 /**
597  * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
598  * @context: the security context
599  * @secattr: the NetLabel security attributes
600  *
601  * Description:
602  * Given the security context and the NetLabel security attributes, copy the
603  * NetLabel MLS sensitivity level into the context.
604  *
605  */
606 void mls_import_netlbl_lvl(struct context *context,
607                            struct netlbl_lsm_secattr *secattr)
608 {
609         if (!selinux_mls_enabled)
610                 return;
611
612         context->range.level[0].sens = secattr->mls_lvl + 1;
613         context->range.level[1].sens = context->range.level[0].sens;
614 }
615
616 /**
617  * mls_export_netlbl_cat - Export the MLS categories to NetLabel
618  * @context: the security context
619  * @secattr: the NetLabel security attributes
620  *
621  * Description:
622  * Given the security context copy the low MLS categories into the NetLabel
623  * MLS category field.  Returns zero on success, negative values on failure.
624  *
625  */
626 int mls_export_netlbl_cat(struct context *context,
627                           struct netlbl_lsm_secattr *secattr)
628 {
629         int rc;
630
631         if (!selinux_mls_enabled)
632                 return 0;
633
634         rc = ebitmap_netlbl_export(&context->range.level[0].cat,
635                                    &secattr->mls_cat);
636         if (rc == 0 && secattr->mls_cat != NULL)
637                 secattr->flags |= NETLBL_SECATTR_MLS_CAT;
638
639         return rc;
640 }
641
642 /**
643  * mls_import_netlbl_cat - Import the MLS categories from NetLabel
644  * @context: the security context
645  * @secattr: the NetLabel security attributes
646  *
647  * Description:
648  * Copy the NetLabel security attributes into the SELinux context; since the
649  * NetLabel security attribute only contains a single MLS category use it for
650  * both the low and high categories of the context.  Returns zero on success,
651  * negative values on failure.
652  *
653  */
654 int mls_import_netlbl_cat(struct context *context,
655                           struct netlbl_lsm_secattr *secattr)
656 {
657         int rc;
658
659         if (!selinux_mls_enabled)
660                 return 0;
661
662         rc = ebitmap_netlbl_import(&context->range.level[0].cat,
663                                    secattr->mls_cat);
664         if (rc != 0)
665                 goto import_netlbl_cat_failure;
666
667         rc = ebitmap_cpy(&context->range.level[1].cat,
668                          &context->range.level[0].cat);
669         if (rc != 0)
670                 goto import_netlbl_cat_failure;
671
672         return 0;
673
674 import_netlbl_cat_failure:
675         ebitmap_destroy(&context->range.level[0].cat);
676         ebitmap_destroy(&context->range.level[1].cat);
677         return rc;
678 }
679 #endif /* CONFIG_NETLABEL */