root/security/selinux/ss/mls.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mls_compute_context_len
  2. mls_sid_to_context
  3. mls_level_isvalid
  4. mls_range_isvalid
  5. mls_context_isvalid
  6. mls_context_to_sid
  7. mls_from_string
  8. mls_range_set
  9. mls_setup_user_range
  10. mls_convert_context
  11. mls_compute_sid
  12. mls_export_netlbl_lvl
  13. mls_import_netlbl_lvl
  14. mls_export_netlbl_cat
  15. mls_import_netlbl_cat

   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                 /*
 249                  * With no MLS, only return -EINVAL if there is a MLS field
 250                  * and it did not come from an xattr.
 251                  */
 252                 if (oldc && def_sid == SECSID_NULL)
 253                         return -EINVAL;
 254                 return 0;
 255         }
 256 
 257         /*
 258          * No MLS component to the security context, try and map to
 259          * default if provided.
 260          */
 261         if (!oldc) {
 262                 struct context *defcon;
 263 
 264                 if (def_sid == SECSID_NULL)
 265                         return -EINVAL;
 266 
 267                 defcon = sidtab_search(s, def_sid);
 268                 if (!defcon)
 269                         return -EINVAL;
 270 
 271                 return mls_context_cpy(context, defcon);
 272         }
 273 
 274         /*
 275          * If we're dealing with a range, figure out where the two parts
 276          * of the range begin.
 277          */
 278         rangep[0] = scontext;
 279         rangep[1] = strchr(scontext, '-');
 280         if (rangep[1]) {
 281                 rangep[1][0] = '\0';
 282                 rangep[1]++;
 283         }
 284 
 285         /* For each part of the range: */
 286         for (l = 0; l < 2; l++) {
 287                 /* Split sensitivity and category set. */
 288                 sensitivity = rangep[l];
 289                 if (sensitivity == NULL)
 290                         break;
 291                 next_cat = strchr(sensitivity, ':');
 292                 if (next_cat)
 293                         *(next_cat++) = '\0';
 294 
 295                 /* Parse sensitivity. */
 296                 levdatum = hashtab_search(pol->p_levels.table, sensitivity);
 297                 if (!levdatum)
 298                         return -EINVAL;
 299                 context->range.level[l].sens = levdatum->level->sens;
 300 
 301                 /* Extract category set. */
 302                 while (next_cat != NULL) {
 303                         cur_cat = next_cat;
 304                         next_cat = strchr(next_cat, ',');
 305                         if (next_cat != NULL)
 306                                 *(next_cat++) = '\0';
 307 
 308                         /* Separate into range if exists */
 309                         rngptr = strchr(cur_cat, '.');
 310                         if (rngptr != NULL) {
 311                                 /* Remove '.' */
 312                                 *rngptr++ = '\0';
 313                         }
 314 
 315                         catdatum = hashtab_search(pol->p_cats.table, cur_cat);
 316                         if (!catdatum)
 317                                 return -EINVAL;
 318 
 319                         rc = ebitmap_set_bit(&context->range.level[l].cat,
 320                                              catdatum->value - 1, 1);
 321                         if (rc)
 322                                 return rc;
 323 
 324                         /* If range, set all categories in range */
 325                         if (rngptr == NULL)
 326                                 continue;
 327 
 328                         rngdatum = hashtab_search(pol->p_cats.table, rngptr);
 329                         if (!rngdatum)
 330                                 return -EINVAL;
 331 
 332                         if (catdatum->value >= rngdatum->value)
 333                                 return -EINVAL;
 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                                         return rc;
 339                         }
 340                 }
 341         }
 342 
 343         /* If we didn't see a '-', the range start is also the range end. */
 344         if (rangep[1] == NULL) {
 345                 context->range.level[1].sens = context->range.level[0].sens;
 346                 rc = ebitmap_cpy(&context->range.level[1].cat,
 347                                  &context->range.level[0].cat);
 348                 if (rc)
 349                         return rc;
 350         }
 351 
 352         return 0;
 353 }
 354 
 355 /*
 356  * Set the MLS fields in the security context structure
 357  * `context' based on the string representation in
 358  * the string `str'.  This function will allocate temporary memory with the
 359  * given constraints of gfp_mask.
 360  */
 361 int mls_from_string(struct policydb *p, char *str, struct context *context,
 362                     gfp_t gfp_mask)
 363 {
 364         char *tmpstr;
 365         int rc;
 366 
 367         if (!p->mls_enabled)
 368                 return -EINVAL;
 369 
 370         tmpstr = kstrdup(str, gfp_mask);
 371         if (!tmpstr) {
 372                 rc = -ENOMEM;
 373         } else {
 374                 rc = mls_context_to_sid(p, ':', tmpstr, context,
 375                                         NULL, SECSID_NULL);
 376                 kfree(tmpstr);
 377         }
 378 
 379         return rc;
 380 }
 381 
 382 /*
 383  * Copies the MLS range `range' into `context'.
 384  */
 385 int mls_range_set(struct context *context,
 386                                 struct mls_range *range)
 387 {
 388         int l, rc = 0;
 389 
 390         /* Copy the MLS range into the  context */
 391         for (l = 0; l < 2; l++) {
 392                 context->range.level[l].sens = range->level[l].sens;
 393                 rc = ebitmap_cpy(&context->range.level[l].cat,
 394                                  &range->level[l].cat);
 395                 if (rc)
 396                         break;
 397         }
 398 
 399         return rc;
 400 }
 401 
 402 int mls_setup_user_range(struct policydb *p,
 403                          struct context *fromcon, struct user_datum *user,
 404                          struct context *usercon)
 405 {
 406         if (p->mls_enabled) {
 407                 struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
 408                 struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
 409                 struct mls_level *user_low = &(user->range.level[0]);
 410                 struct mls_level *user_clr = &(user->range.level[1]);
 411                 struct mls_level *user_def = &(user->dfltlevel);
 412                 struct mls_level *usercon_sen = &(usercon->range.level[0]);
 413                 struct mls_level *usercon_clr = &(usercon->range.level[1]);
 414 
 415                 /* Honor the user's default level if we can */
 416                 if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
 417                         *usercon_sen = *user_def;
 418                 else if (mls_level_between(fromcon_sen, user_def, user_clr))
 419                         *usercon_sen = *fromcon_sen;
 420                 else if (mls_level_between(fromcon_clr, user_low, user_def))
 421                         *usercon_sen = *user_low;
 422                 else
 423                         return -EINVAL;
 424 
 425                 /* Lower the clearance of available contexts
 426                    if the clearance of "fromcon" is lower than
 427                    that of the user's default clearance (but
 428                    only if the "fromcon" clearance dominates
 429                    the user's computed sensitivity level) */
 430                 if (mls_level_dom(user_clr, fromcon_clr))
 431                         *usercon_clr = *fromcon_clr;
 432                 else if (mls_level_dom(fromcon_clr, user_clr))
 433                         *usercon_clr = *user_clr;
 434                 else
 435                         return -EINVAL;
 436         }
 437 
 438         return 0;
 439 }
 440 
 441 /*
 442  * Convert the MLS fields in the security context
 443  * structure `oldc' from the values specified in the
 444  * policy `oldp' to the values specified in the policy `newp',
 445  * storing the resulting context in `newc'.
 446  */
 447 int mls_convert_context(struct policydb *oldp,
 448                         struct policydb *newp,
 449                         struct context *oldc,
 450                         struct context *newc)
 451 {
 452         struct level_datum *levdatum;
 453         struct cat_datum *catdatum;
 454         struct ebitmap_node *node;
 455         int l, i;
 456 
 457         if (!oldp->mls_enabled || !newp->mls_enabled)
 458                 return 0;
 459 
 460         for (l = 0; l < 2; l++) {
 461                 levdatum = hashtab_search(newp->p_levels.table,
 462                                           sym_name(oldp, SYM_LEVELS,
 463                                                    oldc->range.level[l].sens - 1));
 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 = hashtab_search(newp->p_cats.table,
 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 = hashtab_search(p->range_tr, &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                 }
 533 
 534                 /* Fallthrough */
 535         case AVTAB_CHANGE:
 536                 if ((tclass == p->process_class) || (sock == true))
 537                         /* Use the process MLS attributes. */
 538                         return mls_context_cpy(newcontext, scontext);
 539                 else
 540                         /* Use the process effective MLS attributes. */
 541                         return mls_context_cpy_low(newcontext, scontext);
 542         case AVTAB_MEMBER:
 543                 /* Use the process effective MLS attributes. */
 544                 return mls_context_cpy_low(newcontext, scontext);
 545 
 546         /* fall through */
 547         }
 548         return -EINVAL;
 549 }
 550 
 551 #ifdef CONFIG_NETLABEL
 552 /**
 553  * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
 554  * @context: the security context
 555  * @secattr: the NetLabel security attributes
 556  *
 557  * Description:
 558  * Given the security context copy the low MLS sensitivity level into the
 559  * NetLabel MLS sensitivity level field.
 560  *
 561  */
 562 void mls_export_netlbl_lvl(struct policydb *p,
 563                            struct context *context,
 564                            struct netlbl_lsm_secattr *secattr)
 565 {
 566         if (!p->mls_enabled)
 567                 return;
 568 
 569         secattr->attr.mls.lvl = context->range.level[0].sens - 1;
 570         secattr->flags |= NETLBL_SECATTR_MLS_LVL;
 571 }
 572 
 573 /**
 574  * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
 575  * @context: the security context
 576  * @secattr: the NetLabel security attributes
 577  *
 578  * Description:
 579  * Given the security context and the NetLabel security attributes, copy the
 580  * NetLabel MLS sensitivity level into the context.
 581  *
 582  */
 583 void mls_import_netlbl_lvl(struct policydb *p,
 584                            struct context *context,
 585                            struct netlbl_lsm_secattr *secattr)
 586 {
 587         if (!p->mls_enabled)
 588                 return;
 589 
 590         context->range.level[0].sens = secattr->attr.mls.lvl + 1;
 591         context->range.level[1].sens = context->range.level[0].sens;
 592 }
 593 
 594 /**
 595  * mls_export_netlbl_cat - Export the MLS categories to NetLabel
 596  * @context: the security context
 597  * @secattr: the NetLabel security attributes
 598  *
 599  * Description:
 600  * Given the security context copy the low MLS categories into the NetLabel
 601  * MLS category field.  Returns zero on success, negative values on failure.
 602  *
 603  */
 604 int mls_export_netlbl_cat(struct policydb *p,
 605                           struct context *context,
 606                           struct netlbl_lsm_secattr *secattr)
 607 {
 608         int rc;
 609 
 610         if (!p->mls_enabled)
 611                 return 0;
 612 
 613         rc = ebitmap_netlbl_export(&context->range.level[0].cat,
 614                                    &secattr->attr.mls.cat);
 615         if (rc == 0 && secattr->attr.mls.cat != NULL)
 616                 secattr->flags |= NETLBL_SECATTR_MLS_CAT;
 617 
 618         return rc;
 619 }
 620 
 621 /**
 622  * mls_import_netlbl_cat - Import the MLS categories from NetLabel
 623  * @context: the security context
 624  * @secattr: the NetLabel security attributes
 625  *
 626  * Description:
 627  * Copy the NetLabel security attributes into the SELinux context; since the
 628  * NetLabel security attribute only contains a single MLS category use it for
 629  * both the low and high categories of the context.  Returns zero on success,
 630  * negative values on failure.
 631  *
 632  */
 633 int mls_import_netlbl_cat(struct policydb *p,
 634                           struct context *context,
 635                           struct netlbl_lsm_secattr *secattr)
 636 {
 637         int rc;
 638 
 639         if (!p->mls_enabled)
 640                 return 0;
 641 
 642         rc = ebitmap_netlbl_import(&context->range.level[0].cat,
 643                                    secattr->attr.mls.cat);
 644         if (rc)
 645                 goto import_netlbl_cat_failure;
 646         memcpy(&context->range.level[1].cat, &context->range.level[0].cat,
 647                sizeof(context->range.level[0].cat));
 648 
 649         return 0;
 650 
 651 import_netlbl_cat_failure:
 652         ebitmap_destroy(&context->range.level[0].cat);
 653         return rc;
 654 }
 655 #endif /* CONFIG_NETLABEL */

/* [<][>][^][v][top][bottom][index][help] */