Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Implementation of the multi-level security (MLS) policy.
0004  *
0005  * Author : Stephen Smalley, <sds@tycho.nsa.gov>
0006  */
0007 /*
0008  * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
0009  *
0010  *  Support for enhanced MLS infrastructure.
0011  *
0012  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
0013  */
0014 /*
0015  * Updated: Hewlett-Packard <paul@paul-moore.com>
0016  *
0017  *      Added support to import/export the MLS label from NetLabel
0018  *
0019  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
0020  */
0021 
0022 #include <linux/kernel.h>
0023 #include <linux/slab.h>
0024 #include <linux/string.h>
0025 #include <linux/errno.h>
0026 #include <net/netlabel.h>
0027 #include "sidtab.h"
0028 #include "mls.h"
0029 #include "policydb.h"
0030 #include "services.h"
0031 
0032 /*
0033  * Return the length in bytes for the MLS fields of the
0034  * security context string representation of `context'.
0035  */
0036 int mls_compute_context_len(struct policydb *p, struct context *context)
0037 {
0038     int i, l, len, head, prev;
0039     char *nm;
0040     struct ebitmap *e;
0041     struct ebitmap_node *node;
0042 
0043     if (!p->mls_enabled)
0044         return 0;
0045 
0046     len = 1; /* for the beginning ":" */
0047     for (l = 0; l < 2; l++) {
0048         int index_sens = context->range.level[l].sens;
0049         len += strlen(sym_name(p, SYM_LEVELS, index_sens - 1));
0050 
0051         /* categories */
0052         head = -2;
0053         prev = -2;
0054         e = &context->range.level[l].cat;
0055         ebitmap_for_each_positive_bit(e, node, i) {
0056             if (i - prev > 1) {
0057                 /* one or more negative bits are skipped */
0058                 if (head != prev) {
0059                     nm = sym_name(p, SYM_CATS, prev);
0060                     len += strlen(nm) + 1;
0061                 }
0062                 nm = sym_name(p, SYM_CATS, i);
0063                 len += strlen(nm) + 1;
0064                 head = i;
0065             }
0066             prev = i;
0067         }
0068         if (prev != head) {
0069             nm = sym_name(p, SYM_CATS, prev);
0070             len += strlen(nm) + 1;
0071         }
0072         if (l == 0) {
0073             if (mls_level_eq(&context->range.level[0],
0074                      &context->range.level[1]))
0075                 break;
0076             else
0077                 len++;
0078         }
0079     }
0080 
0081     return len;
0082 }
0083 
0084 /*
0085  * Write the security context string representation of
0086  * the MLS fields of `context' into the string `*scontext'.
0087  * Update `*scontext' to point to the end of the MLS fields.
0088  */
0089 void mls_sid_to_context(struct policydb *p,
0090             struct context *context,
0091             char **scontext)
0092 {
0093     char *scontextp, *nm;
0094     int i, l, head, prev;
0095     struct ebitmap *e;
0096     struct ebitmap_node *node;
0097 
0098     if (!p->mls_enabled)
0099         return;
0100 
0101     scontextp = *scontext;
0102 
0103     *scontextp = ':';
0104     scontextp++;
0105 
0106     for (l = 0; l < 2; l++) {
0107         strcpy(scontextp, sym_name(p, SYM_LEVELS,
0108                        context->range.level[l].sens - 1));
0109         scontextp += strlen(scontextp);
0110 
0111         /* categories */
0112         head = -2;
0113         prev = -2;
0114         e = &context->range.level[l].cat;
0115         ebitmap_for_each_positive_bit(e, node, i) {
0116             if (i - prev > 1) {
0117                 /* one or more negative bits are skipped */
0118                 if (prev != head) {
0119                     if (prev - head > 1)
0120                         *scontextp++ = '.';
0121                     else
0122                         *scontextp++ = ',';
0123                     nm = sym_name(p, SYM_CATS, prev);
0124                     strcpy(scontextp, nm);
0125                     scontextp += strlen(nm);
0126                 }
0127                 if (prev < 0)
0128                     *scontextp++ = ':';
0129                 else
0130                     *scontextp++ = ',';
0131                 nm = sym_name(p, SYM_CATS, i);
0132                 strcpy(scontextp, nm);
0133                 scontextp += strlen(nm);
0134                 head = i;
0135             }
0136             prev = i;
0137         }
0138 
0139         if (prev != head) {
0140             if (prev - head > 1)
0141                 *scontextp++ = '.';
0142             else
0143                 *scontextp++ = ',';
0144             nm = sym_name(p, SYM_CATS, prev);
0145             strcpy(scontextp, nm);
0146             scontextp += strlen(nm);
0147         }
0148 
0149         if (l == 0) {
0150             if (mls_level_eq(&context->range.level[0],
0151                      &context->range.level[1]))
0152                 break;
0153             else
0154                 *scontextp++ = '-';
0155         }
0156     }
0157 
0158     *scontext = scontextp;
0159 }
0160 
0161 int mls_level_isvalid(struct policydb *p, struct mls_level *l)
0162 {
0163     struct level_datum *levdatum;
0164 
0165     if (!l->sens || l->sens > p->p_levels.nprim)
0166         return 0;
0167     levdatum = symtab_search(&p->p_levels,
0168                  sym_name(p, SYM_LEVELS, l->sens - 1));
0169     if (!levdatum)
0170         return 0;
0171 
0172     /*
0173      * Return 1 iff all the bits set in l->cat are also be set in
0174      * levdatum->level->cat and no bit in l->cat is larger than
0175      * p->p_cats.nprim.
0176      */
0177     return ebitmap_contains(&levdatum->level->cat, &l->cat,
0178                 p->p_cats.nprim);
0179 }
0180 
0181 int mls_range_isvalid(struct policydb *p, struct mls_range *r)
0182 {
0183     return (mls_level_isvalid(p, &r->level[0]) &&
0184         mls_level_isvalid(p, &r->level[1]) &&
0185         mls_level_dom(&r->level[1], &r->level[0]));
0186 }
0187 
0188 /*
0189  * Return 1 if the MLS fields in the security context
0190  * structure `c' are valid.  Return 0 otherwise.
0191  */
0192 int mls_context_isvalid(struct policydb *p, struct context *c)
0193 {
0194     struct user_datum *usrdatum;
0195 
0196     if (!p->mls_enabled)
0197         return 1;
0198 
0199     if (!mls_range_isvalid(p, &c->range))
0200         return 0;
0201 
0202     if (c->role == OBJECT_R_VAL)
0203         return 1;
0204 
0205     /*
0206      * User must be authorized for the MLS range.
0207      */
0208     if (!c->user || c->user > p->p_users.nprim)
0209         return 0;
0210     usrdatum = p->user_val_to_struct[c->user - 1];
0211     if (!mls_range_contains(usrdatum->range, c->range))
0212         return 0; /* user may not be associated with range */
0213 
0214     return 1;
0215 }
0216 
0217 /*
0218  * Set the MLS fields in the security context structure
0219  * `context' based on the string representation in
0220  * the string `scontext'.
0221  *
0222  * This function modifies the string in place, inserting
0223  * NULL characters to terminate the MLS fields.
0224  *
0225  * If a def_sid is provided and no MLS field is present,
0226  * copy the MLS field of the associated default context.
0227  * Used for upgraded to MLS systems where objects may lack
0228  * MLS fields.
0229  *
0230  * Policy read-lock must be held for sidtab lookup.
0231  *
0232  */
0233 int mls_context_to_sid(struct policydb *pol,
0234                char oldc,
0235                char *scontext,
0236                struct context *context,
0237                struct sidtab *s,
0238                u32 def_sid)
0239 {
0240     char *sensitivity, *cur_cat, *next_cat, *rngptr;
0241     struct level_datum *levdatum;
0242     struct cat_datum *catdatum, *rngdatum;
0243     int l, rc, i;
0244     char *rangep[2];
0245 
0246     if (!pol->mls_enabled) {
0247         /*
0248          * With no MLS, only return -EINVAL if there is a MLS field
0249          * and it did not come from an xattr.
0250          */
0251         if (oldc && def_sid == SECSID_NULL)
0252             return -EINVAL;
0253         return 0;
0254     }
0255 
0256     /*
0257      * No MLS component to the security context, try and map to
0258      * default if provided.
0259      */
0260     if (!oldc) {
0261         struct context *defcon;
0262 
0263         if (def_sid == SECSID_NULL)
0264             return -EINVAL;
0265 
0266         defcon = sidtab_search(s, def_sid);
0267         if (!defcon)
0268             return -EINVAL;
0269 
0270         return mls_context_cpy(context, defcon);
0271     }
0272 
0273     /*
0274      * If we're dealing with a range, figure out where the two parts
0275      * of the range begin.
0276      */
0277     rangep[0] = scontext;
0278     rangep[1] = strchr(scontext, '-');
0279     if (rangep[1]) {
0280         rangep[1][0] = '\0';
0281         rangep[1]++;
0282     }
0283 
0284     /* For each part of the range: */
0285     for (l = 0; l < 2; l++) {
0286         /* Split sensitivity and category set. */
0287         sensitivity = rangep[l];
0288         if (sensitivity == NULL)
0289             break;
0290         next_cat = strchr(sensitivity, ':');
0291         if (next_cat)
0292             *(next_cat++) = '\0';
0293 
0294         /* Parse sensitivity. */
0295         levdatum = symtab_search(&pol->p_levels, sensitivity);
0296         if (!levdatum)
0297             return -EINVAL;
0298         context->range.level[l].sens = levdatum->level->sens;
0299 
0300         /* Extract category set. */
0301         while (next_cat != NULL) {
0302             cur_cat = next_cat;
0303             next_cat = strchr(next_cat, ',');
0304             if (next_cat != NULL)
0305                 *(next_cat++) = '\0';
0306 
0307             /* Separate into range if exists */
0308             rngptr = strchr(cur_cat, '.');
0309             if (rngptr != NULL) {
0310                 /* Remove '.' */
0311                 *rngptr++ = '\0';
0312             }
0313 
0314             catdatum = symtab_search(&pol->p_cats, cur_cat);
0315             if (!catdatum)
0316                 return -EINVAL;
0317 
0318             rc = ebitmap_set_bit(&context->range.level[l].cat,
0319                          catdatum->value - 1, 1);
0320             if (rc)
0321                 return rc;
0322 
0323             /* If range, set all categories in range */
0324             if (rngptr == NULL)
0325                 continue;
0326 
0327             rngdatum = symtab_search(&pol->p_cats, rngptr);
0328             if (!rngdatum)
0329                 return -EINVAL;
0330 
0331             if (catdatum->value >= rngdatum->value)
0332                 return -EINVAL;
0333 
0334             for (i = catdatum->value; i < rngdatum->value; i++) {
0335                 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
0336                 if (rc)
0337                     return rc;
0338             }
0339         }
0340     }
0341 
0342     /* If we didn't see a '-', the range start is also the range end. */
0343     if (rangep[1] == NULL) {
0344         context->range.level[1].sens = context->range.level[0].sens;
0345         rc = ebitmap_cpy(&context->range.level[1].cat,
0346                  &context->range.level[0].cat);
0347         if (rc)
0348             return rc;
0349     }
0350 
0351     return 0;
0352 }
0353 
0354 /*
0355  * Set the MLS fields in the security context structure
0356  * `context' based on the string representation in
0357  * the string `str'.  This function will allocate temporary memory with the
0358  * given constraints of gfp_mask.
0359  */
0360 int mls_from_string(struct policydb *p, char *str, struct context *context,
0361             gfp_t gfp_mask)
0362 {
0363     char *tmpstr;
0364     int rc;
0365 
0366     if (!p->mls_enabled)
0367         return -EINVAL;
0368 
0369     tmpstr = kstrdup(str, gfp_mask);
0370     if (!tmpstr) {
0371         rc = -ENOMEM;
0372     } else {
0373         rc = mls_context_to_sid(p, ':', tmpstr, context,
0374                     NULL, SECSID_NULL);
0375         kfree(tmpstr);
0376     }
0377 
0378     return rc;
0379 }
0380 
0381 /*
0382  * Copies the MLS range `range' into `context'.
0383  */
0384 int mls_range_set(struct context *context,
0385                 struct mls_range *range)
0386 {
0387     int l, rc = 0;
0388 
0389     /* Copy the MLS range into the  context */
0390     for (l = 0; l < 2; l++) {
0391         context->range.level[l].sens = range->level[l].sens;
0392         rc = ebitmap_cpy(&context->range.level[l].cat,
0393                  &range->level[l].cat);
0394         if (rc)
0395             break;
0396     }
0397 
0398     return rc;
0399 }
0400 
0401 int mls_setup_user_range(struct policydb *p,
0402              struct context *fromcon, struct user_datum *user,
0403              struct context *usercon)
0404 {
0405     if (p->mls_enabled) {
0406         struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
0407         struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
0408         struct mls_level *user_low = &(user->range.level[0]);
0409         struct mls_level *user_clr = &(user->range.level[1]);
0410         struct mls_level *user_def = &(user->dfltlevel);
0411         struct mls_level *usercon_sen = &(usercon->range.level[0]);
0412         struct mls_level *usercon_clr = &(usercon->range.level[1]);
0413 
0414         /* Honor the user's default level if we can */
0415         if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
0416             *usercon_sen = *user_def;
0417         else if (mls_level_between(fromcon_sen, user_def, user_clr))
0418             *usercon_sen = *fromcon_sen;
0419         else if (mls_level_between(fromcon_clr, user_low, user_def))
0420             *usercon_sen = *user_low;
0421         else
0422             return -EINVAL;
0423 
0424         /* Lower the clearance of available contexts
0425            if the clearance of "fromcon" is lower than
0426            that of the user's default clearance (but
0427            only if the "fromcon" clearance dominates
0428            the user's computed sensitivity level) */
0429         if (mls_level_dom(user_clr, fromcon_clr))
0430             *usercon_clr = *fromcon_clr;
0431         else if (mls_level_dom(fromcon_clr, user_clr))
0432             *usercon_clr = *user_clr;
0433         else
0434             return -EINVAL;
0435     }
0436 
0437     return 0;
0438 }
0439 
0440 /*
0441  * Convert the MLS fields in the security context
0442  * structure `oldc' from the values specified in the
0443  * policy `oldp' to the values specified in the policy `newp',
0444  * storing the resulting context in `newc'.
0445  */
0446 int mls_convert_context(struct policydb *oldp,
0447             struct policydb *newp,
0448             struct context *oldc,
0449             struct context *newc)
0450 {
0451     struct level_datum *levdatum;
0452     struct cat_datum *catdatum;
0453     struct ebitmap_node *node;
0454     int l, i;
0455 
0456     if (!oldp->mls_enabled || !newp->mls_enabled)
0457         return 0;
0458 
0459     for (l = 0; l < 2; l++) {
0460         char *name = sym_name(oldp, SYM_LEVELS,
0461                       oldc->range.level[l].sens - 1);
0462 
0463         levdatum = symtab_search(&newp->p_levels, name);
0464 
0465         if (!levdatum)
0466             return -EINVAL;
0467         newc->range.level[l].sens = levdatum->level->sens;
0468 
0469         ebitmap_for_each_positive_bit(&oldc->range.level[l].cat,
0470                           node, i) {
0471             int rc;
0472 
0473             catdatum = symtab_search(&newp->p_cats,
0474                          sym_name(oldp, SYM_CATS, i));
0475             if (!catdatum)
0476                 return -EINVAL;
0477             rc = ebitmap_set_bit(&newc->range.level[l].cat,
0478                          catdatum->value - 1, 1);
0479             if (rc)
0480                 return rc;
0481         }
0482     }
0483 
0484     return 0;
0485 }
0486 
0487 int mls_compute_sid(struct policydb *p,
0488             struct context *scontext,
0489             struct context *tcontext,
0490             u16 tclass,
0491             u32 specified,
0492             struct context *newcontext,
0493             bool sock)
0494 {
0495     struct range_trans rtr;
0496     struct mls_range *r;
0497     struct class_datum *cladatum;
0498     int default_range = 0;
0499 
0500     if (!p->mls_enabled)
0501         return 0;
0502 
0503     switch (specified) {
0504     case AVTAB_TRANSITION:
0505         /* Look for a range transition rule. */
0506         rtr.source_type = scontext->type;
0507         rtr.target_type = tcontext->type;
0508         rtr.target_class = tclass;
0509         r = policydb_rangetr_search(p, &rtr);
0510         if (r)
0511             return mls_range_set(newcontext, r);
0512 
0513         if (tclass && tclass <= p->p_classes.nprim) {
0514             cladatum = p->class_val_to_struct[tclass - 1];
0515             if (cladatum)
0516                 default_range = cladatum->default_range;
0517         }
0518 
0519         switch (default_range) {
0520         case DEFAULT_SOURCE_LOW:
0521             return mls_context_cpy_low(newcontext, scontext);
0522         case DEFAULT_SOURCE_HIGH:
0523             return mls_context_cpy_high(newcontext, scontext);
0524         case DEFAULT_SOURCE_LOW_HIGH:
0525             return mls_context_cpy(newcontext, scontext);
0526         case DEFAULT_TARGET_LOW:
0527             return mls_context_cpy_low(newcontext, tcontext);
0528         case DEFAULT_TARGET_HIGH:
0529             return mls_context_cpy_high(newcontext, tcontext);
0530         case DEFAULT_TARGET_LOW_HIGH:
0531             return mls_context_cpy(newcontext, tcontext);
0532         case DEFAULT_GLBLUB:
0533             return mls_context_glblub(newcontext,
0534                           scontext, tcontext);
0535         }
0536 
0537         fallthrough;
0538     case AVTAB_CHANGE:
0539         if ((tclass == p->process_class) || sock)
0540             /* Use the process MLS attributes. */
0541             return mls_context_cpy(newcontext, scontext);
0542         else
0543             /* Use the process effective MLS attributes. */
0544             return mls_context_cpy_low(newcontext, scontext);
0545     case AVTAB_MEMBER:
0546         /* Use the process effective MLS attributes. */
0547         return mls_context_cpy_low(newcontext, scontext);
0548     }
0549     return -EINVAL;
0550 }
0551 
0552 #ifdef CONFIG_NETLABEL
0553 /**
0554  * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
0555  * @p: the policy
0556  * @context: the security context
0557  * @secattr: the NetLabel security attributes
0558  *
0559  * Description:
0560  * Given the security context copy the low MLS sensitivity level into the
0561  * NetLabel MLS sensitivity level field.
0562  *
0563  */
0564 void mls_export_netlbl_lvl(struct policydb *p,
0565                struct context *context,
0566                struct netlbl_lsm_secattr *secattr)
0567 {
0568     if (!p->mls_enabled)
0569         return;
0570 
0571     secattr->attr.mls.lvl = context->range.level[0].sens - 1;
0572     secattr->flags |= NETLBL_SECATTR_MLS_LVL;
0573 }
0574 
0575 /**
0576  * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
0577  * @p: the policy
0578  * @context: the security context
0579  * @secattr: the NetLabel security attributes
0580  *
0581  * Description:
0582  * Given the security context and the NetLabel security attributes, copy the
0583  * NetLabel MLS sensitivity level into the context.
0584  *
0585  */
0586 void mls_import_netlbl_lvl(struct policydb *p,
0587                struct context *context,
0588                struct netlbl_lsm_secattr *secattr)
0589 {
0590     if (!p->mls_enabled)
0591         return;
0592 
0593     context->range.level[0].sens = secattr->attr.mls.lvl + 1;
0594     context->range.level[1].sens = context->range.level[0].sens;
0595 }
0596 
0597 /**
0598  * mls_export_netlbl_cat - Export the MLS categories to NetLabel
0599  * @p: the policy
0600  * @context: the security context
0601  * @secattr: the NetLabel security attributes
0602  *
0603  * Description:
0604  * Given the security context copy the low MLS categories into the NetLabel
0605  * MLS category field.  Returns zero on success, negative values on failure.
0606  *
0607  */
0608 int mls_export_netlbl_cat(struct policydb *p,
0609               struct context *context,
0610               struct netlbl_lsm_secattr *secattr)
0611 {
0612     int rc;
0613 
0614     if (!p->mls_enabled)
0615         return 0;
0616 
0617     rc = ebitmap_netlbl_export(&context->range.level[0].cat,
0618                    &secattr->attr.mls.cat);
0619     if (rc == 0 && secattr->attr.mls.cat != NULL)
0620         secattr->flags |= NETLBL_SECATTR_MLS_CAT;
0621 
0622     return rc;
0623 }
0624 
0625 /**
0626  * mls_import_netlbl_cat - Import the MLS categories from NetLabel
0627  * @p: the policy
0628  * @context: the security context
0629  * @secattr: the NetLabel security attributes
0630  *
0631  * Description:
0632  * Copy the NetLabel security attributes into the SELinux context; since the
0633  * NetLabel security attribute only contains a single MLS category use it for
0634  * both the low and high categories of the context.  Returns zero on success,
0635  * negative values on failure.
0636  *
0637  */
0638 int mls_import_netlbl_cat(struct policydb *p,
0639               struct context *context,
0640               struct netlbl_lsm_secattr *secattr)
0641 {
0642     int rc;
0643 
0644     if (!p->mls_enabled)
0645         return 0;
0646 
0647     rc = ebitmap_netlbl_import(&context->range.level[0].cat,
0648                    secattr->attr.mls.cat);
0649     if (rc)
0650         goto import_netlbl_cat_failure;
0651     memcpy(&context->range.level[1].cat, &context->range.level[0].cat,
0652            sizeof(context->range.level[0].cat));
0653 
0654     return 0;
0655 
0656 import_netlbl_cat_failure:
0657     ebitmap_destroy(&context->range.level[0].cat);
0658     return rc;
0659 }
0660 #endif /* CONFIG_NETLABEL */