Merge tag 'pinctrl-v4.20-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[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 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         return;
160 }
161
162 int mls_level_isvalid(struct policydb *p, struct mls_level *l)
163 {
164         struct level_datum *levdatum;
165
166         if (!l->sens || l->sens > p->p_levels.nprim)
167                 return 0;
168         levdatum = hashtab_search(p->p_levels.table,
169                                   sym_name(p, SYM_LEVELS, l->sens - 1));
170         if (!levdatum)
171                 return 0;
172
173         /*
174          * Return 1 iff all the bits set in l->cat are also be set in
175          * levdatum->level->cat and no bit in l->cat is larger than
176          * p->p_cats.nprim.
177          */
178         return ebitmap_contains(&levdatum->level->cat, &l->cat,
179                                 p->p_cats.nprim);
180 }
181
182 int mls_range_isvalid(struct policydb *p, struct mls_range *r)
183 {
184         return (mls_level_isvalid(p, &r->level[0]) &&
185                 mls_level_isvalid(p, &r->level[1]) &&
186                 mls_level_dom(&r->level[1], &r->level[0]));
187 }
188
189 /*
190  * Return 1 if the MLS fields in the security context
191  * structure `c' are valid.  Return 0 otherwise.
192  */
193 int mls_context_isvalid(struct policydb *p, struct context *c)
194 {
195         struct user_datum *usrdatum;
196
197         if (!p->mls_enabled)
198                 return 1;
199
200         if (!mls_range_isvalid(p, &c->range))
201                 return 0;
202
203         if (c->role == OBJECT_R_VAL)
204                 return 1;
205
206         /*
207          * User must be authorized for the MLS range.
208          */
209         if (!c->user || c->user > p->p_users.nprim)
210                 return 0;
211         usrdatum = p->user_val_to_struct[c->user - 1];
212         if (!mls_range_contains(usrdatum->range, c->range))
213                 return 0; /* user may not be associated with range */
214
215         return 1;
216 }
217
218 /*
219  * Set the MLS fields in the security context structure
220  * `context' based on the string representation in
221  * the string `scontext'.
222  *
223  * This function modifies the string in place, inserting
224  * NULL characters to terminate the MLS fields.
225  *
226  * If a def_sid is provided and no MLS field is present,
227  * copy the MLS field of the associated default context.
228  * Used for upgraded to MLS systems where objects may lack
229  * MLS fields.
230  *
231  * Policy read-lock must be held for sidtab lookup.
232  *
233  */
234 int mls_context_to_sid(struct policydb *pol,
235                        char oldc,
236                        char *scontext,
237                        struct context *context,
238                        struct sidtab *s,
239                        u32 def_sid)
240 {
241         char *sensitivity, *cur_cat, *next_cat, *rngptr;
242         struct level_datum *levdatum;
243         struct cat_datum *catdatum, *rngdatum;
244         int l, rc, i;
245         char *rangep[2];
246
247         if (!pol->mls_enabled) {
248                 if ((def_sid != SECSID_NULL && oldc) || (*scontext) == '\0')
249                         return 0;
250                 return -EINVAL;
251         }
252
253         /*
254          * No MLS component to the security context, try and map to
255          * default if provided.
256          */
257         if (!oldc) {
258                 struct context *defcon;
259
260                 if (def_sid == SECSID_NULL)
261                         return -EINVAL;
262
263                 defcon = sidtab_search(s, def_sid);
264                 if (!defcon)
265                         return -EINVAL;
266
267                 return mls_context_cpy(context, defcon);
268         }
269
270         /*
271          * If we're dealing with a range, figure out where the two parts
272          * of the range begin.
273          */
274         rangep[0] = scontext;
275         rangep[1] = strchr(scontext, '-');
276         if (rangep[1]) {
277                 rangep[1][0] = '\0';
278                 rangep[1]++;
279         }
280
281         /* For each part of the range: */
282         for (l = 0; l < 2; l++) {
283                 /* Split sensitivity and category set. */
284                 sensitivity = rangep[l];
285                 if (sensitivity == NULL)
286                         break;
287                 next_cat = strchr(sensitivity, ':');
288                 if (next_cat)
289                         *(next_cat++) = '\0';
290
291                 /* Parse sensitivity. */
292                 levdatum = hashtab_search(pol->p_levels.table, sensitivity);
293                 if (!levdatum)
294                         return -EINVAL;
295                 context->range.level[l].sens = levdatum->level->sens;
296
297                 /* Extract category set. */
298                 while (next_cat != NULL) {
299                         cur_cat = next_cat;
300                         next_cat = strchr(next_cat, ',');
301                         if (next_cat != NULL)
302                                 *(next_cat++) = '\0';
303
304                         /* Separate into range if exists */
305                         rngptr = strchr(cur_cat, '.');
306                         if (rngptr != NULL) {
307                                 /* Remove '.' */
308                                 *rngptr++ = '\0';
309                         }
310
311                         catdatum = hashtab_search(pol->p_cats.table, cur_cat);
312                         if (!catdatum)
313                                 return -EINVAL;
314
315                         rc = ebitmap_set_bit(&context->range.level[l].cat,
316                                              catdatum->value - 1, 1);
317                         if (rc)
318                                 return rc;
319
320                         /* If range, set all categories in range */
321                         if (rngptr == NULL)
322                                 continue;
323
324                         rngdatum = hashtab_search(pol->p_cats.table, rngptr);
325                         if (!rngdatum)
326                                 return -EINVAL;
327
328                         if (catdatum->value >= rngdatum->value)
329                                 return -EINVAL;
330
331                         for (i = catdatum->value; i < rngdatum->value; i++) {
332                                 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
333                                 if (rc)
334                                         return rc;
335                         }
336                 }
337         }
338
339         /* If we didn't see a '-', the range start is also the range end. */
340         if (rangep[1] == NULL) {
341                 context->range.level[1].sens = context->range.level[0].sens;
342                 rc = ebitmap_cpy(&context->range.level[1].cat,
343                                  &context->range.level[0].cat);
344                 if (rc)
345                         return rc;
346         }
347
348         return 0;
349 }
350
351 /*
352  * Set the MLS fields in the security context structure
353  * `context' based on the string representation in
354  * the string `str'.  This function will allocate temporary memory with the
355  * given constraints of gfp_mask.
356  */
357 int mls_from_string(struct policydb *p, char *str, struct context *context,
358                     gfp_t gfp_mask)
359 {
360         char *tmpstr;
361         int rc;
362
363         if (!p->mls_enabled)
364                 return -EINVAL;
365
366         tmpstr = kstrdup(str, gfp_mask);
367         if (!tmpstr) {
368                 rc = -ENOMEM;
369         } else {
370                 rc = mls_context_to_sid(p, ':', tmpstr, context,
371                                         NULL, SECSID_NULL);
372                 kfree(tmpstr);
373         }
374
375         return rc;
376 }
377
378 /*
379  * Copies the MLS range `range' into `context'.
380  */
381 int mls_range_set(struct context *context,
382                                 struct mls_range *range)
383 {
384         int l, rc = 0;
385
386         /* Copy the MLS range into the  context */
387         for (l = 0; l < 2; l++) {
388                 context->range.level[l].sens = range->level[l].sens;
389                 rc = ebitmap_cpy(&context->range.level[l].cat,
390                                  &range->level[l].cat);
391                 if (rc)
392                         break;
393         }
394
395         return rc;
396 }
397
398 int mls_setup_user_range(struct policydb *p,
399                          struct context *fromcon, struct user_datum *user,
400                          struct context *usercon)
401 {
402         if (p->mls_enabled) {
403                 struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
404                 struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
405                 struct mls_level *user_low = &(user->range.level[0]);
406                 struct mls_level *user_clr = &(user->range.level[1]);
407                 struct mls_level *user_def = &(user->dfltlevel);
408                 struct mls_level *usercon_sen = &(usercon->range.level[0]);
409                 struct mls_level *usercon_clr = &(usercon->range.level[1]);
410
411                 /* Honor the user's default level if we can */
412                 if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
413                         *usercon_sen = *user_def;
414                 else if (mls_level_between(fromcon_sen, user_def, user_clr))
415                         *usercon_sen = *fromcon_sen;
416                 else if (mls_level_between(fromcon_clr, user_low, user_def))
417                         *usercon_sen = *user_low;
418                 else
419                         return -EINVAL;
420
421                 /* Lower the clearance of available contexts
422                    if the clearance of "fromcon" is lower than
423                    that of the user's default clearance (but
424                    only if the "fromcon" clearance dominates
425                    the user's computed sensitivity level) */
426                 if (mls_level_dom(user_clr, fromcon_clr))
427                         *usercon_clr = *fromcon_clr;
428                 else if (mls_level_dom(fromcon_clr, user_clr))
429                         *usercon_clr = *user_clr;
430                 else
431                         return -EINVAL;
432         }
433
434         return 0;
435 }
436
437 /*
438  * Convert the MLS fields in the security context
439  * structure `c' from the values specified in the
440  * policy `oldp' to the values specified in the policy `newp'.
441  */
442 int mls_convert_context(struct policydb *oldp,
443                         struct policydb *newp,
444                         struct context *c)
445 {
446         struct level_datum *levdatum;
447         struct cat_datum *catdatum;
448         struct ebitmap bitmap;
449         struct ebitmap_node *node;
450         int l, i;
451
452         if (!oldp->mls_enabled || !newp->mls_enabled)
453                 return 0;
454
455         for (l = 0; l < 2; l++) {
456                 levdatum = hashtab_search(newp->p_levels.table,
457                                           sym_name(oldp, SYM_LEVELS,
458                                                    c->range.level[l].sens - 1));
459
460                 if (!levdatum)
461                         return -EINVAL;
462                 c->range.level[l].sens = levdatum->level->sens;
463
464                 ebitmap_init(&bitmap);
465                 ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
466                         int rc;
467
468                         catdatum = hashtab_search(newp->p_cats.table,
469                                                   sym_name(oldp, SYM_CATS, i));
470                         if (!catdatum)
471                                 return -EINVAL;
472                         rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
473                         if (rc)
474                                 return rc;
475
476                         cond_resched();
477                 }
478                 ebitmap_destroy(&c->range.level[l].cat);
479                 c->range.level[l].cat = bitmap;
480         }
481
482         return 0;
483 }
484
485 int mls_compute_sid(struct policydb *p,
486                     struct context *scontext,
487                     struct context *tcontext,
488                     u16 tclass,
489                     u32 specified,
490                     struct context *newcontext,
491                     bool sock)
492 {
493         struct range_trans rtr;
494         struct mls_range *r;
495         struct class_datum *cladatum;
496         int default_range = 0;
497
498         if (!p->mls_enabled)
499                 return 0;
500
501         switch (specified) {
502         case AVTAB_TRANSITION:
503                 /* Look for a range transition rule. */
504                 rtr.source_type = scontext->type;
505                 rtr.target_type = tcontext->type;
506                 rtr.target_class = tclass;
507                 r = hashtab_search(p->range_tr, &rtr);
508                 if (r)
509                         return mls_range_set(newcontext, r);
510
511                 if (tclass && tclass <= p->p_classes.nprim) {
512                         cladatum = p->class_val_to_struct[tclass - 1];
513                         if (cladatum)
514                                 default_range = cladatum->default_range;
515                 }
516
517                 switch (default_range) {
518                 case DEFAULT_SOURCE_LOW:
519                         return mls_context_cpy_low(newcontext, scontext);
520                 case DEFAULT_SOURCE_HIGH:
521                         return mls_context_cpy_high(newcontext, scontext);
522                 case DEFAULT_SOURCE_LOW_HIGH:
523                         return mls_context_cpy(newcontext, scontext);
524                 case DEFAULT_TARGET_LOW:
525                         return mls_context_cpy_low(newcontext, tcontext);
526                 case DEFAULT_TARGET_HIGH:
527                         return mls_context_cpy_high(newcontext, tcontext);
528                 case DEFAULT_TARGET_LOW_HIGH:
529                         return mls_context_cpy(newcontext, tcontext);
530                 }
531
532                 /* Fallthrough */
533         case AVTAB_CHANGE:
534                 if ((tclass == p->process_class) || (sock == true))
535                         /* Use the process MLS attributes. */
536                         return mls_context_cpy(newcontext, scontext);
537                 else
538                         /* Use the process effective MLS attributes. */
539                         return mls_context_cpy_low(newcontext, scontext);
540         case AVTAB_MEMBER:
541                 /* Use the process effective MLS attributes. */
542                 return mls_context_cpy_low(newcontext, scontext);
543
544         /* fall through */
545         }
546         return -EINVAL;
547 }
548
549 #ifdef CONFIG_NETLABEL
550 /**
551  * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
552  * @context: the security context
553  * @secattr: the NetLabel security attributes
554  *
555  * Description:
556  * Given the security context copy the low MLS sensitivity level into the
557  * NetLabel MLS sensitivity level field.
558  *
559  */
560 void mls_export_netlbl_lvl(struct policydb *p,
561                            struct context *context,
562                            struct netlbl_lsm_secattr *secattr)
563 {
564         if (!p->mls_enabled)
565                 return;
566
567         secattr->attr.mls.lvl = context->range.level[0].sens - 1;
568         secattr->flags |= NETLBL_SECATTR_MLS_LVL;
569 }
570
571 /**
572  * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
573  * @context: the security context
574  * @secattr: the NetLabel security attributes
575  *
576  * Description:
577  * Given the security context and the NetLabel security attributes, copy the
578  * NetLabel MLS sensitivity level into the context.
579  *
580  */
581 void mls_import_netlbl_lvl(struct policydb *p,
582                            struct context *context,
583                            struct netlbl_lsm_secattr *secattr)
584 {
585         if (!p->mls_enabled)
586                 return;
587
588         context->range.level[0].sens = secattr->attr.mls.lvl + 1;
589         context->range.level[1].sens = context->range.level[0].sens;
590 }
591
592 /**
593  * mls_export_netlbl_cat - Export the MLS categories to NetLabel
594  * @context: the security context
595  * @secattr: the NetLabel security attributes
596  *
597  * Description:
598  * Given the security context copy the low MLS categories into the NetLabel
599  * MLS category field.  Returns zero on success, negative values on failure.
600  *
601  */
602 int mls_export_netlbl_cat(struct policydb *p,
603                           struct context *context,
604                           struct netlbl_lsm_secattr *secattr)
605 {
606         int rc;
607
608         if (!p->mls_enabled)
609                 return 0;
610
611         rc = ebitmap_netlbl_export(&context->range.level[0].cat,
612                                    &secattr->attr.mls.cat);
613         if (rc == 0 && secattr->attr.mls.cat != NULL)
614                 secattr->flags |= NETLBL_SECATTR_MLS_CAT;
615
616         return rc;
617 }
618
619 /**
620  * mls_import_netlbl_cat - Import the MLS categories from NetLabel
621  * @context: the security context
622  * @secattr: the NetLabel security attributes
623  *
624  * Description:
625  * Copy the NetLabel security attributes into the SELinux context; since the
626  * NetLabel security attribute only contains a single MLS category use it for
627  * both the low and high categories of the context.  Returns zero on success,
628  * negative values on failure.
629  *
630  */
631 int mls_import_netlbl_cat(struct policydb *p,
632                           struct context *context,
633                           struct netlbl_lsm_secattr *secattr)
634 {
635         int rc;
636
637         if (!p->mls_enabled)
638                 return 0;
639
640         rc = ebitmap_netlbl_import(&context->range.level[0].cat,
641                                    secattr->attr.mls.cat);
642         if (rc)
643                 goto import_netlbl_cat_failure;
644         memcpy(&context->range.level[1].cat, &context->range.level[0].cat,
645                sizeof(context->range.level[0].cat));
646
647         return 0;
648
649 import_netlbl_cat_failure:
650         ebitmap_destroy(&context->range.level[0].cat);
651         return rc;
652 }
653 #endif /* CONFIG_NETLABEL */