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 return 0; 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 goto out; 277 278 defcon = sidtab_search(s, def_sid); 279 if (!defcon) 280 goto out; 281 282 rc = mls_copy_context(context, defcon); 283 goto out; 284 } 285 286 /* Extract low sensitivity. */ 287 scontextp = p = *scontext; 288 while (*p && *p != ':' && *p != '-') 289 p++; 290 291 delim = *p; 292 if (delim != 0) 293 *p++ = 0; 294 295 for (l = 0; l < 2; l++) { 296 levdatum = hashtab_search(policydb.p_levels.table, scontextp); 297 if (!levdatum) { 298 rc = -EINVAL; 299 goto out; 300 } 301 302 context->range.level[l].sens = levdatum->level->sens; 303 304 if (delim == ':') { 305 /* Extract category set. */ 306 while (1) { 307 scontextp = p; 308 while (*p && *p != ',' && *p != '-') 309 p++; 310 delim = *p; 311 if (delim != 0) 312 *p++ = 0; 313 314 /* Separate into range if exists */ 315 if ((rngptr = strchr(scontextp, '.')) != NULL) { 316 /* Remove '.' */ 317 *rngptr++ = 0; 318 } 319 320 catdatum = hashtab_search(policydb.p_cats.table, 321 scontextp); 322 if (!catdatum) { 323 rc = -EINVAL; 324 goto out; 325 } 326 327 rc = ebitmap_set_bit(&context->range.level[l].cat, 328 catdatum->value - 1, 1); 329 if (rc) 330 goto out; 331 332 /* If range, set all categories in range */ 333 if (rngptr) { 334 int i; 335 336 rngdatum = hashtab_search(policydb.p_cats.table, rngptr); 337 if (!rngdatum) { 338 rc = -EINVAL; 339 goto out; 340 } 341 342 if (catdatum->value >= rngdatum->value) { 343 rc = -EINVAL; 344 goto out; 345 } 346 347 for (i = catdatum->value; i < rngdatum->value; i++) { 348 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1); 349 if (rc) 350 goto out; 351 } 352 } 353 354 if (delim != ',') 355 break; 356 } 357 } 358 if (delim == '-') { 359 /* Extract high sensitivity. */ 360 scontextp = p; 361 while (*p && *p != ':') 362 p++; 363 364 delim = *p; 365 if (delim != 0) 366 *p++ = 0; 367 } else 368 break; 369 } 370 371 if (l == 0) { 372 context->range.level[1].sens = context->range.level[0].sens; 373 rc = ebitmap_cpy(&context->range.level[1].cat, 374 &context->range.level[0].cat); 375 if (rc) 376 goto out; 377 } 378 *scontext = ++p; 379 rc = 0; 380 out: 381 return rc; 382 } 383 384 /* 385 * Copies the effective MLS range from `src' into `dst'. 386 */ 387 static inline int mls_scopy_context(struct context *dst, 388 struct context *src) 389 { 390 int l, rc = 0; 391 392 /* Copy the MLS range from the source context */ 393 for (l = 0; l < 2; l++) { 394 dst->range.level[l].sens = src->range.level[0].sens; 395 rc = ebitmap_cpy(&dst->range.level[l].cat, 396 &src->range.level[0].cat); 397 if (rc) 398 break; 399 } 400 401 return rc; 402 } 403 404 /* 405 * Copies the MLS range `range' into `context'. 406 */ 407 static inline int mls_range_set(struct context *context, 408 struct mls_range *range) 409 { 410 int l, rc = 0; 411 412 /* Copy the MLS range into the context */ 413 for (l = 0; l < 2; l++) { 414 context->range.level[l].sens = range->level[l].sens; 415 rc = ebitmap_cpy(&context->range.level[l].cat, 416 &range->level[l].cat); 417 if (rc) 418 break; 419 } 420 421 return rc; 422 } 423 424 int mls_setup_user_range(struct context *fromcon, struct user_datum *user, 425 struct context *usercon) 426 { 427 if (selinux_mls_enabled) { 428 struct mls_level *fromcon_sen = &(fromcon->range.level[0]); 429 struct mls_level *fromcon_clr = &(fromcon->range.level[1]); 430 struct mls_level *user_low = &(user->range.level[0]); 431 struct mls_level *user_clr = &(user->range.level[1]); 432 struct mls_level *user_def = &(user->dfltlevel); 433 struct mls_level *usercon_sen = &(usercon->range.level[0]); 434 struct mls_level *usercon_clr = &(usercon->range.level[1]); 435 436 /* Honor the user's default level if we can */ 437 if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) { 438 *usercon_sen = *user_def; 439 } else if (mls_level_between(fromcon_sen, user_def, user_clr)) { 440 *usercon_sen = *fromcon_sen; 441 } else if (mls_level_between(fromcon_clr, user_low, user_def)) { 442 *usercon_sen = *user_low; 443 } else 444 return -EINVAL; 445 446 /* Lower the clearance of available contexts 447 if the clearance of "fromcon" is lower than 448 that of the user's default clearance (but 449 only if the "fromcon" clearance dominates 450 the user's computed sensitivity level) */ 451 if (mls_level_dom(user_clr, fromcon_clr)) { 452 *usercon_clr = *fromcon_clr; 453 } else if (mls_level_dom(fromcon_clr, user_clr)) { 454 *usercon_clr = *user_clr; 455 } else 456 return -EINVAL; 457 } 458 459 return 0; 460 } 461 462 /* 463 * Convert the MLS fields in the security context 464 * structure `c' from the values specified in the 465 * policy `oldp' to the values specified in the policy `newp'. 466 */ 467 int mls_convert_context(struct policydb *oldp, 468 struct policydb *newp, 469 struct context *c) 470 { 471 struct level_datum *levdatum; 472 struct cat_datum *catdatum; 473 struct ebitmap bitmap; 474 struct ebitmap_node *node; 475 int l, i; 476 477 if (!selinux_mls_enabled) 478 return 0; 479 480 for (l = 0; l < 2; l++) { 481 levdatum = hashtab_search(newp->p_levels.table, 482 oldp->p_sens_val_to_name[c->range.level[l].sens - 1]); 483 484 if (!levdatum) 485 return -EINVAL; 486 c->range.level[l].sens = levdatum->level->sens; 487 488 ebitmap_init(&bitmap); 489 ebitmap_for_each_bit(&c->range.level[l].cat, node, i) { 490 if (ebitmap_node_get_bit(node, i)) { 491 int rc; 492 493 catdatum = hashtab_search(newp->p_cats.table, 494 oldp->p_cat_val_to_name[i]); 495 if (!catdatum) 496 return -EINVAL; 497 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); 498 if (rc) 499 return rc; 500 } 501 } 502 ebitmap_destroy(&c->range.level[l].cat); 503 c->range.level[l].cat = bitmap; 504 } 505 506 return 0; 507 } 508 509 int mls_compute_sid(struct context *scontext, 510 struct context *tcontext, 511 u16 tclass, 512 u32 specified, 513 struct context *newcontext) 514 { 515 if (!selinux_mls_enabled) 516 return 0; 517 518 switch (specified) { 519 case AVTAB_TRANSITION: 520 if (tclass == SECCLASS_PROCESS) { 521 struct range_trans *rangetr; 522 /* Look for a range transition rule. */ 523 for (rangetr = policydb.range_tr; rangetr; 524 rangetr = rangetr->next) { 525 if (rangetr->dom == scontext->type && 526 rangetr->type == tcontext->type) { 527 /* Set the range from the rule */ 528 return mls_range_set(newcontext, 529 &rangetr->range); 530 } 531 } 532 } 533 /* Fallthrough */ 534 case AVTAB_CHANGE: 535 if (tclass == SECCLASS_PROCESS) 536 /* Use the process MLS attributes. */ 537 return mls_copy_context(newcontext, scontext); 538 else 539 /* Use the process effective MLS attributes. */ 540 return mls_scopy_context(newcontext, scontext); 541 case AVTAB_MEMBER: 542 /* Only polyinstantiate the MLS attributes if 543 the type is being polyinstantiated */ 544 if (newcontext->type != tcontext->type) { 545 /* Use the process effective MLS attributes. */ 546 return mls_scopy_context(newcontext, scontext); 547 } else { 548 /* Use the related object MLS attributes. */ 549 return mls_copy_context(newcontext, tcontext); 550 } 551 default: 552 return -EINVAL; 553 } 554 return -EINVAL; 555 } 556 557