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-2005 Trusted Computer Solutions, Inc. 12 */ 13 14 #include <linux/kernel.h> 15 #include <linux/slab.h> 16 #include <linux/string.h> 17 #include <linux/errno.h> 18 #include "sidtab.h" 19 #include "mls.h" 20 #include "policydb.h" 21 #include "services.h" 22 23 /* 24 * Return the length in bytes for the MLS fields of the 25 * security context string representation of `context'. 26 */ 27 int mls_compute_context_len(struct context * context) 28 { 29 int i, l, len, range; 30 struct ebitmap_node *node; 31 32 if (!selinux_mls_enabled) 33 return 0; 34 35 len = 1; /* for the beginning ":" */ 36 for (l = 0; l < 2; l++) { 37 range = 0; 38 len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); 39 40 ebitmap_for_each_bit(&context->range.level[l].cat, node, i) { 41 if (ebitmap_node_get_bit(node, i)) { 42 if (range) { 43 range++; 44 continue; 45 } 46 47 len += strlen(policydb.p_cat_val_to_name[i]) + 1; 48 range++; 49 } else { 50 if (range > 1) 51 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1; 52 range = 0; 53 } 54 } 55 /* Handle case where last category is the end of range */ 56 if (range > 1) 57 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1; 58 59 if (l == 0) { 60 if (mls_level_eq(&context->range.level[0], 61 &context->range.level[1])) 62 break; 63 else 64 len++; 65 } 66 } 67 68 return len; 69 } 70 71 /* 72 * Write the security context string representation of 73 * the MLS fields of `context' into the string `*scontext'. 74 * Update `*scontext' to point to the end of the MLS fields. 75 */ 76 void mls_sid_to_context(struct context *context, 77 char **scontext) 78 { 79 char *scontextp; 80 int i, l, range, wrote_sep; 81 struct ebitmap_node *node; 82 83 if (!selinux_mls_enabled) 84 return; 85 86 scontextp = *scontext; 87 88 *scontextp = ':'; 89 scontextp++; 90 91 for (l = 0; l < 2; l++) { 92 range = 0; 93 wrote_sep = 0; 94 strcpy(scontextp, 95 policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); 96 scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); 97 98 /* categories */ 99 ebitmap_for_each_bit(&context->range.level[l].cat, node, i) { 100 if (ebitmap_node_get_bit(node, i)) { 101 if (range) { 102 range++; 103 continue; 104 } 105 106 if (!wrote_sep) { 107 *scontextp++ = ':'; 108 wrote_sep = 1; 109 } else 110 *scontextp++ = ','; 111 strcpy(scontextp, policydb.p_cat_val_to_name[i]); 112 scontextp += strlen(policydb.p_cat_val_to_name[i]); 113 range++; 114 } else { 115 if (range > 1) { 116 if (range > 2) 117 *scontextp++ = '.'; 118 else 119 *scontextp++ = ','; 120 121 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]); 122 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); 123 } 124 range = 0; 125 } 126 } 127 128 /* Handle case where last category is the end of range */ 129 if (range > 1) { 130 if (range > 2) 131 *scontextp++ = '.'; 132 else 133 *scontextp++ = ','; 134 135 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]); 136 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); 137 } 138 139 if (l == 0) { 140 if (mls_level_eq(&context->range.level[0], 141 &context->range.level[1])) 142 break; 143 else { 144 *scontextp = '-'; 145 scontextp++; 146 } 147 } 148 } 149 150 *scontext = scontextp; 151 return; 152 } 153 154 /* 155 * Return 1 if the MLS fields in the security context 156 * structure `c' are valid. Return 0 otherwise. 157 */ 158 int mls_context_isvalid(struct policydb *p, struct context *c) 159 { 160 struct level_datum *levdatum; 161 struct user_datum *usrdatum; 162 struct ebitmap_node *node; 163 int i, l; 164 165 if (!selinux_mls_enabled) 166 return 1; 167 168 /* 169 * MLS range validity checks: high must dominate low, low level must 170 * be valid (category set <-> sensitivity check), and high level must 171 * be valid (category set <-> sensitivity check) 172 */ 173 if (!mls_level_dom(&c->range.level[1], &c->range.level[0])) 174 /* High does not dominate low. */ 175 return 0; 176 177 for (l = 0; l < 2; l++) { 178 if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim) 179 return 0; 180 levdatum = hashtab_search(p->p_levels.table, 181 p->p_sens_val_to_name[c->range.level[l].sens - 1]); 182 if (!levdatum) 183 return 0; 184 185 ebitmap_for_each_bit(&c->range.level[l].cat, node, i) { 186 if (ebitmap_node_get_bit(node, i)) { 187 if (i > p->p_cats.nprim) 188 return 0; 189 if (!ebitmap_get_bit(&levdatum->level->cat, i)) 190 /* 191 * Category may not be associated with 192 * sensitivity in low level. 193 */ 194 return 0; 195 } 196 } 197 } 198 199 if (c->role == OBJECT_R_VAL) 200 return 1; 201 202 /* 203 * User must be authorized for the MLS range. 204 */ 205 if (!c->user || c->user > p->p_users.nprim) 206 return 0; 207 usrdatum = p->user_val_to_struct[c->user - 1]; 208 if (!mls_range_contains(usrdatum->range, c->range)) 209 return 0; /* user may not be associated with range */ 210 211 return 1; 212 } 213 214 /* 215 * Copies the MLS range from `src' into `dst'. 216 */ 217 static inline int mls_copy_context(struct context *dst, 218 struct context *src) 219 { 220 int l, rc = 0; 221 222 /* Copy the MLS range from the source context */ 223 for (l = 0; l < 2; l++) { 224 dst->range.level[l].sens = src->range.level[l].sens; 225 rc = ebitmap_cpy(&dst->range.level[l].cat, 226 &src->range.level[l].cat); 227 if (rc) 228 break; 229 } 230 231 return rc; 232 } 233 234 /* 235 * Set the MLS fields in the security context structure 236 * `context' based on the string representation in 237 * the string `*scontext'. Update `*scontext' to 238 * point to the end of the string representation of 239 * the MLS fields. 240 * 241 * This function modifies the string in place, inserting 242 * NULL characters to terminate the MLS fields. 243 * 244 * If a def_sid is provided and no MLS field is present, 245 * copy the MLS field of the associated default context. 246 * Used for upgraded to MLS systems where objects may lack 247 * MLS fields. 248 * 249 * Policy read-lock must be held for sidtab lookup. 250 * 251 */ 252 int mls_context_to_sid(char oldc, 253 char **scontext, 254 struct context *context, 255 struct sidtab *s, 256 u32 def_sid) 257 { 258 259 char delim; 260 char *scontextp, *p, *rngptr; 261 struct level_datum *levdatum; 262 struct cat_datum *catdatum, *rngdatum; 263 int l, rc = -EINVAL; 264 265 if (!selinux_mls_enabled) { 266 if (def_sid != SECSID_NULL && oldc) 267 *scontext += strlen(*scontext); 268 return 0; 269 } 270 271 /* 272 * No MLS component to the security context, try and map to 273 * default if provided. 274 */ 275 if (!oldc) { 276 struct context *defcon; 277 278 if (def_sid == SECSID_NULL) 279 goto out; 280 281 defcon = sidtab_search(s, def_sid); 282 if (!defcon) 283 goto out; 284 285 rc = mls_copy_context(context, defcon); 286 goto out; 287 } 288 289 /* Extract low sensitivity. */ 290 scontextp = p = *scontext; 291 while (*p && *p != ':' && *p != '-') 292 p++; 293 294 delim = *p; 295 if (delim != 0) 296 *p++ = 0; 297 298 for (l = 0; l < 2; l++) { 299 levdatum = hashtab_search(policydb.p_levels.table, scontextp); 300 if (!levdatum) { 301 rc = -EINVAL; 302 goto out; 303 } 304 305 context->range.level[l].sens = levdatum->level->sens; 306 307 if (delim == ':') { 308 /* Extract category set. */ 309 while (1) { 310 scontextp = p; 311 while (*p && *p != ',' && *p != '-') 312 p++; 313 delim = *p; 314 if (delim != 0) 315 *p++ = 0; 316 317 /* Separate into range if exists */ 318 if ((rngptr = strchr(scontextp, '.')) != NULL) { 319 /* Remove '.' */ 320 *rngptr++ = 0; 321 } 322 323 catdatum = hashtab_search(policydb.p_cats.table, 324 scontextp); 325 if (!catdatum) { 326 rc = -EINVAL; 327 goto out; 328 } 329 330 rc = ebitmap_set_bit(&context->range.level[l].cat, 331 catdatum->value - 1, 1); 332 if (rc) 333 goto out; 334 335 /* If range, set all categories in range */ 336 if (rngptr) { 337 int i; 338 339 rngdatum = hashtab_search(policydb.p_cats.table, rngptr); 340 if (!rngdatum) { 341 rc = -EINVAL; 342 goto out; 343 } 344 345 if (catdatum->value >= rngdatum->value) { 346 rc = -EINVAL; 347 goto out; 348 } 349 350 for (i = catdatum->value; i < rngdatum->value; i++) { 351 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1); 352 if (rc) 353 goto out; 354 } 355 } 356 357 if (delim != ',') 358 break; 359 } 360 } 361 if (delim == '-') { 362 /* Extract high sensitivity. */ 363 scontextp = p; 364 while (*p && *p != ':') 365 p++; 366 367 delim = *p; 368 if (delim != 0) 369 *p++ = 0; 370 } else 371 break; 372 } 373 374 if (l == 0) { 375 context->range.level[1].sens = context->range.level[0].sens; 376 rc = ebitmap_cpy(&context->range.level[1].cat, 377 &context->range.level[0].cat); 378 if (rc) 379 goto out; 380 } 381 *scontext = ++p; 382 rc = 0; 383 out: 384 return rc; 385 } 386 387 /* 388 * Copies the effective MLS range from `src' into `dst'. 389 */ 390 static inline int mls_scopy_context(struct context *dst, 391 struct context *src) 392 { 393 int l, rc = 0; 394 395 /* Copy the MLS range from the source context */ 396 for (l = 0; l < 2; l++) { 397 dst->range.level[l].sens = src->range.level[0].sens; 398 rc = ebitmap_cpy(&dst->range.level[l].cat, 399 &src->range.level[0].cat); 400 if (rc) 401 break; 402 } 403 404 return rc; 405 } 406 407 /* 408 * Copies the MLS range `range' into `context'. 409 */ 410 static inline int mls_range_set(struct context *context, 411 struct mls_range *range) 412 { 413 int l, rc = 0; 414 415 /* Copy the MLS range into the context */ 416 for (l = 0; l < 2; l++) { 417 context->range.level[l].sens = range->level[l].sens; 418 rc = ebitmap_cpy(&context->range.level[l].cat, 419 &range->level[l].cat); 420 if (rc) 421 break; 422 } 423 424 return rc; 425 } 426 427 int mls_setup_user_range(struct context *fromcon, struct user_datum *user, 428 struct context *usercon) 429 { 430 if (selinux_mls_enabled) { 431 struct mls_level *fromcon_sen = &(fromcon->range.level[0]); 432 struct mls_level *fromcon_clr = &(fromcon->range.level[1]); 433 struct mls_level *user_low = &(user->range.level[0]); 434 struct mls_level *user_clr = &(user->range.level[1]); 435 struct mls_level *user_def = &(user->dfltlevel); 436 struct mls_level *usercon_sen = &(usercon->range.level[0]); 437 struct mls_level *usercon_clr = &(usercon->range.level[1]); 438 439 /* Honor the user's default level if we can */ 440 if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) { 441 *usercon_sen = *user_def; 442 } else if (mls_level_between(fromcon_sen, user_def, user_clr)) { 443 *usercon_sen = *fromcon_sen; 444 } else if (mls_level_between(fromcon_clr, user_low, user_def)) { 445 *usercon_sen = *user_low; 446 } else 447 return -EINVAL; 448 449 /* Lower the clearance of available contexts 450 if the clearance of "fromcon" is lower than 451 that of the user's default clearance (but 452 only if the "fromcon" clearance dominates 453 the user's computed sensitivity level) */ 454 if (mls_level_dom(user_clr, fromcon_clr)) { 455 *usercon_clr = *fromcon_clr; 456 } else if (mls_level_dom(fromcon_clr, user_clr)) { 457 *usercon_clr = *user_clr; 458 } else 459 return -EINVAL; 460 } 461 462 return 0; 463 } 464 465 /* 466 * Convert the MLS fields in the security context 467 * structure `c' from the values specified in the 468 * policy `oldp' to the values specified in the policy `newp'. 469 */ 470 int mls_convert_context(struct policydb *oldp, 471 struct policydb *newp, 472 struct context *c) 473 { 474 struct level_datum *levdatum; 475 struct cat_datum *catdatum; 476 struct ebitmap bitmap; 477 struct ebitmap_node *node; 478 int l, i; 479 480 if (!selinux_mls_enabled) 481 return 0; 482 483 for (l = 0; l < 2; l++) { 484 levdatum = hashtab_search(newp->p_levels.table, 485 oldp->p_sens_val_to_name[c->range.level[l].sens - 1]); 486 487 if (!levdatum) 488 return -EINVAL; 489 c->range.level[l].sens = levdatum->level->sens; 490 491 ebitmap_init(&bitmap); 492 ebitmap_for_each_bit(&c->range.level[l].cat, node, i) { 493 if (ebitmap_node_get_bit(node, i)) { 494 int rc; 495 496 catdatum = hashtab_search(newp->p_cats.table, 497 oldp->p_cat_val_to_name[i]); 498 if (!catdatum) 499 return -EINVAL; 500 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); 501 if (rc) 502 return rc; 503 } 504 } 505 ebitmap_destroy(&c->range.level[l].cat); 506 c->range.level[l].cat = bitmap; 507 } 508 509 return 0; 510 } 511 512 int mls_compute_sid(struct context *scontext, 513 struct context *tcontext, 514 u16 tclass, 515 u32 specified, 516 struct context *newcontext) 517 { 518 if (!selinux_mls_enabled) 519 return 0; 520 521 switch (specified) { 522 case AVTAB_TRANSITION: 523 if (tclass == SECCLASS_PROCESS) { 524 struct range_trans *rangetr; 525 /* Look for a range transition rule. */ 526 for (rangetr = policydb.range_tr; rangetr; 527 rangetr = rangetr->next) { 528 if (rangetr->dom == scontext->type && 529 rangetr->type == tcontext->type) { 530 /* Set the range from the rule */ 531 return mls_range_set(newcontext, 532 &rangetr->range); 533 } 534 } 535 } 536 /* Fallthrough */ 537 case AVTAB_CHANGE: 538 if (tclass == SECCLASS_PROCESS) 539 /* Use the process MLS attributes. */ 540 return mls_copy_context(newcontext, scontext); 541 else 542 /* Use the process effective MLS attributes. */ 543 return mls_scopy_context(newcontext, scontext); 544 case AVTAB_MEMBER: 545 /* Only polyinstantiate the MLS attributes if 546 the type is being polyinstantiated */ 547 if (newcontext->type != tcontext->type) { 548 /* Use the process effective MLS attributes. */ 549 return mls_scopy_context(newcontext, scontext); 550 } else { 551 /* Use the related object MLS attributes. */ 552 return mls_copy_context(newcontext, tcontext); 553 } 554 default: 555 return -EINVAL; 556 } 557 return -EINVAL; 558 } 559 560