1 /* Author : Stephen Smalley, <sds (at) epoch.ncsc.mil> */ 2 /* 3 * Updated: Trusted Computer Solutions, Inc. <dgoeddel (at) trustedcs.com> 4 * 5 * Support for enhanced MLS infrastructure. 6 * 7 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24 /* FLASK */ 25 26 /* 27 * Implementation of the multi-level security (MLS) policy. 28 */ 29 30 #include <sepol/policydb/policydb.h> 31 #include <sepol/policydb/services.h> 32 #include <sepol/policydb/flask.h> 33 #include <sepol/policydb/context.h> 34 35 #include <stdlib.h> 36 37 #include "handle.h" 38 #include "debug.h" 39 #include "private.h" 40 #include "mls.h" 41 42 int mls_to_string(sepol_handle_t * handle, 43 const policydb_t * policydb, 44 const context_struct_t * mls, char **str) 45 { 46 47 char *ptr = NULL, *ptr2 = NULL; 48 49 /* Temporary buffer - length + NULL terminator */ 50 int len = mls_compute_context_len(policydb, mls) + 1; 51 52 ptr = (char *)malloc(len); 53 if (ptr == NULL) 54 goto omem; 55 56 /* Final string w/ ':' cut off */ 57 ptr2 = (char *)malloc(len - 1); 58 if (ptr2 == NULL) 59 goto omem; 60 61 mls_sid_to_context(policydb, mls, &ptr); 62 ptr -= len - 1; 63 strcpy(ptr2, ptr + 1); 64 65 free(ptr); 66 *str = ptr2; 67 return STATUS_SUCCESS; 68 69 omem: 70 ERR(handle, "out of memory, could not convert mls context to string"); 71 72 free(ptr); 73 free(ptr2); 74 return STATUS_ERR; 75 76 } 77 78 int mls_from_string(sepol_handle_t * handle, 79 const policydb_t * policydb, 80 const char *str, context_struct_t * mls) 81 { 82 83 char *tmp = strdup(str); 84 char *tmp_cp = tmp; 85 if (!tmp) 86 goto omem; 87 88 if (mls_context_to_sid(policydb, '$', &tmp_cp, mls) < 0) { 89 ERR(handle, "invalid MLS context %s", str); 90 free(tmp); 91 goto err; 92 } 93 94 free(tmp); 95 return STATUS_SUCCESS; 96 97 omem: 98 ERR(handle, "out of memory"); 99 100 err: 101 ERR(handle, "could not construct mls context structure"); 102 return STATUS_ERR; 103 } 104 105 /* 106 * Return the length in bytes for the MLS fields of the 107 * security context string representation of `context'. 108 */ 109 int mls_compute_context_len(const policydb_t * policydb, 110 const context_struct_t * context) 111 { 112 113 unsigned int i, l, len, range; 114 ebitmap_node_t *cnode; 115 116 if (!policydb->mls) 117 return 0; 118 119 len = 1; /* for the beginning ":" */ 120 for (l = 0; l < 2; l++) { 121 range = 0; 122 len += 123 strlen(policydb-> 124 p_sens_val_to_name[context->range.level[l].sens - 125 1]); 126 127 ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) { 128 if (ebitmap_node_get_bit(cnode, i)) { 129 if (range) { 130 range++; 131 continue; 132 } 133 134 len += 135 strlen(policydb->p_cat_val_to_name[i]) + 1; 136 range++; 137 } else { 138 if (range > 1) 139 len += 140 strlen(policydb-> 141 p_cat_val_to_name[i - 1]) + 142 1; 143 range = 0; 144 } 145 } 146 /* Handle case where last category is the end of range */ 147 if (range > 1) 148 len += strlen(policydb->p_cat_val_to_name[i - 1]) + 1; 149 150 if (l == 0) { 151 if (mls_level_eq(&context->range.level[0], 152 &context->range.level[1])) 153 break; 154 else 155 len++; 156 } 157 } 158 159 return len; 160 } 161 162 /* 163 * Write the security context string representation of 164 * the MLS fields of `context' into the string `*scontext'. 165 * Update `*scontext' to point to the end of the MLS fields. 166 */ 167 void mls_sid_to_context(const policydb_t * policydb, 168 const context_struct_t * context, char **scontext) 169 { 170 171 char *scontextp; 172 unsigned int i, l, range, wrote_sep; 173 ebitmap_node_t *cnode; 174 175 if (!policydb->mls) 176 return; 177 178 scontextp = *scontext; 179 180 *scontextp = ':'; 181 scontextp++; 182 183 for (l = 0; l < 2; l++) { 184 range = 0; 185 wrote_sep = 0; 186 strcpy(scontextp, 187 policydb->p_sens_val_to_name[context->range.level[l]. 188 sens - 1]); 189 scontextp += 190 strlen(policydb-> 191 p_sens_val_to_name[context->range.level[l].sens - 192 1]); 193 /* categories */ 194 ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) { 195 if (ebitmap_node_get_bit(cnode, i)) { 196 if (range) { 197 range++; 198 continue; 199 } 200 201 if (!wrote_sep) { 202 *scontextp++ = ':'; 203 wrote_sep = 1; 204 } else 205 *scontextp++ = ','; 206 strcpy(scontextp, 207 policydb->p_cat_val_to_name[i]); 208 scontextp += 209 strlen(policydb->p_cat_val_to_name[i]); 210 range++; 211 } else { 212 if (range > 1) { 213 if (range > 2) 214 *scontextp++ = '.'; 215 else 216 *scontextp++ = ','; 217 218 strcpy(scontextp, 219 policydb->p_cat_val_to_name[i - 220 1]); 221 scontextp += 222 strlen(policydb-> 223 p_cat_val_to_name[i - 1]); 224 } 225 range = 0; 226 } 227 } 228 /* Handle case where last category is the end of range */ 229 if (range > 1) { 230 if (range > 2) 231 *scontextp++ = '.'; 232 else 233 *scontextp++ = ','; 234 235 strcpy(scontextp, policydb->p_cat_val_to_name[i - 1]); 236 scontextp += strlen(policydb->p_cat_val_to_name[i - 1]); 237 } 238 239 if (l == 0) { 240 if (mls_level_eq(&context->range.level[0], 241 &context->range.level[1])) 242 break; 243 else { 244 *scontextp = '-'; 245 scontextp++; 246 } 247 } 248 } 249 250 *scontext = scontextp; 251 return; 252 } 253 254 /* 255 * Return 1 if the MLS fields in the security context 256 * structure `c' are valid. Return 0 otherwise. 257 */ 258 int mls_context_isvalid(const policydb_t * p, const context_struct_t * c) 259 { 260 261 level_datum_t *levdatum; 262 user_datum_t *usrdatum; 263 unsigned int i, l; 264 ebitmap_node_t *cnode; 265 266 if (!p->mls) 267 return 1; 268 269 /* 270 * MLS range validity checks: high must dominate low, low level must 271 * be valid (category set <-> sensitivity check), and high level must 272 * be valid (category set <-> sensitivity check) 273 */ 274 if (!mls_level_dom(&c->range.level[1], &c->range.level[0])) 275 /* High does not dominate low. */ 276 return 0; 277 278 for (l = 0; l < 2; l++) { 279 if (!c->range.level[l].sens 280 || c->range.level[l].sens > p->p_levels.nprim) 281 return 0; 282 levdatum = (level_datum_t *) hashtab_search(p->p_levels.table, 283 p-> 284 p_sens_val_to_name 285 [c->range.level[l]. 286 sens - 1]); 287 if (!levdatum) 288 return 0; 289 290 ebitmap_for_each_bit(&c->range.level[l].cat, cnode, i) { 291 if (ebitmap_node_get_bit(cnode, i)) { 292 if (i > p->p_cats.nprim) 293 return 0; 294 if (!ebitmap_get_bit(&levdatum->level->cat, i)) 295 /* 296 * Category may not be associated with 297 * sensitivity in low level. 298 */ 299 return 0; 300 } 301 } 302 } 303 304 if (c->role == OBJECT_R_VAL) 305 return 1; 306 307 /* 308 * User must be authorized for the MLS range. 309 */ 310 if (!c->user || c->user > p->p_users.nprim) 311 return 0; 312 usrdatum = p->user_val_to_struct[c->user - 1]; 313 if (!mls_range_contains(usrdatum->exp_range, c->range)) 314 return 0; /* user may not be associated with range */ 315 316 return 1; 317 } 318 319 /* 320 * Set the MLS fields in the security context structure 321 * `context' based on the string representation in 322 * the string `*scontext'. Update `*scontext' to 323 * point to the end of the string representation of 324 * the MLS fields. 325 * 326 * This function modifies the string in place, inserting 327 * NULL characters to terminate the MLS fields. 328 */ 329 int mls_context_to_sid(const policydb_t * policydb, 330 char oldc, char **scontext, context_struct_t * context) 331 { 332 333 char delim; 334 char *scontextp, *p, *rngptr; 335 level_datum_t *levdatum; 336 cat_datum_t *catdatum, *rngdatum; 337 unsigned int l; 338 339 if (!policydb->mls) 340 return 0; 341 342 /* No MLS component to the security context */ 343 if (!oldc) 344 goto err; 345 346 /* Extract low sensitivity. */ 347 scontextp = p = *scontext; 348 while (*p && *p != ':' && *p != '-') 349 p++; 350 351 delim = *p; 352 if (delim != 0) 353 *p++ = 0; 354 355 for (l = 0; l < 2; l++) { 356 levdatum = 357 (level_datum_t *) hashtab_search(policydb->p_levels.table, 358 (hashtab_key_t) scontextp); 359 360 if (!levdatum) 361 goto err; 362 363 context->range.level[l].sens = levdatum->level->sens; 364 365 if (delim == ':') { 366 /* Extract category set. */ 367 while (1) { 368 scontextp = p; 369 while (*p && *p != ',' && *p != '-') 370 p++; 371 delim = *p; 372 if (delim != 0) 373 *p++ = 0; 374 375 /* Separate into range if exists */ 376 if ((rngptr = strchr(scontextp, '.')) != NULL) { 377 /* Remove '.' */ 378 *rngptr++ = 0; 379 } 380 381 catdatum = 382 (cat_datum_t *) hashtab_search(policydb-> 383 p_cats.table, 384 (hashtab_key_t) 385 scontextp); 386 if (!catdatum) 387 goto err; 388 389 if (ebitmap_set_bit 390 (&context->range.level[l].cat, 391 catdatum->s.value - 1, 1)) 392 goto err; 393 394 /* If range, set all categories in range */ 395 if (rngptr) { 396 unsigned int i; 397 398 rngdatum = (cat_datum_t *) 399 hashtab_search(policydb->p_cats. 400 table, 401 (hashtab_key_t) 402 rngptr); 403 if (!rngdatum) 404 goto err; 405 406 if (catdatum->s.value >= 407 rngdatum->s.value) 408 goto err; 409 410 for (i = catdatum->s.value; 411 i < rngdatum->s.value; i++) { 412 if (ebitmap_set_bit 413 (&context->range.level[l]. 414 cat, i, 1)) 415 goto err; 416 } 417 } 418 419 if (delim != ',') 420 break; 421 } 422 } 423 if (delim == '-') { 424 /* Extract high sensitivity. */ 425 scontextp = p; 426 while (*p && *p != ':') 427 p++; 428 429 delim = *p; 430 if (delim != 0) 431 *p++ = 0; 432 } else 433 break; 434 } 435 436 /* High level is missing, copy low level */ 437 if (l == 0) { 438 if (mls_level_cpy(&context->range.level[1], 439 &context->range.level[0]) < 0) 440 goto err; 441 } 442 *scontext = ++p; 443 444 return STATUS_SUCCESS; 445 446 err: 447 return STATUS_ERR; 448 } 449 450 /* 451 * Copies the MLS range from `src' into `dst'. 452 */ 453 static inline int mls_copy_context(context_struct_t * dst, 454 context_struct_t * src) 455 { 456 int l, rc = 0; 457 458 /* Copy the MLS range from the source context */ 459 for (l = 0; l < 2; l++) { 460 dst->range.level[l].sens = src->range.level[l].sens; 461 rc = ebitmap_cpy(&dst->range.level[l].cat, 462 &src->range.level[l].cat); 463 if (rc) 464 break; 465 } 466 467 return rc; 468 } 469 470 /* 471 * Copies the effective MLS range from `src' into `dst'. 472 */ 473 static inline int mls_scopy_context(context_struct_t * dst, 474 context_struct_t * src) 475 { 476 int l, rc = 0; 477 478 /* Copy the MLS range from the source context */ 479 for (l = 0; l < 2; l++) { 480 dst->range.level[l].sens = src->range.level[0].sens; 481 rc = ebitmap_cpy(&dst->range.level[l].cat, 482 &src->range.level[0].cat); 483 if (rc) 484 break; 485 } 486 487 return rc; 488 } 489 490 /* 491 * Copies the MLS range `range' into `context'. 492 */ 493 static inline int mls_range_set(context_struct_t * context, mls_range_t * range) 494 { 495 int l, rc = 0; 496 497 /* Copy the MLS range into the context */ 498 for (l = 0; l < 2; l++) { 499 context->range.level[l].sens = range->level[l].sens; 500 rc = ebitmap_cpy(&context->range.level[l].cat, 501 &range->level[l].cat); 502 if (rc) 503 break; 504 } 505 506 return rc; 507 } 508 509 int mls_setup_user_range(context_struct_t * fromcon, user_datum_t * user, 510 context_struct_t * usercon, int mls) 511 { 512 if (mls) { 513 mls_level_t *fromcon_sen = &(fromcon->range.level[0]); 514 mls_level_t *fromcon_clr = &(fromcon->range.level[1]); 515 mls_level_t *user_low = &(user->exp_range.level[0]); 516 mls_level_t *user_clr = &(user->exp_range.level[1]); 517 mls_level_t *user_def = &(user->exp_dfltlevel); 518 mls_level_t *usercon_sen = &(usercon->range.level[0]); 519 mls_level_t *usercon_clr = &(usercon->range.level[1]); 520 521 /* Honor the user's default level if we can */ 522 if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) { 523 *usercon_sen = *user_def; 524 } else if (mls_level_between(fromcon_sen, user_def, user_clr)) { 525 *usercon_sen = *fromcon_sen; 526 } else if (mls_level_between(fromcon_clr, user_low, user_def)) { 527 *usercon_sen = *user_low; 528 } else 529 return -EINVAL; 530 531 /* Lower the clearance of available contexts 532 if the clearance of "fromcon" is lower than 533 that of the user's default clearance (but 534 only if the "fromcon" clearance dominates 535 the user's computed sensitivity level) */ 536 if (mls_level_dom(user_clr, fromcon_clr)) { 537 *usercon_clr = *fromcon_clr; 538 } else if (mls_level_dom(fromcon_clr, user_clr)) { 539 *usercon_clr = *user_clr; 540 } else 541 return -EINVAL; 542 } 543 544 return 0; 545 } 546 547 /* 548 * Convert the MLS fields in the security context 549 * structure `c' from the values specified in the 550 * policy `oldp' to the values specified in the policy `newp'. 551 */ 552 int mls_convert_context(policydb_t * oldp, 553 policydb_t * newp, context_struct_t * c) 554 { 555 level_datum_t *levdatum; 556 cat_datum_t *catdatum; 557 ebitmap_t bitmap; 558 unsigned int l, i; 559 ebitmap_node_t *cnode; 560 561 if (!oldp->mls) 562 return 0; 563 564 for (l = 0; l < 2; l++) { 565 levdatum = 566 (level_datum_t *) hashtab_search(newp->p_levels.table, 567 oldp-> 568 p_sens_val_to_name[c-> 569 range. 570 level 571 [l]. 572 sens - 573 1]); 574 575 if (!levdatum) 576 return -EINVAL; 577 c->range.level[l].sens = levdatum->level->sens; 578 579 ebitmap_init(&bitmap); 580 ebitmap_for_each_bit(&c->range.level[l].cat, cnode, i) { 581 if (ebitmap_node_get_bit(cnode, i)) { 582 int rc; 583 584 catdatum = 585 (cat_datum_t *) hashtab_search(newp->p_cats. 586 table, 587 oldp-> 588 p_cat_val_to_name 589 [i]); 590 if (!catdatum) 591 return -EINVAL; 592 rc = ebitmap_set_bit(&bitmap, 593 catdatum->s.value - 1, 1); 594 if (rc) 595 return rc; 596 } 597 } 598 ebitmap_destroy(&c->range.level[l].cat); 599 c->range.level[l].cat = bitmap; 600 } 601 602 return 0; 603 } 604 605 int mls_compute_sid(policydb_t * policydb, 606 context_struct_t * scontext, 607 context_struct_t * tcontext, 608 sepol_security_class_t tclass, 609 uint32_t specified, context_struct_t * newcontext) 610 { 611 range_trans_t *rtr; 612 if (!policydb->mls) 613 return 0; 614 615 switch (specified) { 616 case AVTAB_TRANSITION: 617 /* Look for a range transition rule. */ 618 for (rtr = policydb->range_tr; rtr; rtr = rtr->next) { 619 if (rtr->source_type == scontext->type && 620 rtr->target_type == tcontext->type && 621 rtr->target_class == tclass) { 622 /* Set the range from the rule */ 623 return mls_range_set(newcontext, 624 &rtr->target_range); 625 } 626 } 627 /* Fallthrough */ 628 case AVTAB_CHANGE: 629 if (tclass == SECCLASS_PROCESS) 630 /* Use the process MLS attributes. */ 631 return mls_copy_context(newcontext, scontext); 632 else 633 /* Use the process effective MLS attributes. */ 634 return mls_scopy_context(newcontext, scontext); 635 case AVTAB_MEMBER: 636 /* Only polyinstantiate the MLS attributes if 637 the type is being polyinstantiated */ 638 if (newcontext->type != tcontext->type) { 639 /* Use the process effective MLS attributes. */ 640 return mls_scopy_context(newcontext, scontext); 641 } else { 642 /* Use the related object MLS attributes. */ 643 return mls_copy_context(newcontext, tcontext); 644 } 645 default: 646 return -EINVAL; 647 } 648 return -EINVAL; 649 } 650 651 int sepol_mls_contains(sepol_handle_t * handle, 652 sepol_policydb_t * policydb, 653 const char *mls1, const char *mls2, int *response) 654 { 655 656 context_struct_t *ctx1 = NULL, *ctx2 = NULL; 657 ctx1 = malloc(sizeof(context_struct_t)); 658 ctx2 = malloc(sizeof(context_struct_t)); 659 if (ctx1 == NULL || ctx2 == NULL) 660 goto omem; 661 context_init(ctx1); 662 context_init(ctx2); 663 664 if (mls_from_string(handle, &policydb->p, mls1, ctx1) < 0) 665 goto err; 666 667 if (mls_from_string(handle, &policydb->p, mls2, ctx2) < 0) 668 goto err; 669 670 *response = mls_range_contains(ctx1->range, ctx2->range); 671 context_destroy(ctx1); 672 context_destroy(ctx2); 673 free(ctx1); 674 free(ctx2); 675 return STATUS_SUCCESS; 676 677 omem: 678 ERR(handle, "out of memory"); 679 680 err: 681 ERR(handle, "could not check if mls context %s contains %s", 682 mls1, mls2); 683 context_destroy(ctx1); 684 context_destroy(ctx2); 685 free(ctx1); 686 free(ctx2); 687 return STATUS_ERR; 688 } 689 690 int sepol_mls_check(sepol_handle_t * handle, 691 sepol_policydb_t * policydb, const char *mls) 692 { 693 694 int ret; 695 context_struct_t *con = malloc(sizeof(context_struct_t)); 696 if (!con) { 697 ERR(handle, "out of memory, could not check if " 698 "mls context %s is valid", mls); 699 return STATUS_ERR; 700 } 701 context_init(con); 702 703 ret = mls_from_string(handle, &policydb->p, mls, con); 704 context_destroy(con); 705 free(con); 706 return ret; 707 } 708 709 void mls_semantic_cat_init(mls_semantic_cat_t * c) 710 { 711 memset(c, 0, sizeof(mls_semantic_cat_t)); 712 } 713 714 void mls_semantic_cat_destroy(mls_semantic_cat_t * c __attribute__ ((unused))) 715 { 716 /* it's currently a simple struct - really nothing to destroy */ 717 return; 718 } 719 720 void mls_semantic_level_init(mls_semantic_level_t * l) 721 { 722 memset(l, 0, sizeof(mls_semantic_level_t)); 723 } 724 725 void mls_semantic_level_destroy(mls_semantic_level_t * l) 726 { 727 mls_semantic_cat_t *cur, *next; 728 729 if (l == NULL) 730 return; 731 732 next = l->cat; 733 while (next) { 734 cur = next; 735 next = cur->next; 736 mls_semantic_cat_destroy(cur); 737 free(cur); 738 } 739 } 740 741 int mls_semantic_level_cpy(mls_semantic_level_t * dst, 742 mls_semantic_level_t * src) 743 { 744 mls_semantic_cat_t *cat, *newcat, *lnewcat = NULL; 745 746 mls_semantic_level_init(dst); 747 dst->sens = src->sens; 748 cat = src->cat; 749 while (cat) { 750 newcat = 751 (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t)); 752 if (!newcat) 753 goto err; 754 755 mls_semantic_cat_init(newcat); 756 if (lnewcat) 757 lnewcat->next = newcat; 758 else 759 dst->cat = newcat; 760 761 newcat->low = cat->low; 762 newcat->high = cat->high; 763 764 lnewcat = newcat; 765 cat = cat->next; 766 } 767 return 0; 768 769 err: 770 mls_semantic_level_destroy(dst); 771 return -1; 772 } 773 774 void mls_semantic_range_init(mls_semantic_range_t * r) 775 { 776 mls_semantic_level_init(&r->level[0]); 777 mls_semantic_level_init(&r->level[1]); 778 } 779 780 void mls_semantic_range_destroy(mls_semantic_range_t * r) 781 { 782 mls_semantic_level_destroy(&r->level[0]); 783 mls_semantic_level_destroy(&r->level[1]); 784 } 785 786 int mls_semantic_range_cpy(mls_semantic_range_t * dst, 787 mls_semantic_range_t * src) 788 { 789 if (mls_semantic_level_cpy(&dst->level[0], &src->level[0]) < 0) 790 return -1; 791 792 if (mls_semantic_level_cpy(&dst->level[1], &src->level[1]) < 0) { 793 mls_semantic_level_destroy(&dst->level[0]); 794 return -1; 795 } 796 797 return 0; 798 } 799