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