1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Implementation of the multi-level security (MLS) policy. 4 * 5 * Author : Stephen Smalley, <stephen.smalley.work@gmail.com> 6 */ 7 8 /* 9 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> 10 * Support for enhanced MLS infrastructure. 11 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 12 * 13 * Updated: Hewlett-Packard <paul@paul-moore.com> 14 * Added support to import/export the MLS label from NetLabel 15 * Copyright (C) Hewlett-Packard Development Company, L.P., 2006 16 */ 17 18 #include <linux/kernel.h> 19 #include <linux/slab.h> 20 #include <linux/string.h> 21 #include <linux/errno.h> 22 #include <net/netlabel.h> 23 #include "sidtab.h" 24 #include "mls.h" 25 #include "policydb.h" 26 #include "services.h" 27 28 /* 29 * Return the length in bytes for the MLS fields of the 30 * security context string representation of `context'. 31 */ 32 int mls_compute_context_len(struct policydb *p, struct context *context) 33 { 34 int i, l, len, head, prev; 35 const char *nm; 36 struct ebitmap *e; 37 struct ebitmap_node *node; 38 39 if (!p->mls_enabled) 40 return 0; 41 42 len = 1; /* for the beginning ":" */ 43 for (l = 0; l < 2; l++) { 44 u32 index_sens = context->range.level[l].sens; 45 len += strlen(sym_name(p, SYM_LEVELS, index_sens - 1)); 46 47 /* categories */ 48 head = -2; 49 prev = -2; 50 e = &context->range.level[l].cat; 51 ebitmap_for_each_positive_bit(e, node, i) 52 { 53 if (i - prev > 1) { 54 /* one or more negative bits are skipped */ 55 if (head != prev) { 56 nm = sym_name(p, SYM_CATS, prev); 57 len += strlen(nm) + 1; 58 } 59 nm = sym_name(p, SYM_CATS, i); 60 len += strlen(nm) + 1; 61 head = i; 62 } 63 prev = i; 64 } 65 if (prev != head) { 66 nm = sym_name(p, SYM_CATS, prev); 67 len += strlen(nm) + 1; 68 } 69 if (l == 0) { 70 if (mls_level_eq(&context->range.level[0], 71 &context->range.level[1])) 72 break; 73 else 74 len++; 75 } 76 } 77 78 return len; 79 } 80 81 /* 82 * Write the security context string representation of 83 * the MLS fields of `context' into the string `*scontext'. 84 * Update `*scontext' to point to the end of the MLS fields. 85 */ 86 void mls_sid_to_context(struct policydb *p, struct context *context, 87 char **scontext) 88 { 89 const char *nm; 90 char *scontextp; 91 int i, l, head, prev; 92 struct ebitmap *e; 93 struct ebitmap_node *node; 94 95 if (!p->mls_enabled) 96 return; 97 98 scontextp = *scontext; 99 100 *scontextp = ':'; 101 scontextp++; 102 103 for (l = 0; l < 2; l++) { 104 strcpy(scontextp, sym_name(p, SYM_LEVELS, 105 context->range.level[l].sens - 1)); 106 scontextp += strlen(scontextp); 107 108 /* categories */ 109 head = -2; 110 prev = -2; 111 e = &context->range.level[l].cat; 112 ebitmap_for_each_positive_bit(e, node, i) 113 { 114 if (i - prev > 1) { 115 /* one or more negative bits are skipped */ 116 if (prev != head) { 117 if (prev - head > 1) 118 *scontextp++ = '.'; 119 else 120 *scontextp++ = ','; 121 nm = sym_name(p, SYM_CATS, prev); 122 strcpy(scontextp, nm); 123 scontextp += strlen(nm); 124 } 125 if (prev < 0) 126 *scontextp++ = ':'; 127 else 128 *scontextp++ = ','; 129 nm = sym_name(p, SYM_CATS, i); 130 strcpy(scontextp, nm); 131 scontextp += strlen(nm); 132 head = i; 133 } 134 prev = i; 135 } 136 137 if (prev != head) { 138 if (prev - head > 1) 139 *scontextp++ = '.'; 140 else 141 *scontextp++ = ','; 142 nm = sym_name(p, SYM_CATS, prev); 143 strcpy(scontextp, nm); 144 scontextp += strlen(nm); 145 } 146 147 if (l == 0) { 148 if (mls_level_eq(&context->range.level[0], 149 &context->range.level[1])) 150 break; 151 else 152 *scontextp++ = '-'; 153 } 154 } 155 156 *scontext = scontextp; 157 } 158 159 bool mls_level_isvalid(const struct policydb *p, const struct mls_level *l) 160 { 161 const char *name; 162 const struct level_datum *levdatum; 163 struct ebitmap_node *node; 164 u32 bit; 165 int rc; 166 167 if (!l->sens || l->sens > p->p_levels.nprim) 168 return false; 169 170 name = sym_name(p, SYM_LEVELS, l->sens - 1); 171 if (!name) 172 return false; 173 174 levdatum = symtab_search(&p->p_levels, name); 175 if (!levdatum) 176 return false; 177 178 /* 179 * Validate that all bits set in l->cat are also be set in 180 * levdatum->level->cat and no bit in l->cat is larger than 181 * p->p_cats.nprim. 182 */ 183 rc = ebitmap_contains(&levdatum->level.cat, &l->cat, 184 p->p_cats.nprim); 185 if (!rc) 186 return false; 187 188 ebitmap_for_each_positive_bit(&levdatum->level.cat, node, bit) { 189 if (!sym_name(p, SYM_CATS, bit)) 190 return false; 191 } 192 193 return true; 194 } 195 196 bool mls_range_isvalid(const struct policydb *p, const struct mls_range *r) 197 { 198 return (mls_level_isvalid(p, &r->level[0]) && 199 mls_level_isvalid(p, &r->level[1]) && 200 mls_level_dom(&r->level[1], &r->level[0])); 201 } 202 203 /* 204 * Return true if the MLS fields in the security context 205 * structure `c' are valid. Return 0 otherwise. 206 */ 207 bool mls_context_isvalid(const struct policydb *p, const struct context *c) 208 { 209 const struct user_datum *usrdatum; 210 211 if (!p->mls_enabled) 212 return true; 213 214 if (!mls_range_isvalid(p, &c->range)) 215 return false; 216 217 if (c->role == OBJECT_R_VAL) 218 return true; 219 220 /* 221 * User must be authorized for the MLS range. 222 */ 223 if (!c->user || c->user > p->p_users.nprim) 224 return false; 225 usrdatum = p->user_val_to_struct[c->user - 1]; 226 if (!usrdatum || !mls_range_contains(usrdatum->range, c->range)) 227 return false; /* user may not be associated with range */ 228 229 return true; 230 } 231 232 /* 233 * Set the MLS fields in the security context structure 234 * `context' based on the string representation in 235 * the string `scontext'. 236 * 237 * This function modifies the string in place, inserting 238 * NULL characters to terminate the MLS fields. 239 * 240 * If a def_sid is provided and no MLS field is present, 241 * copy the MLS field of the associated default context. 242 * Used for upgraded to MLS systems where objects may lack 243 * MLS fields. 244 * 245 * Policy read-lock must be held for sidtab lookup. 246 * 247 */ 248 int mls_context_to_sid(struct policydb *pol, char oldc, char *scontext, 249 struct context *context, struct sidtab *s, u32 def_sid) 250 { 251 char *sensitivity, *cur_cat, *next_cat, *rngptr; 252 struct level_datum *levdatum; 253 struct cat_datum *catdatum, *rngdatum; 254 u32 i; 255 int l, rc; 256 char *rangep[2]; 257 258 if (!pol->mls_enabled) { 259 /* 260 * With no MLS, only return -EINVAL if there is a MLS field 261 * and it did not come from an xattr. 262 */ 263 if (oldc && def_sid == SECSID_NULL) 264 return -EINVAL; 265 return 0; 266 } 267 268 /* 269 * No MLS component to the security context, try and map to 270 * default if provided. 271 */ 272 if (!oldc) { 273 struct context *defcon; 274 275 if (def_sid == SECSID_NULL) 276 return -EINVAL; 277 278 defcon = sidtab_search(s, def_sid); 279 if (!defcon) 280 return -EINVAL; 281 282 return mls_context_cpy(context, defcon); 283 } 284 285 /* 286 * If we're dealing with a range, figure out where the two parts 287 * of the range begin. 288 */ 289 rangep[0] = scontext; 290 rangep[1] = strchr(scontext, '-'); 291 if (rangep[1]) { 292 rangep[1][0] = '\0'; 293 rangep[1]++; 294 } 295 296 /* For each part of the range: */ 297 for (l = 0; l < 2; l++) { 298 /* Split sensitivity and category set. */ 299 sensitivity = rangep[l]; 300 if (sensitivity == NULL) 301 break; 302 next_cat = strchr(sensitivity, ':'); 303 if (next_cat) 304 *(next_cat++) = '\0'; 305 306 /* Parse sensitivity. */ 307 levdatum = symtab_search(&pol->p_levels, sensitivity); 308 if (!levdatum) 309 return -EINVAL; 310 context->range.level[l].sens = levdatum->level.sens; 311 312 /* Extract category set. */ 313 while (next_cat != NULL) { 314 cur_cat = next_cat; 315 next_cat = strchr(next_cat, ','); 316 if (next_cat != NULL) 317 *(next_cat++) = '\0'; 318 319 /* Separate into range if exists */ 320 rngptr = strchr(cur_cat, '.'); 321 if (rngptr != NULL) { 322 /* Remove '.' */ 323 *rngptr++ = '\0'; 324 } 325 326 catdatum = symtab_search(&pol->p_cats, cur_cat); 327 if (!catdatum) 328 return -EINVAL; 329 330 rc = ebitmap_set_bit(&context->range.level[l].cat, 331 catdatum->value - 1, 1); 332 if (rc) 333 return rc; 334 335 /* If range, set all categories in range */ 336 if (rngptr == NULL) 337 continue; 338 339 rngdatum = symtab_search(&pol->p_cats, rngptr); 340 if (!rngdatum) 341 return -EINVAL; 342 343 if (catdatum->value >= rngdatum->value) 344 return -EINVAL; 345 346 for (i = catdatum->value; i < rngdatum->value; i++) { 347 rc = ebitmap_set_bit( 348 &context->range.level[l].cat, i, 1); 349 if (rc) 350 return rc; 351 } 352 } 353 } 354 355 /* If we didn't see a '-', the range start is also the range end. */ 356 if (rangep[1] == NULL) { 357 context->range.level[1].sens = context->range.level[0].sens; 358 rc = ebitmap_cpy(&context->range.level[1].cat, 359 &context->range.level[0].cat); 360 if (rc) 361 return rc; 362 } 363 364 return 0; 365 } 366 367 /* 368 * Set the MLS fields in the security context structure 369 * `context' based on the string representation in 370 * the string `str'. This function will allocate temporary memory with the 371 * given constraints of gfp_mask. 372 */ 373 int mls_from_string(struct policydb *p, char *str, struct context *context, 374 gfp_t gfp_mask) 375 { 376 char *tmpstr; 377 int rc; 378 379 if (!p->mls_enabled) 380 return -EINVAL; 381 382 tmpstr = kstrdup(str, gfp_mask); 383 if (!tmpstr) { 384 rc = -ENOMEM; 385 } else { 386 rc = mls_context_to_sid(p, ':', tmpstr, context, NULL, 387 SECSID_NULL); 388 kfree(tmpstr); 389 } 390 391 return rc; 392 } 393 394 /* 395 * Copies the MLS range `range' into `context'. 396 */ 397 int mls_range_set(struct context *context, struct mls_range *range) 398 { 399 int l, rc = 0; 400 401 /* Copy the MLS range into the context */ 402 for (l = 0; l < 2; l++) { 403 context->range.level[l].sens = range->level[l].sens; 404 rc = ebitmap_cpy(&context->range.level[l].cat, 405 &range->level[l].cat); 406 if (rc) 407 break; 408 } 409 410 return rc; 411 } 412 413 int mls_setup_user_range(struct policydb *p, struct context *fromcon, 414 struct user_datum *user, struct context *usercon) 415 { 416 if (p->mls_enabled) { 417 struct mls_level *fromcon_sen = &(fromcon->range.level[0]); 418 struct mls_level *fromcon_clr = &(fromcon->range.level[1]); 419 struct mls_level *user_low = &(user->range.level[0]); 420 struct mls_level *user_clr = &(user->range.level[1]); 421 struct mls_level *user_def = &(user->dfltlevel); 422 struct mls_level *usercon_sen = &(usercon->range.level[0]); 423 struct mls_level *usercon_clr = &(usercon->range.level[1]); 424 425 /* Honor the user's default level if we can */ 426 if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) 427 *usercon_sen = *user_def; 428 else if (mls_level_between(fromcon_sen, user_def, user_clr)) 429 *usercon_sen = *fromcon_sen; 430 else if (mls_level_between(fromcon_clr, user_low, user_def)) 431 *usercon_sen = *user_low; 432 else 433 return -EINVAL; 434 435 /* Lower the clearance of available contexts 436 if the clearance of "fromcon" is lower than 437 that of the user's default clearance (but 438 only if the "fromcon" clearance dominates 439 the user's computed sensitivity level) */ 440 if (mls_level_dom(user_clr, fromcon_clr)) 441 *usercon_clr = *fromcon_clr; 442 else if (mls_level_dom(fromcon_clr, user_clr)) 443 *usercon_clr = *user_clr; 444 else 445 return -EINVAL; 446 } 447 448 return 0; 449 } 450 451 /* 452 * Convert the MLS fields in the security context 453 * structure `oldc' from the values specified in the 454 * policy `oldp' to the values specified in the policy `newp', 455 * storing the resulting context in `newc'. 456 */ 457 int mls_convert_context(struct policydb *oldp, struct policydb *newp, 458 struct context *oldc, struct context *newc) 459 { 460 struct level_datum *levdatum; 461 struct cat_datum *catdatum; 462 struct ebitmap_node *node; 463 u32 i; 464 int l; 465 466 if (!oldp->mls_enabled || !newp->mls_enabled) 467 return 0; 468 469 for (l = 0; l < 2; l++) { 470 const char *name = sym_name(oldp, SYM_LEVELS, 471 oldc->range.level[l].sens - 1); 472 473 levdatum = symtab_search(&newp->p_levels, name); 474 475 if (!levdatum) 476 return -EINVAL; 477 newc->range.level[l].sens = levdatum->level.sens; 478 479 ebitmap_for_each_positive_bit(&oldc->range.level[l].cat, node, 480 i) 481 { 482 int rc; 483 484 catdatum = symtab_search(&newp->p_cats, 485 sym_name(oldp, SYM_CATS, i)); 486 if (!catdatum) 487 return -EINVAL; 488 rc = ebitmap_set_bit(&newc->range.level[l].cat, 489 catdatum->value - 1, 1); 490 if (rc) 491 return rc; 492 } 493 } 494 495 return 0; 496 } 497 498 int mls_compute_sid(struct policydb *p, struct context *scontext, 499 struct context *tcontext, u16 tclass, u32 specified, 500 struct context *newcontext, bool sock) 501 { 502 struct range_trans rtr; 503 struct mls_range *r; 504 struct class_datum *cladatum; 505 char default_range = 0; 506 507 if (!p->mls_enabled) 508 return 0; 509 510 switch (specified) { 511 case AVTAB_TRANSITION: 512 /* Look for a range transition rule. */ 513 rtr.source_type = scontext->type; 514 rtr.target_type = tcontext->type; 515 rtr.target_class = tclass; 516 r = policydb_rangetr_search(p, &rtr); 517 if (r) 518 return mls_range_set(newcontext, r); 519 520 if (tclass && tclass <= p->p_classes.nprim) { 521 cladatum = p->class_val_to_struct[tclass - 1]; 522 if (cladatum) 523 default_range = cladatum->default_range; 524 } 525 526 switch (default_range) { 527 case DEFAULT_SOURCE_LOW: 528 return mls_context_cpy_low(newcontext, scontext); 529 case DEFAULT_SOURCE_HIGH: 530 return mls_context_cpy_high(newcontext, scontext); 531 case DEFAULT_SOURCE_LOW_HIGH: 532 return mls_context_cpy(newcontext, scontext); 533 case DEFAULT_TARGET_LOW: 534 return mls_context_cpy_low(newcontext, tcontext); 535 case DEFAULT_TARGET_HIGH: 536 return mls_context_cpy_high(newcontext, tcontext); 537 case DEFAULT_TARGET_LOW_HIGH: 538 return mls_context_cpy(newcontext, tcontext); 539 case DEFAULT_GLBLUB: 540 return mls_context_glblub(newcontext, scontext, 541 tcontext); 542 } 543 544 fallthrough; 545 case AVTAB_CHANGE: 546 if ((tclass == p->process_class) || sock) 547 /* Use the process MLS attributes. */ 548 return mls_context_cpy(newcontext, scontext); 549 else 550 /* Use the process effective MLS attributes. */ 551 return mls_context_cpy_low(newcontext, scontext); 552 case AVTAB_MEMBER: 553 /* Use the process effective MLS attributes. */ 554 return mls_context_cpy_low(newcontext, scontext); 555 } 556 return -EINVAL; 557 } 558 559 #ifdef CONFIG_NETLABEL 560 /** 561 * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel 562 * @p: the policy 563 * @context: the security context 564 * @secattr: the NetLabel security attributes 565 * 566 * Description: 567 * Given the security context copy the low MLS sensitivity level into the 568 * NetLabel MLS sensitivity level field. 569 * 570 */ 571 void mls_export_netlbl_lvl(struct policydb *p, struct context *context, 572 struct netlbl_lsm_secattr *secattr) 573 { 574 if (!p->mls_enabled) 575 return; 576 577 secattr->attr.mls.lvl = context->range.level[0].sens - 1; 578 secattr->flags |= NETLBL_SECATTR_MLS_LVL; 579 } 580 581 /** 582 * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels 583 * @p: the policy 584 * @context: the security context 585 * @secattr: the NetLabel security attributes 586 * 587 * Description: 588 * Given the security context and the NetLabel security attributes, copy the 589 * NetLabel MLS sensitivity level into the context. 590 * 591 */ 592 void mls_import_netlbl_lvl(struct policydb *p, struct context *context, 593 struct netlbl_lsm_secattr *secattr) 594 { 595 if (!p->mls_enabled) 596 return; 597 598 context->range.level[0].sens = secattr->attr.mls.lvl + 1; 599 context->range.level[1].sens = context->range.level[0].sens; 600 } 601 602 /** 603 * mls_export_netlbl_cat - Export the MLS categories to NetLabel 604 * @p: the policy 605 * @context: the security context 606 * @secattr: the NetLabel security attributes 607 * 608 * Description: 609 * Given the security context copy the low MLS categories into the NetLabel 610 * MLS category field. Returns zero on success, negative values on failure. 611 * 612 */ 613 int mls_export_netlbl_cat(struct policydb *p, struct context *context, 614 struct netlbl_lsm_secattr *secattr) 615 { 616 int rc; 617 618 if (!p->mls_enabled) 619 return 0; 620 621 rc = ebitmap_netlbl_export(&context->range.level[0].cat, 622 &secattr->attr.mls.cat); 623 if (rc == 0 && secattr->attr.mls.cat != NULL) 624 secattr->flags |= NETLBL_SECATTR_MLS_CAT; 625 626 return rc; 627 } 628 629 /** 630 * mls_import_netlbl_cat - Import the MLS categories from NetLabel 631 * @p: the policy 632 * @context: the security context 633 * @secattr: the NetLabel security attributes 634 * 635 * Description: 636 * Copy the NetLabel security attributes into the SELinux context; since the 637 * NetLabel security attribute only contains a single MLS category use it for 638 * both the low and high categories of the context. Returns zero on success, 639 * negative values on failure. 640 * 641 */ 642 int mls_import_netlbl_cat(struct policydb *p, struct context *context, 643 struct netlbl_lsm_secattr *secattr) 644 { 645 int rc; 646 647 if (!p->mls_enabled) 648 return 0; 649 650 rc = ebitmap_netlbl_import(&context->range.level[0].cat, 651 secattr->attr.mls.cat); 652 if (rc) 653 goto import_netlbl_cat_failure; 654 memcpy(&context->range.level[1].cat, &context->range.level[0].cat, 655 sizeof(context->range.level[0].cat)); 656 657 return 0; 658 659 import_netlbl_cat_failure: 660 ebitmap_destroy(&context->range.level[0].cat); 661 return rc; 662 } 663 #endif /* CONFIG_NETLABEL */ 664