1 2 /* 3 * Author : Stephen Smalley, <sds (at) epoch.ncsc.mil> 4 */ 5 /* 6 * Updated: Trusted Computer Solutions, Inc. <dgoeddel (at) trustedcs.com> 7 * 8 * Support for enhanced MLS infrastructure. 9 * 10 * Updated: Frank Mayer <mayerf (at) tresys.com> 11 * and Karl MacMillan <kmacmillan (at) tresys.com> 12 * 13 * Added conditional policy language extensions 14 * 15 * Updated: Red Hat, Inc. James Morris <jmorris (at) redhat.com> 16 * 17 * Fine-grained netlink support 18 * IPv6 support 19 * Code cleanup 20 * 21 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. 22 * Copyright (C) 2003 - 2004 Tresys Technology, LLC 23 * Copyright (C) 2003 - 2004 Red Hat, Inc. 24 * 25 * This library is free software; you can redistribute it and/or 26 * modify it under the terms of the GNU Lesser General Public 27 * License as published by the Free Software Foundation; either 28 * version 2.1 of the License, or (at your option) any later version. 29 * 30 * This library is distributed in the hope that it will be useful, 31 * but WITHOUT ANY WARRANTY; without even the implied warranty of 32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 33 * Lesser General Public License for more details. 34 * 35 * You should have received a copy of the GNU Lesser General Public 36 * License along with this library; if not, write to the Free Software 37 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 38 */ 39 40 /* FLASK */ 41 42 /* 43 * Implementation of the security services. 44 */ 45 46 /* Initial sizes malloc'd for sepol_compute_av_reason_buffer() support */ 47 #define REASON_BUF_SIZE 2048 48 #define EXPR_BUF_SIZE 1024 49 #define STACK_LEN 32 50 51 #include <stdlib.h> 52 #include <sys/types.h> 53 #include <sys/socket.h> 54 #include <netinet/in.h> 55 #include <arpa/inet.h> 56 57 #include <sepol/policydb/policydb.h> 58 #include <sepol/policydb/sidtab.h> 59 #include <sepol/policydb/services.h> 60 #include <sepol/policydb/conditional.h> 61 #include <sepol/policydb/flask.h> 62 #include <sepol/policydb/util.h> 63 64 #include "debug.h" 65 #include "private.h" 66 #include "context.h" 67 #include "av_permissions.h" 68 #include "dso.h" 69 #include "mls.h" 70 71 #define BUG() do { ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0) 72 #define BUG_ON(x) do { if (x) ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0) 73 74 static int selinux_enforcing = 1; 75 76 static sidtab_t mysidtab, *sidtab = &mysidtab; 77 static policydb_t mypolicydb, *policydb = &mypolicydb; 78 79 /* Used by sepol_compute_av_reason_buffer() to keep track of entries */ 80 static int reason_buf_used; 81 static int reason_buf_len; 82 83 /* Stack services for RPN to infix conversion. */ 84 static char **stack; 85 static int stack_len; 86 static int next_stack_entry; 87 88 static void push(char *expr_ptr) 89 { 90 if (next_stack_entry >= stack_len) { 91 char **new_stack = stack; 92 int new_stack_len; 93 94 if (stack_len == 0) 95 new_stack_len = STACK_LEN; 96 else 97 new_stack_len = stack_len * 2; 98 99 new_stack = realloc(stack, new_stack_len * sizeof(*stack)); 100 if (!new_stack) { 101 ERR(NULL, "unable to allocate stack space"); 102 return; 103 } 104 stack_len = new_stack_len; 105 stack = new_stack; 106 } 107 stack[next_stack_entry] = expr_ptr; 108 next_stack_entry++; 109 } 110 111 static char *pop(void) 112 { 113 next_stack_entry--; 114 if (next_stack_entry < 0) { 115 next_stack_entry = 0; 116 ERR(NULL, "pop called with no stack entries"); 117 return NULL; 118 } 119 return stack[next_stack_entry]; 120 } 121 /* End Stack services */ 122 123 int hidden sepol_set_sidtab(sidtab_t * s) 124 { 125 sidtab = s; 126 return 0; 127 } 128 129 int hidden sepol_set_policydb(policydb_t * p) 130 { 131 policydb = p; 132 return 0; 133 } 134 135 int sepol_set_policydb_from_file(FILE * fp) 136 { 137 struct policy_file pf; 138 139 policy_file_init(&pf); 140 pf.fp = fp; 141 pf.type = PF_USE_STDIO; 142 if (mypolicydb.policy_type) 143 policydb_destroy(&mypolicydb); 144 if (policydb_init(&mypolicydb)) { 145 ERR(NULL, "Out of memory!"); 146 return -1; 147 } 148 if (policydb_read(&mypolicydb, &pf, 0)) { 149 policydb_destroy(&mypolicydb); 150 ERR(NULL, "can't read binary policy: %s", strerror(errno)); 151 return -1; 152 } 153 policydb = &mypolicydb; 154 return sepol_sidtab_init(sidtab); 155 } 156 157 /* 158 * The largest sequence number that has been used when 159 * providing an access decision to the access vector cache. 160 * The sequence number only changes when a policy change 161 * occurs. 162 */ 163 static uint32_t latest_granting = 0; 164 165 /* 166 * cat_expr_buf adds a string to an expression buffer and handles 167 * realloc's if buffer is too small. The array of expression text 168 * buffer pointers and its counter are globally defined here as 169 * constraint_expr_eval_reason() sets them up and cat_expr_buf 170 * updates the e_buf pointer. 171 */ 172 static int expr_counter; 173 static char **expr_list; 174 static int expr_buf_used; 175 static int expr_buf_len; 176 177 static void cat_expr_buf(char *e_buf, const char *string) 178 { 179 int len, new_buf_len; 180 char *p, *new_buf = e_buf; 181 182 while (1) { 183 p = e_buf + expr_buf_used; 184 len = snprintf(p, expr_buf_len - expr_buf_used, "%s", string); 185 if (len < 0 || len >= expr_buf_len - expr_buf_used) { 186 new_buf_len = expr_buf_len + EXPR_BUF_SIZE; 187 new_buf = realloc(e_buf, new_buf_len); 188 if (!new_buf) { 189 ERR(NULL, "failed to realloc expr buffer"); 190 return; 191 } 192 /* Update new ptr in expr list and locally + new len */ 193 expr_list[expr_counter] = new_buf; 194 e_buf = new_buf; 195 expr_buf_len = new_buf_len; 196 } else { 197 expr_buf_used += len; 198 return; 199 } 200 } 201 } 202 203 /* 204 * If the POLICY_KERN version is >= POLICYDB_VERSION_CONSTRAINT_NAMES, 205 * then for 'types' only, read the types_names->types list as it will 206 * contain a list of types and attributes that were defined in the 207 * policy source. 208 * For user and role plus types (for policy vers < 209 * POLICYDB_VERSION_CONSTRAINT_NAMES) just read the e->names list. 210 */ 211 static void get_name_list(constraint_expr_t *e, int type, 212 const char *src, const char *op, int failed) 213 { 214 ebitmap_t *types; 215 int rc = 0; 216 unsigned int i; 217 char tmp_buf[128]; 218 int counter = 0; 219 220 if (policydb->policy_type == POLICY_KERN && 221 policydb->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES && 222 type == CEXPR_TYPE) 223 types = &e->type_names->types; 224 else 225 types = &e->names; 226 227 /* Find out how many entries */ 228 for (i = ebitmap_startbit(types); i < ebitmap_length(types); i++) { 229 rc = ebitmap_get_bit(types, i); 230 if (rc == 0) 231 continue; 232 else 233 counter++; 234 } 235 snprintf(tmp_buf, sizeof(tmp_buf), "(%s%s", src, op); 236 cat_expr_buf(expr_list[expr_counter], tmp_buf); 237 238 if (counter == 0) 239 cat_expr_buf(expr_list[expr_counter], "<empty_set> "); 240 if (counter > 1) 241 cat_expr_buf(expr_list[expr_counter], " {"); 242 if (counter >= 1) { 243 for (i = ebitmap_startbit(types); i < ebitmap_length(types); i++) { 244 rc = ebitmap_get_bit(types, i); 245 if (rc == 0) 246 continue; 247 248 /* Collect entries */ 249 switch (type) { 250 case CEXPR_USER: 251 snprintf(tmp_buf, sizeof(tmp_buf), " %s", 252 policydb->p_user_val_to_name[i]); 253 break; 254 case CEXPR_ROLE: 255 snprintf(tmp_buf, sizeof(tmp_buf), " %s", 256 policydb->p_role_val_to_name[i]); 257 break; 258 case CEXPR_TYPE: 259 snprintf(tmp_buf, sizeof(tmp_buf), " %s", 260 policydb->p_type_val_to_name[i]); 261 break; 262 } 263 cat_expr_buf(expr_list[expr_counter], tmp_buf); 264 } 265 } 266 if (counter > 1) 267 cat_expr_buf(expr_list[expr_counter], " }"); 268 if (failed) 269 cat_expr_buf(expr_list[expr_counter], " -Fail-) "); 270 else 271 cat_expr_buf(expr_list[expr_counter], ") "); 272 273 return; 274 } 275 276 static void msgcat(const char *src, const char *tgt, const char *op, int failed) 277 { 278 char tmp_buf[128]; 279 if (failed) 280 snprintf(tmp_buf, sizeof(tmp_buf), "(%s %s %s -Fail-) ", 281 src, op, tgt); 282 else 283 snprintf(tmp_buf, sizeof(tmp_buf), "(%s %s %s) ", 284 src, op, tgt); 285 cat_expr_buf(expr_list[expr_counter], tmp_buf); 286 } 287 288 /* Returns a buffer with class, statement type and permissions */ 289 static char *get_class_info(sepol_security_class_t tclass, 290 constraint_node_t *constraint, 291 context_struct_t *xcontext) 292 { 293 constraint_expr_t *e; 294 int mls, state_num; 295 296 /* Find if MLS statement or not */ 297 mls = 0; 298 for (e = constraint->expr; e; e = e->next) { 299 if (e->attr >= CEXPR_L1L2) { 300 mls = 1; 301 break; 302 } 303 } 304 305 /* Determine statement type */ 306 const char *statements[] = { 307 "constrain ", /* 0 */ 308 "mlsconstrain ", /* 1 */ 309 "validatetrans ", /* 2 */ 310 "mlsvalidatetrans ", /* 3 */ 311 0 }; 312 313 if (xcontext == NULL) 314 state_num = mls + 0; 315 else 316 state_num = mls + 2; 317 318 int class_buf_len = 0; 319 int new_class_buf_len; 320 int len, buf_used; 321 char *class_buf = NULL, *p; 322 char *new_class_buf = NULL; 323 324 while (1) { 325 new_class_buf_len = class_buf_len + EXPR_BUF_SIZE; 326 new_class_buf = realloc(class_buf, new_class_buf_len); 327 if (!new_class_buf) 328 return NULL; 329 class_buf_len = new_class_buf_len; 330 class_buf = new_class_buf; 331 buf_used = 0; 332 p = class_buf; 333 334 /* Add statement type */ 335 len = snprintf(p, class_buf_len - buf_used, "%s", statements[state_num]); 336 if (len < 0 || len >= class_buf_len - buf_used) 337 continue; 338 339 /* Add class entry */ 340 p += len; 341 buf_used += len; 342 len = snprintf(p, class_buf_len - buf_used, "%s ", 343 policydb->p_class_val_to_name[tclass - 1]); 344 if (len < 0 || len >= class_buf_len - buf_used) 345 continue; 346 347 /* Add permission entries (validatetrans does not have perms) */ 348 p += len; 349 buf_used += len; 350 if (state_num < 2) { 351 len = snprintf(p, class_buf_len - buf_used, "{%s } (", 352 sepol_av_to_string(policydb, tclass, 353 constraint->permissions)); 354 } else { 355 len = snprintf(p, class_buf_len - buf_used, "("); 356 } 357 if (len < 0 || len >= class_buf_len - buf_used) 358 continue; 359 break; 360 } 361 return class_buf; 362 } 363 364 /* 365 * Modified version of constraint_expr_eval that will process each 366 * constraint as before but adds the information to text buffers that 367 * will hold various components. The expression will be in RPN format, 368 * therefore there is a stack based RPN to infix converter to produce 369 * the final readable constraint. 370 * 371 * Return the boolean value of a constraint expression 372 * when it is applied to the specified source and target 373 * security contexts. 374 * 375 * xcontext is a special beast... It is used by the validatetrans rules 376 * only. For these rules, scontext is the context before the transition, 377 * tcontext is the context after the transition, and xcontext is the 378 * context of the process performing the transition. All other callers 379 * of constraint_expr_eval_reason should pass in NULL for xcontext. 380 * 381 * This function will also build a buffer as the constraint is processed 382 * for analysis. If this option is not required, then: 383 * 'tclass' should be '0' and r_buf MUST be NULL. 384 */ 385 static int constraint_expr_eval_reason(context_struct_t *scontext, 386 context_struct_t *tcontext, 387 context_struct_t *xcontext, 388 sepol_security_class_t tclass, 389 constraint_node_t *constraint, 390 char **r_buf, 391 unsigned int flags) 392 { 393 uint32_t val1, val2; 394 context_struct_t *c; 395 role_datum_t *r1, *r2; 396 mls_level_t *l1, *l2; 397 constraint_expr_t *e; 398 int s[CEXPR_MAXDEPTH]; 399 int sp = -1; 400 char tmp_buf[128]; 401 402 /* 403 * Define the s_t_x_num values that make up r1, t2 etc. in text strings 404 * Set 1 = source, 2 = target, 3 = xcontext for validatetrans 405 */ 406 #define SOURCE 1 407 #define TARGET 2 408 #define XTARGET 3 409 410 int s_t_x_num = SOURCE; 411 412 /* Set 0 = fail, u = CEXPR_USER, r = CEXPR_ROLE, t = CEXPR_TYPE */ 413 int u_r_t = 0; 414 415 char *src = NULL; 416 char *tgt = NULL; 417 int rc = 0, x; 418 char *class_buf = NULL; 419 420 /* 421 * The array of expression answer buffer pointers and counter. 422 */ 423 char **answer_list = NULL; 424 int answer_counter = 0; 425 426 class_buf = get_class_info(tclass, constraint, xcontext); 427 if (!class_buf) { 428 ERR(NULL, "failed to allocate class buffer"); 429 return -ENOMEM; 430 } 431 432 /* Original function but with buffer support */ 433 int expr_list_len = 0; 434 expr_counter = 0; 435 expr_list = NULL; 436 for (e = constraint->expr; e; e = e->next) { 437 /* Allocate a stack to hold expression buffer entries */ 438 if (expr_counter >= expr_list_len) { 439 char **new_expr_list = expr_list; 440 int new_expr_list_len; 441 442 if (expr_list_len == 0) 443 new_expr_list_len = STACK_LEN; 444 else 445 new_expr_list_len = expr_list_len * 2; 446 447 new_expr_list = realloc(expr_list, 448 new_expr_list_len * sizeof(*expr_list)); 449 if (!new_expr_list) { 450 ERR(NULL, "failed to allocate expr buffer stack"); 451 rc = -ENOMEM; 452 goto out; 453 } 454 expr_list_len = new_expr_list_len; 455 expr_list = new_expr_list; 456 } 457 458 /* 459 * malloc a buffer to store each expression text component. If 460 * buffer is too small cat_expr_buf() will realloc extra space. 461 */ 462 expr_buf_len = EXPR_BUF_SIZE; 463 expr_list[expr_counter] = malloc(expr_buf_len); 464 if (!expr_list[expr_counter]) { 465 ERR(NULL, "failed to allocate expr buffer"); 466 rc = -ENOMEM; 467 goto out; 468 } 469 expr_buf_used = 0; 470 471 /* Now process each expression of the constraint */ 472 switch (e->expr_type) { 473 case CEXPR_NOT: 474 BUG_ON(sp < 0); 475 s[sp] = !s[sp]; 476 cat_expr_buf(expr_list[expr_counter], "not"); 477 break; 478 case CEXPR_AND: 479 BUG_ON(sp < 1); 480 sp--; 481 s[sp] &= s[sp + 1]; 482 cat_expr_buf(expr_list[expr_counter], "and"); 483 break; 484 case CEXPR_OR: 485 BUG_ON(sp < 1); 486 sp--; 487 s[sp] |= s[sp + 1]; 488 cat_expr_buf(expr_list[expr_counter], "or"); 489 break; 490 case CEXPR_ATTR: 491 if (sp == (CEXPR_MAXDEPTH - 1)) 492 goto out; 493 494 switch (e->attr) { 495 case CEXPR_USER: 496 val1 = scontext->user; 497 val2 = tcontext->user; 498 free(src); src = strdup("u1"); 499 free(tgt); tgt = strdup("u2"); 500 break; 501 case CEXPR_TYPE: 502 val1 = scontext->type; 503 val2 = tcontext->type; 504 free(src); src = strdup("t1"); 505 free(tgt); tgt = strdup("t2"); 506 break; 507 case CEXPR_ROLE: 508 val1 = scontext->role; 509 val2 = tcontext->role; 510 r1 = policydb->role_val_to_struct[val1 - 1]; 511 r2 = policydb->role_val_to_struct[val2 - 1]; 512 free(src); src = strdup("r1"); 513 free(tgt); tgt = strdup("r2"); 514 515 switch (e->op) { 516 case CEXPR_DOM: 517 s[++sp] = ebitmap_get_bit(&r1->dominates, val2 - 1); 518 msgcat(src, tgt, "dom", s[sp] == 0); 519 expr_counter++; 520 continue; 521 case CEXPR_DOMBY: 522 s[++sp] = ebitmap_get_bit(&r2->dominates, val1 - 1); 523 msgcat(src, tgt, "domby", s[sp] == 0); 524 expr_counter++; 525 continue; 526 case CEXPR_INCOMP: 527 s[++sp] = (!ebitmap_get_bit(&r1->dominates, val2 - 1) 528 && !ebitmap_get_bit(&r2->dominates, val1 - 1)); 529 msgcat(src, tgt, "incomp", s[sp] == 0); 530 expr_counter++; 531 continue; 532 default: 533 break; 534 } 535 break; 536 case CEXPR_L1L2: 537 l1 = &(scontext->range.level[0]); 538 l2 = &(tcontext->range.level[0]); 539 free(src); src = strdup("l1"); 540 free(tgt); tgt = strdup("l2"); 541 goto mls_ops; 542 case CEXPR_L1H2: 543 l1 = &(scontext->range.level[0]); 544 l2 = &(tcontext->range.level[1]); 545 free(src); src = strdup("l1"); 546 free(tgt); tgt = strdup("h2"); 547 goto mls_ops; 548 case CEXPR_H1L2: 549 l1 = &(scontext->range.level[1]); 550 l2 = &(tcontext->range.level[0]); 551 free(src); src = strdup("h1"); 552 free(tgt); tgt = strdup("l2"); 553 goto mls_ops; 554 case CEXPR_H1H2: 555 l1 = &(scontext->range.level[1]); 556 l2 = &(tcontext->range.level[1]); 557 free(src); src = strdup("h1"); 558 free(tgt); tgt = strdup("h2"); 559 goto mls_ops; 560 case CEXPR_L1H1: 561 l1 = &(scontext->range.level[0]); 562 l2 = &(scontext->range.level[1]); 563 free(src); src = strdup("l1"); 564 free(tgt); tgt = strdup("h1"); 565 goto mls_ops; 566 case CEXPR_L2H2: 567 l1 = &(tcontext->range.level[0]); 568 l2 = &(tcontext->range.level[1]); 569 free(src); src = strdup("l2"); 570 free(tgt); tgt = strdup("h2"); 571 mls_ops: 572 switch (e->op) { 573 case CEXPR_EQ: 574 s[++sp] = mls_level_eq(l1, l2); 575 msgcat(src, tgt, "eq", s[sp] == 0); 576 expr_counter++; 577 continue; 578 case CEXPR_NEQ: 579 s[++sp] = !mls_level_eq(l1, l2); 580 msgcat(src, tgt, "!=", s[sp] == 0); 581 expr_counter++; 582 continue; 583 case CEXPR_DOM: 584 s[++sp] = mls_level_dom(l1, l2); 585 msgcat(src, tgt, "dom", s[sp] == 0); 586 expr_counter++; 587 continue; 588 case CEXPR_DOMBY: 589 s[++sp] = mls_level_dom(l2, l1); 590 msgcat(src, tgt, "domby", s[sp] == 0); 591 expr_counter++; 592 continue; 593 case CEXPR_INCOMP: 594 s[++sp] = mls_level_incomp(l2, l1); 595 msgcat(src, tgt, "incomp", s[sp] == 0); 596 expr_counter++; 597 continue; 598 default: 599 BUG(); 600 goto out; 601 } 602 break; 603 default: 604 BUG(); 605 goto out; 606 } 607 608 switch (e->op) { 609 case CEXPR_EQ: 610 s[++sp] = (val1 == val2); 611 msgcat(src, tgt, "==", s[sp] == 0); 612 break; 613 case CEXPR_NEQ: 614 s[++sp] = (val1 != val2); 615 msgcat(src, tgt, "!=", s[sp] == 0); 616 break; 617 default: 618 BUG(); 619 goto out; 620 } 621 break; 622 case CEXPR_NAMES: 623 if (sp == (CEXPR_MAXDEPTH - 1)) 624 goto out; 625 s_t_x_num = SOURCE; 626 c = scontext; 627 if (e->attr & CEXPR_TARGET) { 628 s_t_x_num = TARGET; 629 c = tcontext; 630 } else if (e->attr & CEXPR_XTARGET) { 631 s_t_x_num = XTARGET; 632 c = xcontext; 633 } 634 if (!c) { 635 BUG(); 636 goto out; 637 } 638 if (e->attr & CEXPR_USER) { 639 u_r_t = CEXPR_USER; 640 val1 = c->user; 641 snprintf(tmp_buf, sizeof(tmp_buf), "u%d ", s_t_x_num); 642 free(src); src = strdup(tmp_buf); 643 } else if (e->attr & CEXPR_ROLE) { 644 u_r_t = CEXPR_ROLE; 645 val1 = c->role; 646 snprintf(tmp_buf, sizeof(tmp_buf), "r%d ", s_t_x_num); 647 free(src); src = strdup(tmp_buf); 648 } else if (e->attr & CEXPR_TYPE) { 649 u_r_t = CEXPR_TYPE; 650 val1 = c->type; 651 snprintf(tmp_buf, sizeof(tmp_buf), "t%d ", s_t_x_num); 652 free(src); src = strdup(tmp_buf); 653 } else { 654 BUG(); 655 goto out; 656 } 657 658 switch (e->op) { 659 case CEXPR_EQ: 660 s[++sp] = ebitmap_get_bit(&e->names, val1 - 1); 661 get_name_list(e, u_r_t, src, "==", s[sp] == 0); 662 break; 663 664 case CEXPR_NEQ: 665 s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1); 666 get_name_list(e, u_r_t, src, "!=", s[sp] == 0); 667 break; 668 default: 669 BUG(); 670 goto out; 671 } 672 break; 673 default: 674 BUG(); 675 goto out; 676 } 677 expr_counter++; 678 } 679 680 /* 681 * At this point each expression of the constraint is in 682 * expr_list[n+1] and in RPN format. Now convert to 'infix' 683 */ 684 685 /* 686 * Save expr count but zero expr_counter to detect if 687 * 'BUG(); goto out;' was called as we need to release any used 688 * expr_list malloc's. Normally they are released by the RPN to 689 * infix code. 690 */ 691 int expr_count = expr_counter; 692 expr_counter = 0; 693 694 /* 695 * Generate the same number of answer buffer entries as expression 696 * buffers (as there will never be more). 697 */ 698 answer_list = malloc(expr_count * sizeof(*answer_list)); 699 if (!answer_list) { 700 ERR(NULL, "failed to allocate answer stack"); 701 rc = -ENOMEM; 702 goto out; 703 } 704 705 /* The pop operands */ 706 char *a; 707 char *b; 708 int a_len, b_len; 709 710 /* Convert constraint from RPN to infix notation. */ 711 for (x = 0; x != expr_count; x++) { 712 if (strncmp(expr_list[x], "and", 3) == 0 || strncmp(expr_list[x], 713 "or", 2) == 0) { 714 b = pop(); 715 b_len = strlen(b); 716 a = pop(); 717 a_len = strlen(a); 718 719 /* get a buffer to hold the answer */ 720 answer_list[answer_counter] = malloc(a_len + b_len + 8); 721 if (!answer_list[answer_counter]) { 722 ERR(NULL, "failed to allocate answer buffer"); 723 rc = -ENOMEM; 724 goto out; 725 } 726 memset(answer_list[answer_counter], '\0', a_len + b_len + 8); 727 728 sprintf(answer_list[answer_counter], "%s %s %s", a, 729 expr_list[x], b); 730 push(answer_list[answer_counter++]); 731 free(a); 732 free(b); 733 free(expr_list[x]); 734 } else if (strncmp(expr_list[x], "not", 3) == 0) { 735 b = pop(); 736 b_len = strlen(b); 737 738 answer_list[answer_counter] = malloc(b_len + 8); 739 if (!answer_list[answer_counter]) { 740 ERR(NULL, "failed to allocate answer buffer"); 741 rc = -ENOMEM; 742 goto out; 743 } 744 memset(answer_list[answer_counter], '\0', b_len + 8); 745 746 if (strncmp(b, "not", 3) == 0) 747 sprintf(answer_list[answer_counter], "%s (%s)", 748 expr_list[x], b); 749 else 750 sprintf(answer_list[answer_counter], "%s%s", 751 expr_list[x], b); 752 push(answer_list[answer_counter++]); 753 free(b); 754 free(expr_list[x]); 755 } else { 756 push(expr_list[x]); 757 } 758 } 759 /* Get the final answer from tos and build constraint text */ 760 a = pop(); 761 762 /* validatetrans / constraint calculation: 763 rc = 0 is denied, rc = 1 is granted */ 764 sprintf(tmp_buf, "%s %s\n", 765 xcontext ? "Validatetrans" : "Constraint", 766 s[0] ? "GRANTED" : "DENIED"); 767 768 int len, new_buf_len; 769 char *p, **new_buf = r_buf; 770 /* 771 * These contain the constraint components that are added to the 772 * callers reason buffer. 773 */ 774 const char *buffers[] = { class_buf, a, "); ", tmp_buf, 0 }; 775 776 /* 777 * This will add the constraints to the callers reason buffer (who is 778 * responsible for freeing the memory). It will handle any realloc's 779 * should the buffer be too short. 780 * The reason_buf_used and reason_buf_len counters are defined 781 * globally as multiple constraints can be in the buffer. 782 */ 783 784 if (r_buf && ((s[0] == 0) || ((s[0] == 1 && 785 (flags & SHOW_GRANTED) == SHOW_GRANTED)))) { 786 for (x = 0; buffers[x] != NULL; x++) { 787 while (1) { 788 p = *r_buf + reason_buf_used; 789 len = snprintf(p, reason_buf_len - reason_buf_used, 790 "%s", buffers[x]); 791 if (len < 0 || len >= reason_buf_len - reason_buf_used) { 792 new_buf_len = reason_buf_len + REASON_BUF_SIZE; 793 *new_buf = realloc(*r_buf, new_buf_len); 794 if (!new_buf) { 795 ERR(NULL, "failed to realloc reason buffer"); 796 goto out1; 797 } 798 **r_buf = **new_buf; 799 reason_buf_len = new_buf_len; 800 continue; 801 } else { 802 reason_buf_used += len; 803 break; 804 } 805 } 806 } 807 } 808 809 out1: 810 rc = s[0]; 811 free(a); 812 813 out: 814 free(class_buf); 815 free(src); 816 free(tgt); 817 818 if (expr_counter) { 819 for (x = 0; expr_list[x] != NULL; x++) 820 free(expr_list[x]); 821 } 822 free(answer_list); 823 free(expr_list); 824 return rc; 825 } 826 827 /* 828 * Compute access vectors based on a context structure pair for 829 * the permissions in a particular class. 830 */ 831 static int context_struct_compute_av(context_struct_t * scontext, 832 context_struct_t * tcontext, 833 sepol_security_class_t tclass, 834 sepol_access_vector_t requested, 835 struct sepol_av_decision *avd, 836 unsigned int *reason, 837 char **r_buf, 838 unsigned int flags) 839 { 840 constraint_node_t *constraint; 841 struct role_allow *ra; 842 avtab_key_t avkey; 843 class_datum_t *tclass_datum; 844 avtab_ptr_t node; 845 ebitmap_t *sattr, *tattr; 846 ebitmap_node_t *snode, *tnode; 847 unsigned int i, j; 848 849 if (!tclass || tclass > policydb->p_classes.nprim) { 850 ERR(NULL, "unrecognized class %d", tclass); 851 return -EINVAL; 852 } 853 tclass_datum = policydb->class_val_to_struct[tclass - 1]; 854 855 /* 856 * Initialize the access vectors to the default values. 857 */ 858 avd->allowed = 0; 859 avd->decided = 0xffffffff; 860 avd->auditallow = 0; 861 avd->auditdeny = 0xffffffff; 862 avd->seqno = latest_granting; 863 *reason = 0; 864 865 /* 866 * If a specific type enforcement rule was defined for 867 * this permission check, then use it. 868 */ 869 avkey.target_class = tclass; 870 avkey.specified = AVTAB_AV; 871 sattr = &policydb->type_attr_map[scontext->type - 1]; 872 tattr = &policydb->type_attr_map[tcontext->type - 1]; 873 ebitmap_for_each_bit(sattr, snode, i) { 874 if (!ebitmap_node_get_bit(snode, i)) 875 continue; 876 ebitmap_for_each_bit(tattr, tnode, j) { 877 if (!ebitmap_node_get_bit(tnode, j)) 878 continue; 879 avkey.source_type = i + 1; 880 avkey.target_type = j + 1; 881 for (node = 882 avtab_search_node(&policydb->te_avtab, &avkey); 883 node != NULL; 884 node = 885 avtab_search_node_next(node, avkey.specified)) { 886 if (node->key.specified == AVTAB_ALLOWED) 887 avd->allowed |= node->datum.data; 888 else if (node->key.specified == 889 AVTAB_AUDITALLOW) 890 avd->auditallow |= node->datum.data; 891 else if (node->key.specified == AVTAB_AUDITDENY) 892 avd->auditdeny &= node->datum.data; 893 } 894 895 /* Check conditional av table for additional permissions */ 896 cond_compute_av(&policydb->te_cond_avtab, &avkey, avd); 897 898 } 899 } 900 901 if (requested & ~avd->allowed) { 902 *reason |= SEPOL_COMPUTEAV_TE; 903 requested &= avd->allowed; 904 } 905 906 /* 907 * Remove any permissions prohibited by a constraint (this includes 908 * the MLS policy). 909 */ 910 constraint = tclass_datum->constraints; 911 while (constraint) { 912 if ((constraint->permissions & (avd->allowed)) && 913 !constraint_expr_eval_reason(scontext, tcontext, NULL, 914 tclass, constraint, r_buf, flags)) { 915 avd->allowed = 916 (avd->allowed) & ~(constraint->permissions); 917 } 918 constraint = constraint->next; 919 } 920 921 if (requested & ~avd->allowed) { 922 *reason |= SEPOL_COMPUTEAV_CONS; 923 requested &= avd->allowed; 924 } 925 926 /* 927 * If checking process transition permission and the 928 * role is changing, then check the (current_role, new_role) 929 * pair. 930 */ 931 if (tclass == SECCLASS_PROCESS && 932 (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) && 933 scontext->role != tcontext->role) { 934 for (ra = policydb->role_allow; ra; ra = ra->next) { 935 if (scontext->role == ra->role && 936 tcontext->role == ra->new_role) 937 break; 938 } 939 if (!ra) 940 avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION | 941 PROCESS__DYNTRANSITION); 942 } 943 944 if (requested & ~avd->allowed) { 945 *reason |= SEPOL_COMPUTEAV_RBAC; 946 requested &= avd->allowed; 947 } 948 949 return 0; 950 } 951 952 int hidden sepol_validate_transition(sepol_security_id_t oldsid, 953 sepol_security_id_t newsid, 954 sepol_security_id_t tasksid, 955 sepol_security_class_t tclass) 956 { 957 context_struct_t *ocontext; 958 context_struct_t *ncontext; 959 context_struct_t *tcontext; 960 class_datum_t *tclass_datum; 961 constraint_node_t *constraint; 962 963 if (!tclass || tclass > policydb->p_classes.nprim) { 964 ERR(NULL, "unrecognized class %d", tclass); 965 return -EINVAL; 966 } 967 tclass_datum = policydb->class_val_to_struct[tclass - 1]; 968 969 ocontext = sepol_sidtab_search(sidtab, oldsid); 970 if (!ocontext) { 971 ERR(NULL, "unrecognized SID %d", oldsid); 972 return -EINVAL; 973 } 974 975 ncontext = sepol_sidtab_search(sidtab, newsid); 976 if (!ncontext) { 977 ERR(NULL, "unrecognized SID %d", newsid); 978 return -EINVAL; 979 } 980 981 tcontext = sepol_sidtab_search(sidtab, tasksid); 982 if (!tcontext) { 983 ERR(NULL, "unrecognized SID %d", tasksid); 984 return -EINVAL; 985 } 986 987 constraint = tclass_datum->validatetrans; 988 while (constraint) { 989 if (!constraint_expr_eval_reason(ocontext, ncontext, tcontext, 990 0, constraint, NULL, 0)) { 991 return -EPERM; 992 } 993 constraint = constraint->next; 994 } 995 996 return 0; 997 } 998 999 /* 1000 * sepol_validate_transition_reason_buffer - the reason buffer is realloc'd 1001 * in the constraint_expr_eval_reason() function. 1002 */ 1003 int hidden sepol_validate_transition_reason_buffer(sepol_security_id_t oldsid, 1004 sepol_security_id_t newsid, 1005 sepol_security_id_t tasksid, 1006 sepol_security_class_t tclass, 1007 char **reason_buf, 1008 unsigned int flags) 1009 { 1010 context_struct_t *ocontext; 1011 context_struct_t *ncontext; 1012 context_struct_t *tcontext; 1013 class_datum_t *tclass_datum; 1014 constraint_node_t *constraint; 1015 1016 if (!tclass || tclass > policydb->p_classes.nprim) { 1017 ERR(NULL, "unrecognized class %d", tclass); 1018 return -EINVAL; 1019 } 1020 tclass_datum = policydb->class_val_to_struct[tclass - 1]; 1021 1022 ocontext = sepol_sidtab_search(sidtab, oldsid); 1023 if (!ocontext) { 1024 ERR(NULL, "unrecognized SID %d", oldsid); 1025 return -EINVAL; 1026 } 1027 1028 ncontext = sepol_sidtab_search(sidtab, newsid); 1029 if (!ncontext) { 1030 ERR(NULL, "unrecognized SID %d", newsid); 1031 return -EINVAL; 1032 } 1033 1034 tcontext = sepol_sidtab_search(sidtab, tasksid); 1035 if (!tcontext) { 1036 ERR(NULL, "unrecognized SID %d", tasksid); 1037 return -EINVAL; 1038 } 1039 1040 /* 1041 * Set the buffer to NULL as mls/validatetrans may not be processed. 1042 * If a buffer is required, then the routines in 1043 * constraint_expr_eval_reason will realloc in REASON_BUF_SIZE 1044 * chunks (as it gets called for each mls/validatetrans processed). 1045 * We just make sure these start from zero. 1046 */ 1047 *reason_buf = NULL; 1048 reason_buf_used = 0; 1049 reason_buf_len = 0; 1050 constraint = tclass_datum->validatetrans; 1051 while (constraint) { 1052 if (!constraint_expr_eval_reason(ocontext, ncontext, tcontext, 1053 tclass, constraint, reason_buf, flags)) { 1054 return -EPERM; 1055 } 1056 constraint = constraint->next; 1057 } 1058 return 0; 1059 } 1060 1061 int hidden sepol_compute_av_reason(sepol_security_id_t ssid, 1062 sepol_security_id_t tsid, 1063 sepol_security_class_t tclass, 1064 sepol_access_vector_t requested, 1065 struct sepol_av_decision *avd, 1066 unsigned int *reason) 1067 { 1068 context_struct_t *scontext = 0, *tcontext = 0; 1069 int rc = 0; 1070 1071 scontext = sepol_sidtab_search(sidtab, ssid); 1072 if (!scontext) { 1073 ERR(NULL, "unrecognized SID %d", ssid); 1074 rc = -EINVAL; 1075 goto out; 1076 } 1077 tcontext = sepol_sidtab_search(sidtab, tsid); 1078 if (!tcontext) { 1079 ERR(NULL, "unrecognized SID %d", tsid); 1080 rc = -EINVAL; 1081 goto out; 1082 } 1083 1084 rc = context_struct_compute_av(scontext, tcontext, tclass, 1085 requested, avd, reason, NULL, 0); 1086 out: 1087 return rc; 1088 } 1089 1090 /* 1091 * sepol_compute_av_reason_buffer - the reason buffer is malloc'd to 1092 * REASON_BUF_SIZE. If the buffer size is exceeded, then it is realloc'd 1093 * in the constraint_expr_eval_reason() function. 1094 */ 1095 int hidden sepol_compute_av_reason_buffer(sepol_security_id_t ssid, 1096 sepol_security_id_t tsid, 1097 sepol_security_class_t tclass, 1098 sepol_access_vector_t requested, 1099 struct sepol_av_decision *avd, 1100 unsigned int *reason, 1101 char **reason_buf, 1102 unsigned int flags) 1103 { 1104 context_struct_t *scontext = 0, *tcontext = 0; 1105 int rc = 0; 1106 1107 scontext = sepol_sidtab_search(sidtab, ssid); 1108 if (!scontext) { 1109 ERR(NULL, "unrecognized SID %d", ssid); 1110 rc = -EINVAL; 1111 goto out; 1112 } 1113 tcontext = sepol_sidtab_search(sidtab, tsid); 1114 if (!tcontext) { 1115 ERR(NULL, "unrecognized SID %d", tsid); 1116 rc = -EINVAL; 1117 goto out; 1118 } 1119 1120 /* 1121 * Set the buffer to NULL as constraints may not be processed. 1122 * If a buffer is required, then the routines in 1123 * constraint_expr_eval_reason will realloc in REASON_BUF_SIZE 1124 * chunks (as it gets called for each constraint processed). 1125 * We just make sure these start from zero. 1126 */ 1127 *reason_buf = NULL; 1128 reason_buf_used = 0; 1129 reason_buf_len = 0; 1130 1131 rc = context_struct_compute_av(scontext, tcontext, tclass, 1132 requested, avd, reason, reason_buf, flags); 1133 out: 1134 return rc; 1135 } 1136 1137 int hidden sepol_compute_av(sepol_security_id_t ssid, 1138 sepol_security_id_t tsid, 1139 sepol_security_class_t tclass, 1140 sepol_access_vector_t requested, 1141 struct sepol_av_decision *avd) 1142 { 1143 unsigned int reason = 0; 1144 return sepol_compute_av_reason(ssid, tsid, tclass, requested, avd, 1145 &reason); 1146 } 1147 1148 /* 1149 * Return a class ID associated with the class string specified by 1150 * class_name. 1151 */ 1152 int hidden sepol_string_to_security_class(const char *class_name, 1153 sepol_security_class_t *tclass) 1154 { 1155 char *class = NULL; 1156 sepol_security_class_t id; 1157 1158 for (id = 1;; id++) { 1159 class = policydb->p_class_val_to_name[id - 1]; 1160 if (class == NULL) { 1161 ERR(NULL, "could not convert %s to class id", class_name); 1162 return STATUS_ERR; 1163 } 1164 if ((strcmp(class, class_name)) == 0) { 1165 *tclass = id; 1166 return STATUS_SUCCESS; 1167 } 1168 } 1169 } 1170 1171 /* 1172 * Return access vector bit associated with the class ID and permission 1173 * string. 1174 */ 1175 int hidden sepol_string_to_av_perm(sepol_security_class_t tclass, 1176 const char *perm_name, 1177 sepol_access_vector_t *av) 1178 { 1179 class_datum_t *tclass_datum; 1180 perm_datum_t *perm_datum; 1181 1182 if (!tclass || tclass > policydb->p_classes.nprim) { 1183 ERR(NULL, "unrecognized class %d", tclass); 1184 return -EINVAL; 1185 } 1186 tclass_datum = policydb->class_val_to_struct[tclass - 1]; 1187 1188 /* Check for unique perms then the common ones (if any) */ 1189 perm_datum = (perm_datum_t *) 1190 hashtab_search(tclass_datum->permissions.table, 1191 (hashtab_key_t)perm_name); 1192 if (perm_datum != NULL) { 1193 *av = 0x1 << (perm_datum->s.value - 1); 1194 return STATUS_SUCCESS; 1195 } 1196 1197 if (tclass_datum->comdatum == NULL) 1198 goto out; 1199 1200 perm_datum = (perm_datum_t *) 1201 hashtab_search(tclass_datum->comdatum->permissions.table, 1202 (hashtab_key_t)perm_name); 1203 1204 if (perm_datum != NULL) { 1205 *av = 0x1 << (perm_datum->s.value - 1); 1206 return STATUS_SUCCESS; 1207 } 1208 out: 1209 ERR(NULL, "could not convert %s to av bit", perm_name); 1210 return STATUS_ERR; 1211 } 1212 1213 /* 1214 * Write the security context string representation of 1215 * the context associated with `sid' into a dynamically 1216 * allocated string of the correct size. Set `*scontext' 1217 * to point to this string and set `*scontext_len' to 1218 * the length of the string. 1219 */ 1220 int hidden sepol_sid_to_context(sepol_security_id_t sid, 1221 sepol_security_context_t * scontext, 1222 size_t * scontext_len) 1223 { 1224 context_struct_t *context; 1225 int rc = 0; 1226 1227 context = sepol_sidtab_search(sidtab, sid); 1228 if (!context) { 1229 ERR(NULL, "unrecognized SID %d", sid); 1230 rc = -EINVAL; 1231 goto out; 1232 } 1233 rc = context_to_string(NULL, policydb, context, scontext, scontext_len); 1234 out: 1235 return rc; 1236 1237 } 1238 1239 /* 1240 * Return a SID associated with the security context that 1241 * has the string representation specified by `scontext'. 1242 */ 1243 int hidden sepol_context_to_sid(const sepol_security_context_t scontext, 1244 size_t scontext_len, sepol_security_id_t * sid) 1245 { 1246 1247 context_struct_t *context = NULL; 1248 1249 /* First, create the context */ 1250 if (context_from_string(NULL, policydb, &context, 1251 scontext, scontext_len) < 0) 1252 goto err; 1253 1254 /* Obtain the new sid */ 1255 if (sid && (sepol_sidtab_context_to_sid(sidtab, context, sid) < 0)) 1256 goto err; 1257 1258 context_destroy(context); 1259 free(context); 1260 return STATUS_SUCCESS; 1261 1262 err: 1263 if (context) { 1264 context_destroy(context); 1265 free(context); 1266 } 1267 ERR(NULL, "could not convert %s to sid", scontext); 1268 return STATUS_ERR; 1269 } 1270 1271 static inline int compute_sid_handle_invalid_context(context_struct_t * 1272 scontext, 1273 context_struct_t * 1274 tcontext, 1275 sepol_security_class_t 1276 tclass, 1277 context_struct_t * 1278 newcontext) 1279 { 1280 if (selinux_enforcing) { 1281 return -EACCES; 1282 } else { 1283 sepol_security_context_t s, t, n; 1284 size_t slen, tlen, nlen; 1285 1286 context_to_string(NULL, policydb, scontext, &s, &slen); 1287 context_to_string(NULL, policydb, tcontext, &t, &tlen); 1288 context_to_string(NULL, policydb, newcontext, &n, &nlen); 1289 ERR(NULL, "invalid context %s for " 1290 "scontext=%s tcontext=%s tclass=%s", 1291 n, s, t, policydb->p_class_val_to_name[tclass - 1]); 1292 free(s); 1293 free(t); 1294 free(n); 1295 return 0; 1296 } 1297 } 1298 1299 static int sepol_compute_sid(sepol_security_id_t ssid, 1300 sepol_security_id_t tsid, 1301 sepol_security_class_t tclass, 1302 uint32_t specified, sepol_security_id_t * out_sid) 1303 { 1304 context_struct_t *scontext = 0, *tcontext = 0, newcontext; 1305 struct role_trans *roletr = 0; 1306 avtab_key_t avkey; 1307 avtab_datum_t *avdatum; 1308 avtab_ptr_t node; 1309 int rc = 0; 1310 1311 scontext = sepol_sidtab_search(sidtab, ssid); 1312 if (!scontext) { 1313 ERR(NULL, "unrecognized SID %d", ssid); 1314 rc = -EINVAL; 1315 goto out; 1316 } 1317 tcontext = sepol_sidtab_search(sidtab, tsid); 1318 if (!tcontext) { 1319 ERR(NULL, "unrecognized SID %d", tsid); 1320 rc = -EINVAL; 1321 goto out; 1322 } 1323 1324 context_init(&newcontext); 1325 1326 /* Set the user identity. */ 1327 switch (specified) { 1328 case AVTAB_TRANSITION: 1329 case AVTAB_CHANGE: 1330 /* Use the process user identity. */ 1331 newcontext.user = scontext->user; 1332 break; 1333 case AVTAB_MEMBER: 1334 /* Use the related object owner. */ 1335 newcontext.user = tcontext->user; 1336 break; 1337 } 1338 1339 /* Set the role and type to default values. */ 1340 switch (tclass) { 1341 case SECCLASS_PROCESS: 1342 /* Use the current role and type of process. */ 1343 newcontext.role = scontext->role; 1344 newcontext.type = scontext->type; 1345 break; 1346 default: 1347 /* Use the well-defined object role. */ 1348 newcontext.role = OBJECT_R_VAL; 1349 /* Use the type of the related object. */ 1350 newcontext.type = tcontext->type; 1351 } 1352 1353 /* Look for a type transition/member/change rule. */ 1354 avkey.source_type = scontext->type; 1355 avkey.target_type = tcontext->type; 1356 avkey.target_class = tclass; 1357 avkey.specified = specified; 1358 avdatum = avtab_search(&policydb->te_avtab, &avkey); 1359 1360 /* If no permanent rule, also check for enabled conditional rules */ 1361 if (!avdatum) { 1362 node = avtab_search_node(&policydb->te_cond_avtab, &avkey); 1363 for (; node != NULL; 1364 node = avtab_search_node_next(node, specified)) { 1365 if (node->key.specified & AVTAB_ENABLED) { 1366 avdatum = &node->datum; 1367 break; 1368 } 1369 } 1370 } 1371 1372 if (avdatum) { 1373 /* Use the type from the type transition/member/change rule. */ 1374 newcontext.type = avdatum->data; 1375 } 1376 1377 /* Check for class-specific changes. */ 1378 switch (tclass) { 1379 case SECCLASS_PROCESS: 1380 if (specified & AVTAB_TRANSITION) { 1381 /* Look for a role transition rule. */ 1382 for (roletr = policydb->role_tr; roletr; 1383 roletr = roletr->next) { 1384 if (roletr->role == scontext->role && 1385 roletr->type == tcontext->type) { 1386 /* Use the role transition rule. */ 1387 newcontext.role = roletr->new_role; 1388 break; 1389 } 1390 } 1391 } 1392 break; 1393 default: 1394 break; 1395 } 1396 1397 /* Set the MLS attributes. 1398 This is done last because it may allocate memory. */ 1399 rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified, 1400 &newcontext); 1401 if (rc) 1402 goto out; 1403 1404 /* Check the validity of the context. */ 1405 if (!policydb_context_isvalid(policydb, &newcontext)) { 1406 rc = compute_sid_handle_invalid_context(scontext, 1407 tcontext, 1408 tclass, &newcontext); 1409 if (rc) 1410 goto out; 1411 } 1412 /* Obtain the sid for the context. */ 1413 rc = sepol_sidtab_context_to_sid(sidtab, &newcontext, out_sid); 1414 out: 1415 context_destroy(&newcontext); 1416 return rc; 1417 } 1418 1419 /* 1420 * Compute a SID to use for labeling a new object in the 1421 * class `tclass' based on a SID pair. 1422 */ 1423 int hidden sepol_transition_sid(sepol_security_id_t ssid, 1424 sepol_security_id_t tsid, 1425 sepol_security_class_t tclass, 1426 sepol_security_id_t * out_sid) 1427 { 1428 return sepol_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid); 1429 } 1430 1431 /* 1432 * Compute a SID to use when selecting a member of a 1433 * polyinstantiated object of class `tclass' based on 1434 * a SID pair. 1435 */ 1436 int hidden sepol_member_sid(sepol_security_id_t ssid, 1437 sepol_security_id_t tsid, 1438 sepol_security_class_t tclass, 1439 sepol_security_id_t * out_sid) 1440 { 1441 return sepol_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid); 1442 } 1443 1444 /* 1445 * Compute a SID to use for relabeling an object in the 1446 * class `tclass' based on a SID pair. 1447 */ 1448 int hidden sepol_change_sid(sepol_security_id_t ssid, 1449 sepol_security_id_t tsid, 1450 sepol_security_class_t tclass, 1451 sepol_security_id_t * out_sid) 1452 { 1453 return sepol_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid); 1454 } 1455 1456 /* 1457 * Verify that each permission that is defined under the 1458 * existing policy is still defined with the same value 1459 * in the new policy. 1460 */ 1461 static int validate_perm(hashtab_key_t key, hashtab_datum_t datum, void *p) 1462 { 1463 hashtab_t h; 1464 perm_datum_t *perdatum, *perdatum2; 1465 1466 h = (hashtab_t) p; 1467 perdatum = (perm_datum_t *) datum; 1468 1469 perdatum2 = (perm_datum_t *) hashtab_search(h, key); 1470 if (!perdatum2) { 1471 ERR(NULL, "permission %s disappeared", key); 1472 return -1; 1473 } 1474 if (perdatum->s.value != perdatum2->s.value) { 1475 ERR(NULL, "the value of permissions %s changed", key); 1476 return -1; 1477 } 1478 return 0; 1479 } 1480 1481 /* 1482 * Verify that each class that is defined under the 1483 * existing policy is still defined with the same 1484 * attributes in the new policy. 1485 */ 1486 static int validate_class(hashtab_key_t key, hashtab_datum_t datum, void *p) 1487 { 1488 policydb_t *newp; 1489 class_datum_t *cladatum, *cladatum2; 1490 1491 newp = (policydb_t *) p; 1492 cladatum = (class_datum_t *) datum; 1493 1494 cladatum2 = 1495 (class_datum_t *) hashtab_search(newp->p_classes.table, key); 1496 if (!cladatum2) { 1497 ERR(NULL, "class %s disappeared", key); 1498 return -1; 1499 } 1500 if (cladatum->s.value != cladatum2->s.value) { 1501 ERR(NULL, "the value of class %s changed", key); 1502 return -1; 1503 } 1504 if ((cladatum->comdatum && !cladatum2->comdatum) || 1505 (!cladatum->comdatum && cladatum2->comdatum)) { 1506 ERR(NULL, "the inherits clause for the access " 1507 "vector definition for class %s changed", key); 1508 return -1; 1509 } 1510 if (cladatum->comdatum) { 1511 if (hashtab_map 1512 (cladatum->comdatum->permissions.table, validate_perm, 1513 cladatum2->comdatum->permissions.table)) { 1514 ERR(NULL, 1515 " in the access vector definition " 1516 "for class %s\n", key); 1517 return -1; 1518 } 1519 } 1520 if (hashtab_map(cladatum->permissions.table, validate_perm, 1521 cladatum2->permissions.table)) { 1522 ERR(NULL, " in access vector definition for class %s", key); 1523 return -1; 1524 } 1525 return 0; 1526 } 1527 1528 /* Clone the SID into the new SID table. */ 1529 static int clone_sid(sepol_security_id_t sid, 1530 context_struct_t * context, void *arg) 1531 { 1532 sidtab_t *s = arg; 1533 1534 return sepol_sidtab_insert(s, sid, context); 1535 } 1536 1537 static inline int convert_context_handle_invalid_context(context_struct_t * 1538 context) 1539 { 1540 if (selinux_enforcing) { 1541 return -EINVAL; 1542 } else { 1543 sepol_security_context_t s; 1544 size_t len; 1545 1546 context_to_string(NULL, policydb, context, &s, &len); 1547 ERR(NULL, "context %s is invalid", s); 1548 free(s); 1549 return 0; 1550 } 1551 } 1552 1553 typedef struct { 1554 policydb_t *oldp; 1555 policydb_t *newp; 1556 } convert_context_args_t; 1557 1558 /* 1559 * Convert the values in the security context 1560 * structure `c' from the values specified 1561 * in the policy `p->oldp' to the values specified 1562 * in the policy `p->newp'. Verify that the 1563 * context is valid under the new policy. 1564 */ 1565 static int convert_context(sepol_security_id_t key __attribute__ ((unused)), 1566 context_struct_t * c, void *p) 1567 { 1568 convert_context_args_t *args; 1569 context_struct_t oldc; 1570 role_datum_t *role; 1571 type_datum_t *typdatum; 1572 user_datum_t *usrdatum; 1573 sepol_security_context_t s; 1574 size_t len; 1575 int rc = -EINVAL; 1576 1577 args = (convert_context_args_t *) p; 1578 1579 if (context_cpy(&oldc, c)) 1580 return -ENOMEM; 1581 1582 /* Convert the user. */ 1583 usrdatum = (user_datum_t *) hashtab_search(args->newp->p_users.table, 1584 args->oldp-> 1585 p_user_val_to_name[c->user - 1586 1]); 1587 1588 if (!usrdatum) { 1589 goto bad; 1590 } 1591 c->user = usrdatum->s.value; 1592 1593 /* Convert the role. */ 1594 role = (role_datum_t *) hashtab_search(args->newp->p_roles.table, 1595 args->oldp-> 1596 p_role_val_to_name[c->role - 1]); 1597 if (!role) { 1598 goto bad; 1599 } 1600 c->role = role->s.value; 1601 1602 /* Convert the type. */ 1603 typdatum = (type_datum_t *) 1604 hashtab_search(args->newp->p_types.table, 1605 args->oldp->p_type_val_to_name[c->type - 1]); 1606 if (!typdatum) { 1607 goto bad; 1608 } 1609 c->type = typdatum->s.value; 1610 1611 rc = mls_convert_context(args->oldp, args->newp, c); 1612 if (rc) 1613 goto bad; 1614 1615 /* Check the validity of the new context. */ 1616 if (!policydb_context_isvalid(args->newp, c)) { 1617 rc = convert_context_handle_invalid_context(&oldc); 1618 if (rc) 1619 goto bad; 1620 } 1621 1622 context_destroy(&oldc); 1623 return 0; 1624 1625 bad: 1626 context_to_string(NULL, policydb, &oldc, &s, &len); 1627 context_destroy(&oldc); 1628 ERR(NULL, "invalidating context %s", s); 1629 free(s); 1630 return rc; 1631 } 1632 1633 /* Reading from a policy "file". */ 1634 int hidden next_entry(void *buf, struct policy_file *fp, size_t bytes) 1635 { 1636 size_t nread; 1637 1638 switch (fp->type) { 1639 case PF_USE_STDIO: 1640 nread = fread(buf, bytes, 1, fp->fp); 1641 1642 if (nread != 1) 1643 return -1; 1644 break; 1645 case PF_USE_MEMORY: 1646 if (bytes > fp->len) 1647 return -1; 1648 memcpy(buf, fp->data, bytes); 1649 fp->data += bytes; 1650 fp->len -= bytes; 1651 break; 1652 default: 1653 return -1; 1654 } 1655 return 0; 1656 } 1657 1658 size_t hidden put_entry(const void *ptr, size_t size, size_t n, 1659 struct policy_file *fp) 1660 { 1661 size_t bytes = size * n; 1662 1663 switch (fp->type) { 1664 case PF_USE_STDIO: 1665 return fwrite(ptr, size, n, fp->fp); 1666 case PF_USE_MEMORY: 1667 if (bytes > fp->len) { 1668 errno = ENOSPC; 1669 return 0; 1670 } 1671 1672 memcpy(fp->data, ptr, bytes); 1673 fp->data += bytes; 1674 fp->len -= bytes; 1675 return n; 1676 case PF_LEN: 1677 fp->len += bytes; 1678 return n; 1679 default: 1680 return 0; 1681 } 1682 return 0; 1683 } 1684 1685 /* 1686 * Read a new set of configuration data from 1687 * a policy database binary representation file. 1688 * 1689 * Verify that each class that is defined under the 1690 * existing policy is still defined with the same 1691 * attributes in the new policy. 1692 * 1693 * Convert the context structures in the SID table to the 1694 * new representation and verify that all entries 1695 * in the SID table are valid under the new policy. 1696 * 1697 * Change the active policy database to use the new 1698 * configuration data. 1699 * 1700 * Reset the access vector cache. 1701 */ 1702 int hidden sepol_load_policy(void *data, size_t len) 1703 { 1704 policydb_t oldpolicydb, newpolicydb; 1705 sidtab_t oldsidtab, newsidtab; 1706 convert_context_args_t args; 1707 int rc = 0; 1708 struct policy_file file, *fp; 1709 1710 policy_file_init(&file); 1711 file.type = PF_USE_MEMORY; 1712 file.data = data; 1713 file.len = len; 1714 fp = &file; 1715 1716 if (policydb_init(&newpolicydb)) 1717 return -ENOMEM; 1718 1719 if (policydb_read(&newpolicydb, fp, 1)) { 1720 policydb_destroy(&mypolicydb); 1721 return -EINVAL; 1722 } 1723 1724 sepol_sidtab_init(&newsidtab); 1725 1726 /* Verify that the existing classes did not change. */ 1727 if (hashtab_map 1728 (policydb->p_classes.table, validate_class, &newpolicydb)) { 1729 ERR(NULL, "the definition of an existing class changed"); 1730 rc = -EINVAL; 1731 goto err; 1732 } 1733 1734 /* Clone the SID table. */ 1735 sepol_sidtab_shutdown(sidtab); 1736 if (sepol_sidtab_map(sidtab, clone_sid, &newsidtab)) { 1737 rc = -ENOMEM; 1738 goto err; 1739 } 1740 1741 /* Convert the internal representations of contexts 1742 in the new SID table and remove invalid SIDs. */ 1743 args.oldp = policydb; 1744 args.newp = &newpolicydb; 1745 sepol_sidtab_map_remove_on_error(&newsidtab, convert_context, &args); 1746 1747 /* Save the old policydb and SID table to free later. */ 1748 memcpy(&oldpolicydb, policydb, sizeof *policydb); 1749 sepol_sidtab_set(&oldsidtab, sidtab); 1750 1751 /* Install the new policydb and SID table. */ 1752 memcpy(policydb, &newpolicydb, sizeof *policydb); 1753 sepol_sidtab_set(sidtab, &newsidtab); 1754 1755 /* Free the old policydb and SID table. */ 1756 policydb_destroy(&oldpolicydb); 1757 sepol_sidtab_destroy(&oldsidtab); 1758 1759 return 0; 1760 1761 err: 1762 sepol_sidtab_destroy(&newsidtab); 1763 policydb_destroy(&newpolicydb); 1764 return rc; 1765 1766 } 1767 1768 /* 1769 * Return the SIDs to use for an unlabeled file system 1770 * that is being mounted from the device with the 1771 * the kdevname `name'. The `fs_sid' SID is returned for 1772 * the file system and the `file_sid' SID is returned 1773 * for all files within that file system. 1774 */ 1775 int hidden sepol_fs_sid(char *name, 1776 sepol_security_id_t * fs_sid, 1777 sepol_security_id_t * file_sid) 1778 { 1779 int rc = 0; 1780 ocontext_t *c; 1781 1782 c = policydb->ocontexts[OCON_FS]; 1783 while (c) { 1784 if (strcmp(c->u.name, name) == 0) 1785 break; 1786 c = c->next; 1787 } 1788 1789 if (c) { 1790 if (!c->sid[0] || !c->sid[1]) { 1791 rc = sepol_sidtab_context_to_sid(sidtab, 1792 &c->context[0], 1793 &c->sid[0]); 1794 if (rc) 1795 goto out; 1796 rc = sepol_sidtab_context_to_sid(sidtab, 1797 &c->context[1], 1798 &c->sid[1]); 1799 if (rc) 1800 goto out; 1801 } 1802 *fs_sid = c->sid[0]; 1803 *file_sid = c->sid[1]; 1804 } else { 1805 *fs_sid = SECINITSID_FS; 1806 *file_sid = SECINITSID_FILE; 1807 } 1808 1809 out: 1810 return rc; 1811 } 1812 1813 /* 1814 * Return the SID of the port specified by 1815 * `domain', `type', `protocol', and `port'. 1816 */ 1817 int hidden sepol_port_sid(uint16_t domain __attribute__ ((unused)), 1818 uint16_t type __attribute__ ((unused)), 1819 uint8_t protocol, 1820 uint16_t port, sepol_security_id_t * out_sid) 1821 { 1822 ocontext_t *c; 1823 int rc = 0; 1824 1825 c = policydb->ocontexts[OCON_PORT]; 1826 while (c) { 1827 if (c->u.port.protocol == protocol && 1828 c->u.port.low_port <= port && c->u.port.high_port >= port) 1829 break; 1830 c = c->next; 1831 } 1832 1833 if (c) { 1834 if (!c->sid[0]) { 1835 rc = sepol_sidtab_context_to_sid(sidtab, 1836 &c->context[0], 1837 &c->sid[0]); 1838 if (rc) 1839 goto out; 1840 } 1841 *out_sid = c->sid[0]; 1842 } else { 1843 *out_sid = SECINITSID_PORT; 1844 } 1845 1846 out: 1847 return rc; 1848 } 1849 1850 /* 1851 * Return the SIDs to use for a network interface 1852 * with the name `name'. The `if_sid' SID is returned for 1853 * the interface and the `msg_sid' SID is returned as 1854 * the default SID for messages received on the 1855 * interface. 1856 */ 1857 int hidden sepol_netif_sid(char *name, 1858 sepol_security_id_t * if_sid, 1859 sepol_security_id_t * msg_sid) 1860 { 1861 int rc = 0; 1862 ocontext_t *c; 1863 1864 c = policydb->ocontexts[OCON_NETIF]; 1865 while (c) { 1866 if (strcmp(name, c->u.name) == 0) 1867 break; 1868 c = c->next; 1869 } 1870 1871 if (c) { 1872 if (!c->sid[0] || !c->sid[1]) { 1873 rc = sepol_sidtab_context_to_sid(sidtab, 1874 &c->context[0], 1875 &c->sid[0]); 1876 if (rc) 1877 goto out; 1878 rc = sepol_sidtab_context_to_sid(sidtab, 1879 &c->context[1], 1880 &c->sid[1]); 1881 if (rc) 1882 goto out; 1883 } 1884 *if_sid = c->sid[0]; 1885 *msg_sid = c->sid[1]; 1886 } else { 1887 *if_sid = SECINITSID_NETIF; 1888 *msg_sid = SECINITSID_NETMSG; 1889 } 1890 1891 out: 1892 return rc; 1893 } 1894 1895 static int match_ipv6_addrmask(uint32_t * input, uint32_t * addr, 1896 uint32_t * mask) 1897 { 1898 int i, fail = 0; 1899 1900 for (i = 0; i < 4; i++) 1901 if (addr[i] != (input[i] & mask[i])) { 1902 fail = 1; 1903 break; 1904 } 1905 1906 return !fail; 1907 } 1908 1909 /* 1910 * Return the SID of the node specified by the address 1911 * `addrp' where `addrlen' is the length of the address 1912 * in bytes and `domain' is the communications domain or 1913 * address family in which the address should be interpreted. 1914 */ 1915 int hidden sepol_node_sid(uint16_t domain, 1916 void *addrp, 1917 size_t addrlen, sepol_security_id_t * out_sid) 1918 { 1919 int rc = 0; 1920 ocontext_t *c; 1921 1922 switch (domain) { 1923 case AF_INET:{ 1924 uint32_t addr; 1925 1926 if (addrlen != sizeof(uint32_t)) { 1927 rc = -EINVAL; 1928 goto out; 1929 } 1930 1931 addr = *((uint32_t *) addrp); 1932 1933 c = policydb->ocontexts[OCON_NODE]; 1934 while (c) { 1935 if (c->u.node.addr == (addr & c->u.node.mask)) 1936 break; 1937 c = c->next; 1938 } 1939 break; 1940 } 1941 1942 case AF_INET6: 1943 if (addrlen != sizeof(uint64_t) * 2) { 1944 rc = -EINVAL; 1945 goto out; 1946 } 1947 1948 c = policydb->ocontexts[OCON_NODE6]; 1949 while (c) { 1950 if (match_ipv6_addrmask(addrp, c->u.node6.addr, 1951 c->u.node6.mask)) 1952 break; 1953 c = c->next; 1954 } 1955 break; 1956 1957 default: 1958 *out_sid = SECINITSID_NODE; 1959 goto out; 1960 } 1961 1962 if (c) { 1963 if (!c->sid[0]) { 1964 rc = sepol_sidtab_context_to_sid(sidtab, 1965 &c->context[0], 1966 &c->sid[0]); 1967 if (rc) 1968 goto out; 1969 } 1970 *out_sid = c->sid[0]; 1971 } else { 1972 *out_sid = SECINITSID_NODE; 1973 } 1974 1975 out: 1976 return rc; 1977 } 1978 1979 /* 1980 * Generate the set of SIDs for legal security contexts 1981 * for a given user that can be reached by `fromsid'. 1982 * Set `*sids' to point to a dynamically allocated 1983 * array containing the set of SIDs. Set `*nel' to the 1984 * number of elements in the array. 1985 */ 1986 #define SIDS_NEL 25 1987 1988 int hidden sepol_get_user_sids(sepol_security_id_t fromsid, 1989 char *username, 1990 sepol_security_id_t ** sids, uint32_t * nel) 1991 { 1992 context_struct_t *fromcon, usercon; 1993 sepol_security_id_t *mysids, *mysids2, sid; 1994 uint32_t mynel = 0, maxnel = SIDS_NEL; 1995 user_datum_t *user; 1996 role_datum_t *role; 1997 struct sepol_av_decision avd; 1998 int rc = 0; 1999 unsigned int i, j, reason; 2000 ebitmap_node_t *rnode, *tnode; 2001 2002 fromcon = sepol_sidtab_search(sidtab, fromsid); 2003 if (!fromcon) { 2004 rc = -EINVAL; 2005 goto out; 2006 } 2007 2008 user = (user_datum_t *) hashtab_search(policydb->p_users.table, 2009 username); 2010 if (!user) { 2011 rc = -EINVAL; 2012 goto out; 2013 } 2014 usercon.user = user->s.value; 2015 2016 mysids = malloc(maxnel * sizeof(sepol_security_id_t)); 2017 if (!mysids) { 2018 rc = -ENOMEM; 2019 goto out; 2020 } 2021 memset(mysids, 0, maxnel * sizeof(sepol_security_id_t)); 2022 2023 ebitmap_for_each_bit(&user->roles.roles, rnode, i) { 2024 if (!ebitmap_node_get_bit(rnode, i)) 2025 continue; 2026 role = policydb->role_val_to_struct[i]; 2027 usercon.role = i + 1; 2028 ebitmap_for_each_bit(&role->types.types, tnode, j) { 2029 if (!ebitmap_node_get_bit(tnode, j)) 2030 continue; 2031 usercon.type = j + 1; 2032 if (usercon.type == fromcon->type) 2033 continue; 2034 2035 if (mls_setup_user_range 2036 (fromcon, user, &usercon, policydb->mls)) 2037 continue; 2038 2039 rc = context_struct_compute_av(fromcon, &usercon, 2040 SECCLASS_PROCESS, 2041 PROCESS__TRANSITION, 2042 &avd, &reason, NULL, 0); 2043 if (rc || !(avd.allowed & PROCESS__TRANSITION)) 2044 continue; 2045 rc = sepol_sidtab_context_to_sid(sidtab, &usercon, 2046 &sid); 2047 if (rc) { 2048 free(mysids); 2049 goto out; 2050 } 2051 if (mynel < maxnel) { 2052 mysids[mynel++] = sid; 2053 } else { 2054 maxnel += SIDS_NEL; 2055 mysids2 = 2056 malloc(maxnel * 2057 sizeof(sepol_security_id_t)); 2058 2059 if (!mysids2) { 2060 rc = -ENOMEM; 2061 free(mysids); 2062 goto out; 2063 } 2064 memset(mysids2, 0, 2065 maxnel * sizeof(sepol_security_id_t)); 2066 memcpy(mysids2, mysids, 2067 mynel * sizeof(sepol_security_id_t)); 2068 free(mysids); 2069 mysids = mysids2; 2070 mysids[mynel++] = sid; 2071 } 2072 } 2073 } 2074 2075 *sids = mysids; 2076 *nel = mynel; 2077 2078 out: 2079 return rc; 2080 } 2081 2082 /* 2083 * Return the SID to use for a file in a filesystem 2084 * that cannot support a persistent label mapping or use another 2085 * fixed labeling behavior like transition SIDs or task SIDs. 2086 */ 2087 int hidden sepol_genfs_sid(const char *fstype, 2088 const char *path, 2089 sepol_security_class_t sclass, 2090 sepol_security_id_t * sid) 2091 { 2092 size_t len; 2093 genfs_t *genfs; 2094 ocontext_t *c; 2095 int rc = 0, cmp = 0; 2096 2097 for (genfs = policydb->genfs; genfs; genfs = genfs->next) { 2098 cmp = strcmp(fstype, genfs->fstype); 2099 if (cmp <= 0) 2100 break; 2101 } 2102 2103 if (!genfs || cmp) { 2104 *sid = SECINITSID_UNLABELED; 2105 rc = -ENOENT; 2106 goto out; 2107 } 2108 2109 for (c = genfs->head; c; c = c->next) { 2110 len = strlen(c->u.name); 2111 if ((!c->v.sclass || sclass == c->v.sclass) && 2112 (strncmp(c->u.name, path, len) == 0)) 2113 break; 2114 } 2115 2116 if (!c) { 2117 *sid = SECINITSID_UNLABELED; 2118 rc = -ENOENT; 2119 goto out; 2120 } 2121 2122 if (!c->sid[0]) { 2123 rc = sepol_sidtab_context_to_sid(sidtab, 2124 &c->context[0], &c->sid[0]); 2125 if (rc) 2126 goto out; 2127 } 2128 2129 *sid = c->sid[0]; 2130 out: 2131 return rc; 2132 } 2133 2134 int hidden sepol_fs_use(const char *fstype, 2135 unsigned int *behavior, sepol_security_id_t * sid) 2136 { 2137 int rc = 0; 2138 ocontext_t *c; 2139 2140 c = policydb->ocontexts[OCON_FSUSE]; 2141 while (c) { 2142 if (strcmp(fstype, c->u.name) == 0) 2143 break; 2144 c = c->next; 2145 } 2146 2147 if (c) { 2148 *behavior = c->v.behavior; 2149 if (!c->sid[0]) { 2150 rc = sepol_sidtab_context_to_sid(sidtab, 2151 &c->context[0], 2152 &c->sid[0]); 2153 if (rc) 2154 goto out; 2155 } 2156 *sid = c->sid[0]; 2157 } else { 2158 rc = sepol_genfs_sid(fstype, "/", SECCLASS_DIR, sid); 2159 if (rc) { 2160 *behavior = SECURITY_FS_USE_NONE; 2161 rc = 0; 2162 } else { 2163 *behavior = SECURITY_FS_USE_GENFS; 2164 } 2165 } 2166 2167 out: 2168 return rc; 2169 } 2170 2171 /* FLASK */ 2172