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 164 if (!l->sens || l->sens > p->p_levels.nprim) 165 return false; 166 167 name = sym_name(p, SYM_LEVELS, l->sens - 1); 168 if (!name) 169 return false; 170 171 levdatum = symtab_search(&p->p_levels, name); 172 if (!levdatum) 173 return false; 174 175 /* 176 * l is valid iff every bit in l->cat is set in levdatum->level.cat 177 * and no bit in l->cat is larger than p->p_cats.nprim. 178 * policydb_index() has already verified that every bit set in 179 * levdatum->level.cat names a defined category, so containment is 180 * sufficient here. 181 */ 182 return ebitmap_contains(&levdatum->level.cat, &l->cat, 183 p->p_cats.nprim); 184 } 185 186 bool mls_range_isvalid(const struct policydb *p, const struct mls_range *r) 187 { 188 return (mls_level_isvalid(p, &r->level[0]) && 189 mls_level_isvalid(p, &r->level[1]) && 190 mls_level_dom(&r->level[1], &r->level[0])); 191 } 192 193 /* 194 * Return true if the MLS fields in the security context 195 * structure `c' are valid. Return 0 otherwise. 196 */ 197 bool mls_context_isvalid(const struct policydb *p, const struct context *c) 198 { 199 const struct user_datum *usrdatum; 200 201 if (!p->mls_enabled) 202 return true; 203 204 if (!mls_range_isvalid(p, &c->range)) 205 return false; 206 207 if (c->role == OBJECT_R_VAL) 208 return true; 209 210 /* 211 * User must be authorized for the MLS range. 212 */ 213 if (!c->user || c->user > p->p_users.nprim) 214 return false; 215 usrdatum = p->user_val_to_struct[c->user - 1]; 216 if (!usrdatum || !mls_range_contains(usrdatum->range, c->range)) 217 return false; /* user may not be associated with range */ 218 219 return true; 220 } 221 222 /* 223 * Set the MLS fields in the security context structure 224 * `context' based on the string representation in 225 * the string `scontext'. 226 * 227 * This function modifies the string in place, inserting 228 * NULL characters to terminate the MLS fields. 229 * 230 * If a def_sid is provided and no MLS field is present, 231 * copy the MLS field of the associated default context. 232 * Used for upgraded to MLS systems where objects may lack 233 * MLS fields. 234 * 235 * Policy read-lock must be held for sidtab lookup. 236 * 237 */ 238 int mls_context_to_sid(struct policydb *pol, char oldc, char *scontext, 239 struct context *context, struct sidtab *s, u32 def_sid) 240 { 241 char *sensitivity, *cur_cat, *next_cat, *rngptr; 242 struct level_datum *levdatum; 243 struct cat_datum *catdatum, *rngdatum; 244 u32 i; 245 int l, rc; 246 char *rangep[2]; 247 248 if (!pol->mls_enabled) { 249 /* 250 * With no MLS, only return -EINVAL if there is a MLS field 251 * and it did not come from an xattr. 252 */ 253 if (oldc && def_sid == SECSID_NULL) 254 return -EINVAL; 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 return -EINVAL; 267 268 defcon = sidtab_search(s, def_sid); 269 if (!defcon) 270 return -EINVAL; 271 272 return mls_context_cpy(context, defcon); 273 } 274 275 /* 276 * If we're dealing with a range, figure out where the two parts 277 * of the range begin. 278 */ 279 rangep[0] = scontext; 280 rangep[1] = strchr(scontext, '-'); 281 if (rangep[1]) { 282 rangep[1][0] = '\0'; 283 rangep[1]++; 284 } 285 286 /* For each part of the range: */ 287 for (l = 0; l < 2; l++) { 288 /* Split sensitivity and category set. */ 289 sensitivity = rangep[l]; 290 if (sensitivity == NULL) 291 break; 292 next_cat = strchr(sensitivity, ':'); 293 if (next_cat) 294 *(next_cat++) = '\0'; 295 296 /* Parse sensitivity. */ 297 levdatum = symtab_search(&pol->p_levels, sensitivity); 298 if (!levdatum) 299 return -EINVAL; 300 context->range.level[l].sens = levdatum->level.sens; 301 302 /* Extract category set. */ 303 while (next_cat != NULL) { 304 cur_cat = next_cat; 305 next_cat = strchr(next_cat, ','); 306 if (next_cat != NULL) 307 *(next_cat++) = '\0'; 308 309 /* Separate into range if exists */ 310 rngptr = strchr(cur_cat, '.'); 311 if (rngptr != NULL) { 312 /* Remove '.' */ 313 *rngptr++ = '\0'; 314 } 315 316 catdatum = symtab_search(&pol->p_cats, cur_cat); 317 if (!catdatum) 318 return -EINVAL; 319 320 rc = ebitmap_set_bit(&context->range.level[l].cat, 321 catdatum->value - 1, 1); 322 if (rc) 323 return rc; 324 325 /* If range, set all categories in range */ 326 if (rngptr == NULL) 327 continue; 328 329 rngdatum = symtab_search(&pol->p_cats, rngptr); 330 if (!rngdatum) 331 return -EINVAL; 332 333 if (catdatum->value >= rngdatum->value) 334 return -EINVAL; 335 336 for (i = catdatum->value; i < rngdatum->value; i++) { 337 rc = ebitmap_set_bit( 338 &context->range.level[l].cat, i, 1); 339 if (rc) 340 return rc; 341 } 342 } 343 } 344 345 /* If we didn't see a '-', the range start is also the range end. */ 346 if (rangep[1] == NULL) { 347 context->range.level[1].sens = context->range.level[0].sens; 348 rc = ebitmap_cpy(&context->range.level[1].cat, 349 &context->range.level[0].cat); 350 if (rc) 351 return rc; 352 } 353 354 return 0; 355 } 356 357 /* 358 * Set the MLS fields in the security context structure 359 * `context' based on the string representation in 360 * the string `str'. This function will allocate temporary memory with the 361 * given constraints of gfp_mask. 362 */ 363 int mls_from_string(struct policydb *p, char *str, struct context *context, 364 gfp_t gfp_mask) 365 { 366 char *tmpstr; 367 int rc; 368 369 if (!p->mls_enabled) 370 return -EINVAL; 371 372 tmpstr = kstrdup(str, gfp_mask); 373 if (!tmpstr) { 374 rc = -ENOMEM; 375 } else { 376 rc = mls_context_to_sid(p, ':', tmpstr, context, NULL, 377 SECSID_NULL); 378 kfree(tmpstr); 379 } 380 381 return rc; 382 } 383 384 /* 385 * Copies the MLS range `range' into `context'. 386 */ 387 int mls_range_set(struct context *context, struct mls_range *range) 388 { 389 int l, rc = 0; 390 391 /* Copy the MLS range into the context */ 392 for (l = 0; l < 2; l++) { 393 context->range.level[l].sens = range->level[l].sens; 394 rc = ebitmap_cpy(&context->range.level[l].cat, 395 &range->level[l].cat); 396 if (rc) 397 break; 398 } 399 400 return rc; 401 } 402 403 /* 404 * Convert the MLS fields in the security context 405 * structure `oldc' from the values specified in the 406 * policy `oldp' to the values specified in the policy `newp', 407 * storing the resulting context in `newc'. 408 */ 409 int mls_convert_context(struct policydb *oldp, struct policydb *newp, 410 struct context *oldc, struct context *newc) 411 { 412 struct level_datum *levdatum; 413 struct cat_datum *catdatum; 414 struct ebitmap_node *node; 415 u32 i; 416 int l; 417 418 if (!oldp->mls_enabled || !newp->mls_enabled) 419 return 0; 420 421 for (l = 0; l < 2; l++) { 422 const char *name = sym_name(oldp, SYM_LEVELS, 423 oldc->range.level[l].sens - 1); 424 425 levdatum = symtab_search(&newp->p_levels, name); 426 427 if (!levdatum) 428 return -EINVAL; 429 newc->range.level[l].sens = levdatum->level.sens; 430 431 ebitmap_for_each_positive_bit(&oldc->range.level[l].cat, node, 432 i) 433 { 434 int rc; 435 436 catdatum = symtab_search(&newp->p_cats, 437 sym_name(oldp, SYM_CATS, i)); 438 if (!catdatum) 439 return -EINVAL; 440 rc = ebitmap_set_bit(&newc->range.level[l].cat, 441 catdatum->value - 1, 1); 442 if (rc) 443 return rc; 444 } 445 } 446 447 return 0; 448 } 449 450 int mls_compute_sid(struct policydb *p, struct context *scontext, 451 struct context *tcontext, u16 tclass, u32 specified, 452 struct context *newcontext, bool sock) 453 { 454 struct range_trans rtr; 455 struct mls_range *r; 456 struct class_datum *cladatum; 457 char default_range = 0; 458 459 if (!p->mls_enabled) 460 return 0; 461 462 switch (specified) { 463 case AVTAB_TRANSITION: 464 /* Look for a range transition rule. */ 465 rtr.source_type = scontext->type; 466 rtr.target_type = tcontext->type; 467 rtr.target_class = tclass; 468 r = policydb_rangetr_search(p, &rtr); 469 if (r) 470 return mls_range_set(newcontext, r); 471 472 if (tclass && tclass <= p->p_classes.nprim) { 473 cladatum = p->class_val_to_struct[tclass - 1]; 474 if (cladatum) 475 default_range = cladatum->default_range; 476 } 477 478 switch (default_range) { 479 case DEFAULT_SOURCE_LOW: 480 return mls_context_cpy_low(newcontext, scontext); 481 case DEFAULT_SOURCE_HIGH: 482 return mls_context_cpy_high(newcontext, scontext); 483 case DEFAULT_SOURCE_LOW_HIGH: 484 return mls_context_cpy(newcontext, scontext); 485 case DEFAULT_TARGET_LOW: 486 return mls_context_cpy_low(newcontext, tcontext); 487 case DEFAULT_TARGET_HIGH: 488 return mls_context_cpy_high(newcontext, tcontext); 489 case DEFAULT_TARGET_LOW_HIGH: 490 return mls_context_cpy(newcontext, tcontext); 491 case DEFAULT_GLBLUB: 492 return mls_context_glblub(newcontext, scontext, 493 tcontext); 494 } 495 496 fallthrough; 497 case AVTAB_CHANGE: 498 if ((tclass == p->process_class) || sock) 499 /* Use the process MLS attributes. */ 500 return mls_context_cpy(newcontext, scontext); 501 else 502 /* Use the process effective MLS attributes. */ 503 return mls_context_cpy_low(newcontext, scontext); 504 case AVTAB_MEMBER: 505 /* Use the process effective MLS attributes. */ 506 return mls_context_cpy_low(newcontext, scontext); 507 } 508 return -EINVAL; 509 } 510 511 #ifdef CONFIG_NETLABEL 512 /** 513 * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel 514 * @p: the policy 515 * @context: the security context 516 * @secattr: the NetLabel security attributes 517 * 518 * Description: 519 * Given the security context copy the low MLS sensitivity level into the 520 * NetLabel MLS sensitivity level field. 521 * 522 */ 523 void mls_export_netlbl_lvl(struct policydb *p, struct context *context, 524 struct netlbl_lsm_secattr *secattr) 525 { 526 if (!p->mls_enabled) 527 return; 528 529 secattr->attr.mls.lvl = context->range.level[0].sens - 1; 530 secattr->flags |= NETLBL_SECATTR_MLS_LVL; 531 } 532 533 /** 534 * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels 535 * @p: the policy 536 * @context: the security context 537 * @secattr: the NetLabel security attributes 538 * 539 * Description: 540 * Given the security context and the NetLabel security attributes, copy the 541 * NetLabel MLS sensitivity level into the context. 542 * 543 */ 544 void mls_import_netlbl_lvl(struct policydb *p, struct context *context, 545 struct netlbl_lsm_secattr *secattr) 546 { 547 if (!p->mls_enabled) 548 return; 549 550 context->range.level[0].sens = secattr->attr.mls.lvl + 1; 551 context->range.level[1].sens = context->range.level[0].sens; 552 } 553 554 /** 555 * mls_export_netlbl_cat - Export the MLS categories to NetLabel 556 * @p: the policy 557 * @context: the security context 558 * @secattr: the NetLabel security attributes 559 * 560 * Description: 561 * Given the security context copy the low MLS categories into the NetLabel 562 * MLS category field. Returns zero on success, negative values on failure. 563 * 564 */ 565 int mls_export_netlbl_cat(struct policydb *p, struct context *context, 566 struct netlbl_lsm_secattr *secattr) 567 { 568 int rc; 569 570 if (!p->mls_enabled) 571 return 0; 572 573 rc = ebitmap_netlbl_export(&context->range.level[0].cat, 574 &secattr->attr.mls.cat); 575 if (rc == 0 && secattr->attr.mls.cat != NULL) 576 secattr->flags |= NETLBL_SECATTR_MLS_CAT; 577 578 return rc; 579 } 580 581 /** 582 * mls_import_netlbl_cat - Import the MLS categories from NetLabel 583 * @p: the policy 584 * @context: the security context 585 * @secattr: the NetLabel security attributes 586 * 587 * Description: 588 * Copy the NetLabel security attributes into the SELinux context; since the 589 * NetLabel security attribute only contains a single MLS category use it for 590 * both the low and high categories of the context. Returns zero on success, 591 * negative values on failure. 592 * 593 */ 594 int mls_import_netlbl_cat(struct policydb *p, struct context *context, 595 struct netlbl_lsm_secattr *secattr) 596 { 597 int rc; 598 599 if (!p->mls_enabled) 600 return 0; 601 602 rc = ebitmap_netlbl_import(&context->range.level[0].cat, 603 secattr->attr.mls.cat); 604 if (rc) 605 goto import_netlbl_cat_failure; 606 memcpy(&context->range.level[1].cat, &context->range.level[0].cat, 607 sizeof(context->range.level[0].cat)); 608 609 return 0; 610 611 import_netlbl_cat_failure: 612 ebitmap_destroy(&context->range.level[0].cat); 613 return rc; 614 } 615 #endif /* CONFIG_NETLABEL */ 616