1/* Author : Stephen Smalley, <sds@tycho.nsa.gov> */ 2/* 3 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@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/context.h> 31#include <sepol/policydb/policydb.h> 32#include <sepol/policydb/services.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 42int 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 78int 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 */ 109int 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 */ 167void 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 */ 258int 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 hashtab_key_t key; 266 267 if (!p->mls) 268 return 1; 269 270 /* 271 * MLS range validity checks: high must dominate low, low level must 272 * be valid (category set <-> sensitivity check), and high level must 273 * be valid (category set <-> sensitivity check) 274 */ 275 if (!mls_level_dom(&c->range.level[1], &c->range.level[0])) 276 /* High does not dominate low. */ 277 return 0; 278 279 for (l = 0; l < 2; l++) { 280 if (!c->range.level[l].sens 281 || c->range.level[l].sens > p->p_levels.nprim) 282 return 0; 283 284 key = p->p_sens_val_to_name[c->range.level[l].sens - 1]; 285 if (!key) 286 return 0; 287 288 levdatum = (level_datum_t *) hashtab_search(p->p_levels.table, key); 289 if (!levdatum) 290 return 0; 291 292 ebitmap_for_each_positive_bit(&c->range.level[l].cat, cnode, i) { 293 if (i > p->p_cats.nprim) 294 return 0; 295 if (!ebitmap_get_bit(&levdatum->level->cat, i)) 296 /* 297 * Category may not be associated with 298 * sensitivity in low level. 299 */ 300 return 0; 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 (!usrdatum || !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 */ 329int 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 */ 453static inline int mls_copy_context(context_struct_t * dst, 454 const 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 */ 473static inline int mls_scopy_context(context_struct_t * dst, 474 const 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 */ 493static inline int mls_range_set(context_struct_t * context, const 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 509int 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 */ 552int 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_positive_bit(&c->range.level[l].cat, cnode, i) { 581 int rc; 582 583 catdatum = 584 (cat_datum_t *) hashtab_search(newp->p_cats. 585 table, 586 oldp-> 587 p_cat_val_to_name 588 [i]); 589 if (!catdatum) 590 return -EINVAL; 591 rc = ebitmap_set_bit(&bitmap, 592 catdatum->s.value - 1, 1); 593 if (rc) 594 return rc; 595 } 596 ebitmap_destroy(&c->range.level[l].cat); 597 c->range.level[l].cat = bitmap; 598 } 599 600 return 0; 601} 602 603int mls_compute_sid(policydb_t * policydb, 604 const context_struct_t * scontext, 605 const context_struct_t * tcontext, 606 sepol_security_class_t tclass, 607 uint32_t specified, context_struct_t * newcontext) 608{ 609 range_trans_t rtr; 610 struct mls_range *r; 611 struct class_datum *cladatum; 612 int default_range = 0; 613 614 if (!policydb->mls) 615 return 0; 616 617 switch (specified) { 618 case AVTAB_TRANSITION: 619 /* Look for a range transition rule. */ 620 rtr.source_type = scontext->type; 621 rtr.target_type = tcontext->type; 622 rtr.target_class = tclass; 623 r = hashtab_search(policydb->range_tr, (hashtab_key_t) &rtr); 624 if (r) 625 return mls_range_set(newcontext, r); 626 627 if (tclass && tclass <= policydb->p_classes.nprim) { 628 cladatum = policydb->class_val_to_struct[tclass - 1]; 629 if (cladatum) 630 default_range = cladatum->default_range; 631 } 632 633 switch (default_range) { 634 case DEFAULT_SOURCE_LOW: 635 return mls_context_cpy_low(newcontext, scontext); 636 case DEFAULT_SOURCE_HIGH: 637 return mls_context_cpy_high(newcontext, scontext); 638 case DEFAULT_SOURCE_LOW_HIGH: 639 return mls_context_cpy(newcontext, scontext); 640 case DEFAULT_TARGET_LOW: 641 return mls_context_cpy_low(newcontext, tcontext); 642 case DEFAULT_TARGET_HIGH: 643 return mls_context_cpy_high(newcontext, tcontext); 644 case DEFAULT_TARGET_LOW_HIGH: 645 return mls_context_cpy(newcontext, tcontext); 646 case DEFAULT_GLBLUB: 647 return mls_context_glblub(newcontext, scontext, tcontext); 648 } 649 650 /* Fallthrough */ 651 case AVTAB_CHANGE: 652 if (tclass == policydb->process_class) 653 /* Use the process MLS attributes. */ 654 return mls_copy_context(newcontext, scontext); 655 else 656 /* Use the process effective MLS attributes. */ 657 return mls_scopy_context(newcontext, scontext); 658 case AVTAB_MEMBER: 659 /* Use the process effective MLS attributes. */ 660 return mls_context_cpy_low(newcontext, scontext); 661 default: 662 return -EINVAL; 663 } 664 return -EINVAL; 665} 666 667int sepol_mls_contains(sepol_handle_t * handle, 668 const sepol_policydb_t * policydb, 669 const char *mls1, const char *mls2, int *response) 670{ 671 672 context_struct_t *ctx1 = NULL, *ctx2 = NULL; 673 ctx1 = malloc(sizeof(context_struct_t)); 674 ctx2 = malloc(sizeof(context_struct_t)); 675 if (ctx1 == NULL || ctx2 == NULL) 676 goto omem; 677 context_init(ctx1); 678 context_init(ctx2); 679 680 if (mls_from_string(handle, &policydb->p, mls1, ctx1) < 0) 681 goto err; 682 683 if (mls_from_string(handle, &policydb->p, mls2, ctx2) < 0) 684 goto err; 685 686 *response = mls_range_contains(ctx1->range, ctx2->range); 687 context_destroy(ctx1); 688 context_destroy(ctx2); 689 free(ctx1); 690 free(ctx2); 691 return STATUS_SUCCESS; 692 693 omem: 694 ERR(handle, "out of memory"); 695 696 err: 697 ERR(handle, "could not check if mls context %s contains %s", 698 mls1, mls2); 699 context_destroy(ctx1); 700 context_destroy(ctx2); 701 free(ctx1); 702 free(ctx2); 703 return STATUS_ERR; 704} 705 706int sepol_mls_check(sepol_handle_t * handle, 707 const sepol_policydb_t * policydb, const char *mls) 708{ 709 710 int ret; 711 context_struct_t *con = malloc(sizeof(context_struct_t)); 712 if (!con) { 713 ERR(handle, "out of memory, could not check if " 714 "mls context %s is valid", mls); 715 return STATUS_ERR; 716 } 717 context_init(con); 718 719 ret = mls_from_string(handle, &policydb->p, mls, con); 720 context_destroy(con); 721 free(con); 722 return ret; 723} 724 725void mls_semantic_cat_init(mls_semantic_cat_t * c) 726{ 727 memset(c, 0, sizeof(mls_semantic_cat_t)); 728} 729 730void mls_semantic_cat_destroy(mls_semantic_cat_t * c __attribute__ ((unused))) 731{ 732 /* it's currently a simple struct - really nothing to destroy */ 733 return; 734} 735 736void mls_semantic_level_init(mls_semantic_level_t * l) 737{ 738 memset(l, 0, sizeof(mls_semantic_level_t)); 739} 740 741void mls_semantic_level_destroy(mls_semantic_level_t * l) 742{ 743 mls_semantic_cat_t *cur, *next; 744 745 if (l == NULL) 746 return; 747 748 next = l->cat; 749 while (next) { 750 cur = next; 751 next = cur->next; 752 mls_semantic_cat_destroy(cur); 753 free(cur); 754 } 755} 756 757int mls_semantic_level_cpy(mls_semantic_level_t * dst, 758 const mls_semantic_level_t * src) 759{ 760 const mls_semantic_cat_t *cat; 761 mls_semantic_cat_t *newcat, *lnewcat = NULL; 762 763 mls_semantic_level_init(dst); 764 dst->sens = src->sens; 765 cat = src->cat; 766 while (cat) { 767 newcat = 768 (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t)); 769 if (!newcat) 770 goto err; 771 772 mls_semantic_cat_init(newcat); 773 if (lnewcat) 774 lnewcat->next = newcat; 775 else 776 dst->cat = newcat; 777 778 newcat->low = cat->low; 779 newcat->high = cat->high; 780 781 lnewcat = newcat; 782 cat = cat->next; 783 } 784 return 0; 785 786 err: 787 mls_semantic_level_destroy(dst); 788 return -1; 789} 790 791void mls_semantic_range_init(mls_semantic_range_t * r) 792{ 793 mls_semantic_level_init(&r->level[0]); 794 mls_semantic_level_init(&r->level[1]); 795} 796 797void mls_semantic_range_destroy(mls_semantic_range_t * r) 798{ 799 mls_semantic_level_destroy(&r->level[0]); 800 mls_semantic_level_destroy(&r->level[1]); 801} 802 803int mls_semantic_range_cpy(mls_semantic_range_t * dst, 804 const mls_semantic_range_t * src) 805{ 806 if (mls_semantic_level_cpy(&dst->level[0], &src->level[0]) < 0) 807 return -1; 808 809 if (mls_semantic_level_cpy(&dst->level[1], &src->level[1]) < 0) { 810 mls_semantic_level_destroy(&dst->level[0]); 811 return -1; 812 } 813 814 return 0; 815} 816