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