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