GNU Linux-libre 5.19-rc6-gnu
[releases.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 policydb *p, 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 (!p->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(p, 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(p, SYM_CATS, prev);
60                                         len += strlen(nm) + 1;
61                                 }
62                                 nm = sym_name(p, SYM_CATS, i);
63                                 len += strlen(nm) + 1;
64                                 head = i;
65                         }
66                         prev = i;
67                 }
68                 if (prev != head) {
69                         nm = sym_name(p, 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 policydb *p,
90                         struct context *context,
91                         char **scontext)
92 {
93         char *scontextp, *nm;
94         int i, l, head, prev;
95         struct ebitmap *e;
96         struct ebitmap_node *node;
97
98         if (!p->mls_enabled)
99                 return;
100
101         scontextp = *scontext;
102
103         *scontextp = ':';
104         scontextp++;
105
106         for (l = 0; l < 2; l++) {
107                 strcpy(scontextp, sym_name(p, SYM_LEVELS,
108                                            context->range.level[l].sens - 1));
109                 scontextp += strlen(scontextp);
110
111                 /* categories */
112                 head = -2;
113                 prev = -2;
114                 e = &context->range.level[l].cat;
115                 ebitmap_for_each_positive_bit(e, node, i) {
116                         if (i - prev > 1) {
117                                 /* one or more negative bits are skipped */
118                                 if (prev != head) {
119                                         if (prev - head > 1)
120                                                 *scontextp++ = '.';
121                                         else
122                                                 *scontextp++ = ',';
123                                         nm = sym_name(p, SYM_CATS, prev);
124                                         strcpy(scontextp, nm);
125                                         scontextp += strlen(nm);
126                                 }
127                                 if (prev < 0)
128                                         *scontextp++ = ':';
129                                 else
130                                         *scontextp++ = ',';
131                                 nm = sym_name(p, SYM_CATS, i);
132                                 strcpy(scontextp, nm);
133                                 scontextp += strlen(nm);
134                                 head = i;
135                         }
136                         prev = i;
137                 }
138
139                 if (prev != head) {
140                         if (prev - head > 1)
141                                 *scontextp++ = '.';
142                         else
143                                 *scontextp++ = ',';
144                         nm = sym_name(p, SYM_CATS, prev);
145                         strcpy(scontextp, nm);
146                         scontextp += strlen(nm);
147                 }
148
149                 if (l == 0) {
150                         if (mls_level_eq(&context->range.level[0],
151                                          &context->range.level[1]))
152                                 break;
153                         else
154                                 *scontextp++ = '-';
155                 }
156         }
157
158         *scontext = scontextp;
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 = symtab_search(&p->p_levels,
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'.
221  *
222  * This function modifies the string in place, inserting
223  * NULL characters to terminate the MLS fields.
224  *
225  * If a def_sid is provided and no MLS field is present,
226  * copy the MLS field of the associated default context.
227  * Used for upgraded to MLS systems where objects may lack
228  * MLS fields.
229  *
230  * Policy read-lock must be held for sidtab lookup.
231  *
232  */
233 int mls_context_to_sid(struct policydb *pol,
234                        char oldc,
235                        char *scontext,
236                        struct context *context,
237                        struct sidtab *s,
238                        u32 def_sid)
239 {
240         char *sensitivity, *cur_cat, *next_cat, *rngptr;
241         struct level_datum *levdatum;
242         struct cat_datum *catdatum, *rngdatum;
243         int l, rc, i;
244         char *rangep[2];
245
246         if (!pol->mls_enabled) {
247                 /*
248                  * With no MLS, only return -EINVAL if there is a MLS field
249                  * and it did not come from an xattr.
250                  */
251                 if (oldc && def_sid == SECSID_NULL)
252                         return -EINVAL;
253                 return 0;
254         }
255
256         /*
257          * No MLS component to the security context, try and map to
258          * default if provided.
259          */
260         if (!oldc) {
261                 struct context *defcon;
262
263                 if (def_sid == SECSID_NULL)
264                         return -EINVAL;
265
266                 defcon = sidtab_search(s, def_sid);
267                 if (!defcon)
268                         return -EINVAL;
269
270                 return mls_context_cpy(context, defcon);
271         }
272
273         /*
274          * If we're dealing with a range, figure out where the two parts
275          * of the range begin.
276          */
277         rangep[0] = scontext;
278         rangep[1] = strchr(scontext, '-');
279         if (rangep[1]) {
280                 rangep[1][0] = '\0';
281                 rangep[1]++;
282         }
283
284         /* For each part of the range: */
285         for (l = 0; l < 2; l++) {
286                 /* Split sensitivity and category set. */
287                 sensitivity = rangep[l];
288                 if (sensitivity == NULL)
289                         break;
290                 next_cat = strchr(sensitivity, ':');
291                 if (next_cat)
292                         *(next_cat++) = '\0';
293
294                 /* Parse sensitivity. */
295                 levdatum = symtab_search(&pol->p_levels, sensitivity);
296                 if (!levdatum)
297                         return -EINVAL;
298                 context->range.level[l].sens = levdatum->level->sens;
299
300                 /* Extract category set. */
301                 while (next_cat != NULL) {
302                         cur_cat = next_cat;
303                         next_cat = strchr(next_cat, ',');
304                         if (next_cat != NULL)
305                                 *(next_cat++) = '\0';
306
307                         /* Separate into range if exists */
308                         rngptr = strchr(cur_cat, '.');
309                         if (rngptr != NULL) {
310                                 /* Remove '.' */
311                                 *rngptr++ = '\0';
312                         }
313
314                         catdatum = symtab_search(&pol->p_cats, cur_cat);
315                         if (!catdatum)
316                                 return -EINVAL;
317
318                         rc = ebitmap_set_bit(&context->range.level[l].cat,
319                                              catdatum->value - 1, 1);
320                         if (rc)
321                                 return rc;
322
323                         /* If range, set all categories in range */
324                         if (rngptr == NULL)
325                                 continue;
326
327                         rngdatum = symtab_search(&pol->p_cats, rngptr);
328                         if (!rngdatum)
329                                 return -EINVAL;
330
331                         if (catdatum->value >= rngdatum->value)
332                                 return -EINVAL;
333
334                         for (i = catdatum->value; i < rngdatum->value; i++) {
335                                 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
336                                 if (rc)
337                                         return rc;
338                         }
339                 }
340         }
341
342         /* If we didn't see a '-', the range start is also the range end. */
343         if (rangep[1] == NULL) {
344                 context->range.level[1].sens = context->range.level[0].sens;
345                 rc = ebitmap_cpy(&context->range.level[1].cat,
346                                  &context->range.level[0].cat);
347                 if (rc)
348                         return rc;
349         }
350
351         return 0;
352 }
353
354 /*
355  * Set the MLS fields in the security context structure
356  * `context' based on the string representation in
357  * the string `str'.  This function will allocate temporary memory with the
358  * given constraints of gfp_mask.
359  */
360 int mls_from_string(struct policydb *p, char *str, struct context *context,
361                     gfp_t gfp_mask)
362 {
363         char *tmpstr;
364         int rc;
365
366         if (!p->mls_enabled)
367                 return -EINVAL;
368
369         tmpstr = kstrdup(str, gfp_mask);
370         if (!tmpstr) {
371                 rc = -ENOMEM;
372         } else {
373                 rc = mls_context_to_sid(p, ':', tmpstr, context,
374                                         NULL, SECSID_NULL);
375                 kfree(tmpstr);
376         }
377
378         return rc;
379 }
380
381 /*
382  * Copies the MLS range `range' into `context'.
383  */
384 int mls_range_set(struct context *context,
385                                 struct mls_range *range)
386 {
387         int l, rc = 0;
388
389         /* Copy the MLS range into the  context */
390         for (l = 0; l < 2; l++) {
391                 context->range.level[l].sens = range->level[l].sens;
392                 rc = ebitmap_cpy(&context->range.level[l].cat,
393                                  &range->level[l].cat);
394                 if (rc)
395                         break;
396         }
397
398         return rc;
399 }
400
401 int mls_setup_user_range(struct policydb *p,
402                          struct context *fromcon, struct user_datum *user,
403                          struct context *usercon)
404 {
405         if (p->mls_enabled) {
406                 struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
407                 struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
408                 struct mls_level *user_low = &(user->range.level[0]);
409                 struct mls_level *user_clr = &(user->range.level[1]);
410                 struct mls_level *user_def = &(user->dfltlevel);
411                 struct mls_level *usercon_sen = &(usercon->range.level[0]);
412                 struct mls_level *usercon_clr = &(usercon->range.level[1]);
413
414                 /* Honor the user's default level if we can */
415                 if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
416                         *usercon_sen = *user_def;
417                 else if (mls_level_between(fromcon_sen, user_def, user_clr))
418                         *usercon_sen = *fromcon_sen;
419                 else if (mls_level_between(fromcon_clr, user_low, user_def))
420                         *usercon_sen = *user_low;
421                 else
422                         return -EINVAL;
423
424                 /* Lower the clearance of available contexts
425                    if the clearance of "fromcon" is lower than
426                    that of the user's default clearance (but
427                    only if the "fromcon" clearance dominates
428                    the user's computed sensitivity level) */
429                 if (mls_level_dom(user_clr, fromcon_clr))
430                         *usercon_clr = *fromcon_clr;
431                 else if (mls_level_dom(fromcon_clr, user_clr))
432                         *usercon_clr = *user_clr;
433                 else
434                         return -EINVAL;
435         }
436
437         return 0;
438 }
439
440 /*
441  * Convert the MLS fields in the security context
442  * structure `oldc' from the values specified in the
443  * policy `oldp' to the values specified in the policy `newp',
444  * storing the resulting context in `newc'.
445  */
446 int mls_convert_context(struct policydb *oldp,
447                         struct policydb *newp,
448                         struct context *oldc,
449                         struct context *newc)
450 {
451         struct level_datum *levdatum;
452         struct cat_datum *catdatum;
453         struct ebitmap_node *node;
454         int l, i;
455
456         if (!oldp->mls_enabled || !newp->mls_enabled)
457                 return 0;
458
459         for (l = 0; l < 2; l++) {
460                 char *name = sym_name(oldp, SYM_LEVELS,
461                                       oldc->range.level[l].sens - 1);
462
463                 levdatum = symtab_search(&newp->p_levels, name);
464
465                 if (!levdatum)
466                         return -EINVAL;
467                 newc->range.level[l].sens = levdatum->level->sens;
468
469                 ebitmap_for_each_positive_bit(&oldc->range.level[l].cat,
470                                               node, i) {
471                         int rc;
472
473                         catdatum = symtab_search(&newp->p_cats,
474                                                  sym_name(oldp, SYM_CATS, i));
475                         if (!catdatum)
476                                 return -EINVAL;
477                         rc = ebitmap_set_bit(&newc->range.level[l].cat,
478                                              catdatum->value - 1, 1);
479                         if (rc)
480                                 return rc;
481                 }
482         }
483
484         return 0;
485 }
486
487 int mls_compute_sid(struct policydb *p,
488                     struct context *scontext,
489                     struct context *tcontext,
490                     u16 tclass,
491                     u32 specified,
492                     struct context *newcontext,
493                     bool sock)
494 {
495         struct range_trans rtr;
496         struct mls_range *r;
497         struct class_datum *cladatum;
498         int default_range = 0;
499
500         if (!p->mls_enabled)
501                 return 0;
502
503         switch (specified) {
504         case AVTAB_TRANSITION:
505                 /* Look for a range transition rule. */
506                 rtr.source_type = scontext->type;
507                 rtr.target_type = tcontext->type;
508                 rtr.target_class = tclass;
509                 r = policydb_rangetr_search(p, &rtr);
510                 if (r)
511                         return mls_range_set(newcontext, r);
512
513                 if (tclass && tclass <= p->p_classes.nprim) {
514                         cladatum = p->class_val_to_struct[tclass - 1];
515                         if (cladatum)
516                                 default_range = cladatum->default_range;
517                 }
518
519                 switch (default_range) {
520                 case DEFAULT_SOURCE_LOW:
521                         return mls_context_cpy_low(newcontext, scontext);
522                 case DEFAULT_SOURCE_HIGH:
523                         return mls_context_cpy_high(newcontext, scontext);
524                 case DEFAULT_SOURCE_LOW_HIGH:
525                         return mls_context_cpy(newcontext, scontext);
526                 case DEFAULT_TARGET_LOW:
527                         return mls_context_cpy_low(newcontext, tcontext);
528                 case DEFAULT_TARGET_HIGH:
529                         return mls_context_cpy_high(newcontext, tcontext);
530                 case DEFAULT_TARGET_LOW_HIGH:
531                         return mls_context_cpy(newcontext, tcontext);
532                 case DEFAULT_GLBLUB:
533                         return mls_context_glblub(newcontext,
534                                                   scontext, tcontext);
535                 }
536
537                 fallthrough;
538         case AVTAB_CHANGE:
539                 if ((tclass == p->process_class) || sock)
540                         /* Use the process MLS attributes. */
541                         return mls_context_cpy(newcontext, scontext);
542                 else
543                         /* Use the process effective MLS attributes. */
544                         return mls_context_cpy_low(newcontext, scontext);
545         case AVTAB_MEMBER:
546                 /* Use the process effective MLS attributes. */
547                 return mls_context_cpy_low(newcontext, scontext);
548         }
549         return -EINVAL;
550 }
551
552 #ifdef CONFIG_NETLABEL
553 /**
554  * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
555  * @p: the policy
556  * @context: the security context
557  * @secattr: the NetLabel security attributes
558  *
559  * Description:
560  * Given the security context copy the low MLS sensitivity level into the
561  * NetLabel MLS sensitivity level field.
562  *
563  */
564 void mls_export_netlbl_lvl(struct policydb *p,
565                            struct context *context,
566                            struct netlbl_lsm_secattr *secattr)
567 {
568         if (!p->mls_enabled)
569                 return;
570
571         secattr->attr.mls.lvl = context->range.level[0].sens - 1;
572         secattr->flags |= NETLBL_SECATTR_MLS_LVL;
573 }
574
575 /**
576  * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
577  * @p: the policy
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 policydb *p,
587                            struct context *context,
588                            struct netlbl_lsm_secattr *secattr)
589 {
590         if (!p->mls_enabled)
591                 return;
592
593         context->range.level[0].sens = secattr->attr.mls.lvl + 1;
594         context->range.level[1].sens = context->range.level[0].sens;
595 }
596
597 /**
598  * mls_export_netlbl_cat - Export the MLS categories to NetLabel
599  * @p: the policy
600  * @context: the security context
601  * @secattr: the NetLabel security attributes
602  *
603  * Description:
604  * Given the security context copy the low MLS categories into the NetLabel
605  * MLS category field.  Returns zero on success, negative values on failure.
606  *
607  */
608 int mls_export_netlbl_cat(struct policydb *p,
609                           struct context *context,
610                           struct netlbl_lsm_secattr *secattr)
611 {
612         int rc;
613
614         if (!p->mls_enabled)
615                 return 0;
616
617         rc = ebitmap_netlbl_export(&context->range.level[0].cat,
618                                    &secattr->attr.mls.cat);
619         if (rc == 0 && secattr->attr.mls.cat != NULL)
620                 secattr->flags |= NETLBL_SECATTR_MLS_CAT;
621
622         return rc;
623 }
624
625 /**
626  * mls_import_netlbl_cat - Import the MLS categories from NetLabel
627  * @p: the policy
628  * @context: the security context
629  * @secattr: the NetLabel security attributes
630  *
631  * Description:
632  * Copy the NetLabel security attributes into the SELinux context; since the
633  * NetLabel security attribute only contains a single MLS category use it for
634  * both the low and high categories of the context.  Returns zero on success,
635  * negative values on failure.
636  *
637  */
638 int mls_import_netlbl_cat(struct policydb *p,
639                           struct context *context,
640                           struct netlbl_lsm_secattr *secattr)
641 {
642         int rc;
643
644         if (!p->mls_enabled)
645                 return 0;
646
647         rc = ebitmap_netlbl_import(&context->range.level[0].cat,
648                                    secattr->attr.mls.cat);
649         if (rc)
650                 goto import_netlbl_cat_failure;
651         memcpy(&context->range.level[1].cat, &context->range.level[0].cat,
652                sizeof(context->range.level[0].cat));
653
654         return 0;
655
656 import_netlbl_cat_failure:
657         ebitmap_destroy(&context->range.level[0].cat);
658         return rc;
659 }
660 #endif /* CONFIG_NETLABEL */