condition.c (27759B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * security/tomoyo/condition.c 4 * 5 * Copyright (C) 2005-2011 NTT DATA CORPORATION 6 */ 7 8#include "common.h" 9#include <linux/slab.h> 10 11/* List of "struct tomoyo_condition". */ 12LIST_HEAD(tomoyo_condition_list); 13 14/** 15 * tomoyo_argv - Check argv[] in "struct linux_binbrm". 16 * 17 * @index: Index number of @arg_ptr. 18 * @arg_ptr: Contents of argv[@index]. 19 * @argc: Length of @argv. 20 * @argv: Pointer to "struct tomoyo_argv". 21 * @checked: Set to true if @argv[@index] was found. 22 * 23 * Returns true on success, false otherwise. 24 */ 25static bool tomoyo_argv(const unsigned int index, const char *arg_ptr, 26 const int argc, const struct tomoyo_argv *argv, 27 u8 *checked) 28{ 29 int i; 30 struct tomoyo_path_info arg; 31 32 arg.name = arg_ptr; 33 for (i = 0; i < argc; argv++, checked++, i++) { 34 bool result; 35 36 if (index != argv->index) 37 continue; 38 *checked = 1; 39 tomoyo_fill_path_info(&arg); 40 result = tomoyo_path_matches_pattern(&arg, argv->value); 41 if (argv->is_not) 42 result = !result; 43 if (!result) 44 return false; 45 } 46 return true; 47} 48 49/** 50 * tomoyo_envp - Check envp[] in "struct linux_binbrm". 51 * 52 * @env_name: The name of environment variable. 53 * @env_value: The value of environment variable. 54 * @envc: Length of @envp. 55 * @envp: Pointer to "struct tomoyo_envp". 56 * @checked: Set to true if @envp[@env_name] was found. 57 * 58 * Returns true on success, false otherwise. 59 */ 60static bool tomoyo_envp(const char *env_name, const char *env_value, 61 const int envc, const struct tomoyo_envp *envp, 62 u8 *checked) 63{ 64 int i; 65 struct tomoyo_path_info name; 66 struct tomoyo_path_info value; 67 68 name.name = env_name; 69 tomoyo_fill_path_info(&name); 70 value.name = env_value; 71 tomoyo_fill_path_info(&value); 72 for (i = 0; i < envc; envp++, checked++, i++) { 73 bool result; 74 75 if (!tomoyo_path_matches_pattern(&name, envp->name)) 76 continue; 77 *checked = 1; 78 if (envp->value) { 79 result = tomoyo_path_matches_pattern(&value, 80 envp->value); 81 if (envp->is_not) 82 result = !result; 83 } else { 84 result = true; 85 if (!envp->is_not) 86 result = !result; 87 } 88 if (!result) 89 return false; 90 } 91 return true; 92} 93 94/** 95 * tomoyo_scan_bprm - Scan "struct linux_binprm". 96 * 97 * @ee: Pointer to "struct tomoyo_execve". 98 * @argc: Length of @argc. 99 * @argv: Pointer to "struct tomoyo_argv". 100 * @envc: Length of @envp. 101 * @envp: Pointer to "struct tomoyo_envp". 102 * 103 * Returns true on success, false otherwise. 104 */ 105static bool tomoyo_scan_bprm(struct tomoyo_execve *ee, 106 const u16 argc, const struct tomoyo_argv *argv, 107 const u16 envc, const struct tomoyo_envp *envp) 108{ 109 struct linux_binprm *bprm = ee->bprm; 110 struct tomoyo_page_dump *dump = &ee->dump; 111 char *arg_ptr = ee->tmp; 112 int arg_len = 0; 113 unsigned long pos = bprm->p; 114 int offset = pos % PAGE_SIZE; 115 int argv_count = bprm->argc; 116 int envp_count = bprm->envc; 117 bool result = true; 118 u8 local_checked[32]; 119 u8 *checked; 120 121 if (argc + envc <= sizeof(local_checked)) { 122 checked = local_checked; 123 memset(local_checked, 0, sizeof(local_checked)); 124 } else { 125 checked = kzalloc(argc + envc, GFP_NOFS); 126 if (!checked) 127 return false; 128 } 129 while (argv_count || envp_count) { 130 if (!tomoyo_dump_page(bprm, pos, dump)) { 131 result = false; 132 goto out; 133 } 134 pos += PAGE_SIZE - offset; 135 while (offset < PAGE_SIZE) { 136 /* Read. */ 137 const char *kaddr = dump->data; 138 const unsigned char c = kaddr[offset++]; 139 140 if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) { 141 if (c == '\\') { 142 arg_ptr[arg_len++] = '\\'; 143 arg_ptr[arg_len++] = '\\'; 144 } else if (c > ' ' && c < 127) { 145 arg_ptr[arg_len++] = c; 146 } else { 147 arg_ptr[arg_len++] = '\\'; 148 arg_ptr[arg_len++] = (c >> 6) + '0'; 149 arg_ptr[arg_len++] = 150 ((c >> 3) & 7) + '0'; 151 arg_ptr[arg_len++] = (c & 7) + '0'; 152 } 153 } else { 154 arg_ptr[arg_len] = '\0'; 155 } 156 if (c) 157 continue; 158 /* Check. */ 159 if (argv_count) { 160 if (!tomoyo_argv(bprm->argc - argv_count, 161 arg_ptr, argc, argv, 162 checked)) { 163 result = false; 164 break; 165 } 166 argv_count--; 167 } else if (envp_count) { 168 char *cp = strchr(arg_ptr, '='); 169 170 if (cp) { 171 *cp = '\0'; 172 if (!tomoyo_envp(arg_ptr, cp + 1, 173 envc, envp, 174 checked + argc)) { 175 result = false; 176 break; 177 } 178 } 179 envp_count--; 180 } else { 181 break; 182 } 183 arg_len = 0; 184 } 185 offset = 0; 186 if (!result) 187 break; 188 } 189out: 190 if (result) { 191 int i; 192 193 /* Check not-yet-checked entries. */ 194 for (i = 0; i < argc; i++) { 195 if (checked[i]) 196 continue; 197 /* 198 * Return true only if all unchecked indexes in 199 * bprm->argv[] are not matched. 200 */ 201 if (argv[i].is_not) 202 continue; 203 result = false; 204 break; 205 } 206 for (i = 0; i < envc; envp++, i++) { 207 if (checked[argc + i]) 208 continue; 209 /* 210 * Return true only if all unchecked environ variables 211 * in bprm->envp[] are either undefined or not matched. 212 */ 213 if ((!envp->value && !envp->is_not) || 214 (envp->value && envp->is_not)) 215 continue; 216 result = false; 217 break; 218 } 219 } 220 if (checked != local_checked) 221 kfree(checked); 222 return result; 223} 224 225/** 226 * tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition". 227 * 228 * @file: Pointer to "struct file". 229 * @ptr: Pointer to "struct tomoyo_name_union". 230 * @match: True if "exec.realpath=", false if "exec.realpath!=". 231 * 232 * Returns true on success, false otherwise. 233 */ 234static bool tomoyo_scan_exec_realpath(struct file *file, 235 const struct tomoyo_name_union *ptr, 236 const bool match) 237{ 238 bool result; 239 struct tomoyo_path_info exe; 240 241 if (!file) 242 return false; 243 exe.name = tomoyo_realpath_from_path(&file->f_path); 244 if (!exe.name) 245 return false; 246 tomoyo_fill_path_info(&exe); 247 result = tomoyo_compare_name_union(&exe, ptr); 248 kfree(exe.name); 249 return result == match; 250} 251 252/** 253 * tomoyo_get_dqword - tomoyo_get_name() for a quoted string. 254 * 255 * @start: String to save. 256 * 257 * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. 258 */ 259static const struct tomoyo_path_info *tomoyo_get_dqword(char *start) 260{ 261 char *cp = start + strlen(start) - 1; 262 263 if (cp == start || *start++ != '"' || *cp != '"') 264 return NULL; 265 *cp = '\0'; 266 if (*start && !tomoyo_correct_word(start)) 267 return NULL; 268 return tomoyo_get_name(start); 269} 270 271/** 272 * tomoyo_parse_name_union_quoted - Parse a quoted word. 273 * 274 * @param: Pointer to "struct tomoyo_acl_param". 275 * @ptr: Pointer to "struct tomoyo_name_union". 276 * 277 * Returns true on success, false otherwise. 278 */ 279static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param, 280 struct tomoyo_name_union *ptr) 281{ 282 char *filename = param->data; 283 284 if (*filename == '@') 285 return tomoyo_parse_name_union(param, ptr); 286 ptr->filename = tomoyo_get_dqword(filename); 287 return ptr->filename != NULL; 288} 289 290/** 291 * tomoyo_parse_argv - Parse an argv[] condition part. 292 * 293 * @left: Lefthand value. 294 * @right: Righthand value. 295 * @argv: Pointer to "struct tomoyo_argv". 296 * 297 * Returns true on success, false otherwise. 298 */ 299static bool tomoyo_parse_argv(char *left, char *right, 300 struct tomoyo_argv *argv) 301{ 302 if (tomoyo_parse_ulong(&argv->index, &left) != 303 TOMOYO_VALUE_TYPE_DECIMAL || *left++ != ']' || *left) 304 return false; 305 argv->value = tomoyo_get_dqword(right); 306 return argv->value != NULL; 307} 308 309/** 310 * tomoyo_parse_envp - Parse an envp[] condition part. 311 * 312 * @left: Lefthand value. 313 * @right: Righthand value. 314 * @envp: Pointer to "struct tomoyo_envp". 315 * 316 * Returns true on success, false otherwise. 317 */ 318static bool tomoyo_parse_envp(char *left, char *right, 319 struct tomoyo_envp *envp) 320{ 321 const struct tomoyo_path_info *name; 322 const struct tomoyo_path_info *value; 323 char *cp = left + strlen(left) - 1; 324 325 if (*cp-- != ']' || *cp != '"') 326 goto out; 327 *cp = '\0'; 328 if (!tomoyo_correct_word(left)) 329 goto out; 330 name = tomoyo_get_name(left); 331 if (!name) 332 goto out; 333 if (!strcmp(right, "NULL")) { 334 value = NULL; 335 } else { 336 value = tomoyo_get_dqword(right); 337 if (!value) { 338 tomoyo_put_name(name); 339 goto out; 340 } 341 } 342 envp->name = name; 343 envp->value = value; 344 return true; 345out: 346 return false; 347} 348 349/** 350 * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry. 351 * 352 * @a: Pointer to "struct tomoyo_condition". 353 * @b: Pointer to "struct tomoyo_condition". 354 * 355 * Returns true if @a == @b, false otherwise. 356 */ 357static inline bool tomoyo_same_condition(const struct tomoyo_condition *a, 358 const struct tomoyo_condition *b) 359{ 360 return a->size == b->size && a->condc == b->condc && 361 a->numbers_count == b->numbers_count && 362 a->names_count == b->names_count && 363 a->argc == b->argc && a->envc == b->envc && 364 a->grant_log == b->grant_log && a->transit == b->transit && 365 !memcmp(a + 1, b + 1, a->size - sizeof(*a)); 366} 367 368/** 369 * tomoyo_condition_type - Get condition type. 370 * 371 * @word: Keyword string. 372 * 373 * Returns one of values in "enum tomoyo_conditions_index" on success, 374 * TOMOYO_MAX_CONDITION_KEYWORD otherwise. 375 */ 376static u8 tomoyo_condition_type(const char *word) 377{ 378 u8 i; 379 380 for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) { 381 if (!strcmp(word, tomoyo_condition_keyword[i])) 382 break; 383 } 384 return i; 385} 386 387/* Define this to enable debug mode. */ 388/* #define DEBUG_CONDITION */ 389 390#ifdef DEBUG_CONDITION 391#define dprintk printk 392#else 393#define dprintk(...) do { } while (0) 394#endif 395 396/** 397 * tomoyo_commit_condition - Commit "struct tomoyo_condition". 398 * 399 * @entry: Pointer to "struct tomoyo_condition". 400 * 401 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise. 402 * 403 * This function merges duplicated entries. This function returns NULL if 404 * @entry is not duplicated but memory quota for policy has exceeded. 405 */ 406static struct tomoyo_condition *tomoyo_commit_condition 407(struct tomoyo_condition *entry) 408{ 409 struct tomoyo_condition *ptr; 410 bool found = false; 411 412 if (mutex_lock_interruptible(&tomoyo_policy_lock)) { 413 dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__); 414 ptr = NULL; 415 found = true; 416 goto out; 417 } 418 list_for_each_entry(ptr, &tomoyo_condition_list, head.list) { 419 if (!tomoyo_same_condition(ptr, entry) || 420 atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS) 421 continue; 422 /* Same entry found. Share this entry. */ 423 atomic_inc(&ptr->head.users); 424 found = true; 425 break; 426 } 427 if (!found) { 428 if (tomoyo_memory_ok(entry)) { 429 atomic_set(&entry->head.users, 1); 430 list_add(&entry->head.list, &tomoyo_condition_list); 431 } else { 432 found = true; 433 ptr = NULL; 434 } 435 } 436 mutex_unlock(&tomoyo_policy_lock); 437out: 438 if (found) { 439 tomoyo_del_condition(&entry->head.list); 440 kfree(entry); 441 entry = ptr; 442 } 443 return entry; 444} 445 446/** 447 * tomoyo_get_transit_preference - Parse domain transition preference for execve(). 448 * 449 * @param: Pointer to "struct tomoyo_acl_param". 450 * @e: Pointer to "struct tomoyo_condition". 451 * 452 * Returns the condition string part. 453 */ 454static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param, 455 struct tomoyo_condition *e) 456{ 457 char * const pos = param->data; 458 bool flag; 459 460 if (*pos == '<') { 461 e->transit = tomoyo_get_domainname(param); 462 goto done; 463 } 464 { 465 char *cp = strchr(pos, ' '); 466 467 if (cp) 468 *cp = '\0'; 469 flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") || 470 !strcmp(pos, "initialize") || !strcmp(pos, "reset") || 471 !strcmp(pos, "child") || !strcmp(pos, "parent"); 472 if (cp) 473 *cp = ' '; 474 } 475 if (!flag) 476 return pos; 477 e->transit = tomoyo_get_name(tomoyo_read_token(param)); 478done: 479 if (e->transit) 480 return param->data; 481 /* 482 * Return a bad read-only condition string that will let 483 * tomoyo_get_condition() return NULL. 484 */ 485 return "/"; 486} 487 488/** 489 * tomoyo_get_condition - Parse condition part. 490 * 491 * @param: Pointer to "struct tomoyo_acl_param". 492 * 493 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise. 494 */ 495struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param) 496{ 497 struct tomoyo_condition *entry = NULL; 498 struct tomoyo_condition_element *condp = NULL; 499 struct tomoyo_number_union *numbers_p = NULL; 500 struct tomoyo_name_union *names_p = NULL; 501 struct tomoyo_argv *argv = NULL; 502 struct tomoyo_envp *envp = NULL; 503 struct tomoyo_condition e = { }; 504 char * const start_of_string = 505 tomoyo_get_transit_preference(param, &e); 506 char * const end_of_string = start_of_string + strlen(start_of_string); 507 char *pos; 508 509rerun: 510 pos = start_of_string; 511 while (1) { 512 u8 left = -1; 513 u8 right = -1; 514 char *left_word = pos; 515 char *cp; 516 char *right_word; 517 bool is_not; 518 519 if (!*left_word) 520 break; 521 /* 522 * Since left-hand condition does not allow use of "path_group" 523 * or "number_group" and environment variable's names do not 524 * accept '=', it is guaranteed that the original line consists 525 * of one or more repetition of $left$operator$right blocks 526 * where "$left is free from '=' and ' '" and "$operator is 527 * either '=' or '!='" and "$right is free from ' '". 528 * Therefore, we can reconstruct the original line at the end 529 * of dry run even if we overwrite $operator with '\0'. 530 */ 531 cp = strchr(pos, ' '); 532 if (cp) { 533 *cp = '\0'; /* Will restore later. */ 534 pos = cp + 1; 535 } else { 536 pos = ""; 537 } 538 right_word = strchr(left_word, '='); 539 if (!right_word || right_word == left_word) 540 goto out; 541 is_not = *(right_word - 1) == '!'; 542 if (is_not) 543 *(right_word++ - 1) = '\0'; /* Will restore later. */ 544 else if (*(right_word + 1) != '=') 545 *right_word++ = '\0'; /* Will restore later. */ 546 else 547 goto out; 548 dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word, 549 is_not ? "!" : "", right_word); 550 if (!strcmp(left_word, "grant_log")) { 551 if (entry) { 552 if (is_not || 553 entry->grant_log != TOMOYO_GRANTLOG_AUTO) 554 goto out; 555 else if (!strcmp(right_word, "yes")) 556 entry->grant_log = TOMOYO_GRANTLOG_YES; 557 else if (!strcmp(right_word, "no")) 558 entry->grant_log = TOMOYO_GRANTLOG_NO; 559 else 560 goto out; 561 } 562 continue; 563 } 564 if (!strncmp(left_word, "exec.argv[", 10)) { 565 if (!argv) { 566 e.argc++; 567 e.condc++; 568 } else { 569 e.argc--; 570 e.condc--; 571 left = TOMOYO_ARGV_ENTRY; 572 argv->is_not = is_not; 573 if (!tomoyo_parse_argv(left_word + 10, 574 right_word, argv++)) 575 goto out; 576 } 577 goto store_value; 578 } 579 if (!strncmp(left_word, "exec.envp[\"", 11)) { 580 if (!envp) { 581 e.envc++; 582 e.condc++; 583 } else { 584 e.envc--; 585 e.condc--; 586 left = TOMOYO_ENVP_ENTRY; 587 envp->is_not = is_not; 588 if (!tomoyo_parse_envp(left_word + 11, 589 right_word, envp++)) 590 goto out; 591 } 592 goto store_value; 593 } 594 left = tomoyo_condition_type(left_word); 595 dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word, 596 left); 597 if (left == TOMOYO_MAX_CONDITION_KEYWORD) { 598 if (!numbers_p) { 599 e.numbers_count++; 600 } else { 601 e.numbers_count--; 602 left = TOMOYO_NUMBER_UNION; 603 param->data = left_word; 604 if (*left_word == '@' || 605 !tomoyo_parse_number_union(param, 606 numbers_p++)) 607 goto out; 608 } 609 } 610 if (!condp) 611 e.condc++; 612 else 613 e.condc--; 614 if (left == TOMOYO_EXEC_REALPATH || 615 left == TOMOYO_SYMLINK_TARGET) { 616 if (!names_p) { 617 e.names_count++; 618 } else { 619 e.names_count--; 620 right = TOMOYO_NAME_UNION; 621 param->data = right_word; 622 if (!tomoyo_parse_name_union_quoted(param, 623 names_p++)) 624 goto out; 625 } 626 goto store_value; 627 } 628 right = tomoyo_condition_type(right_word); 629 if (right == TOMOYO_MAX_CONDITION_KEYWORD) { 630 if (!numbers_p) { 631 e.numbers_count++; 632 } else { 633 e.numbers_count--; 634 right = TOMOYO_NUMBER_UNION; 635 param->data = right_word; 636 if (!tomoyo_parse_number_union(param, 637 numbers_p++)) 638 goto out; 639 } 640 } 641store_value: 642 if (!condp) { 643 dprintk(KERN_WARNING "%u: dry_run left=%u right=%u match=%u\n", 644 __LINE__, left, right, !is_not); 645 continue; 646 } 647 condp->left = left; 648 condp->right = right; 649 condp->equals = !is_not; 650 dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n", 651 __LINE__, condp->left, condp->right, 652 condp->equals); 653 condp++; 654 } 655 dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n", 656 __LINE__, e.condc, e.numbers_count, e.names_count, e.argc, 657 e.envc); 658 if (entry) { 659 BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc | 660 e.condc); 661 return tomoyo_commit_condition(entry); 662 } 663 e.size = sizeof(*entry) 664 + e.condc * sizeof(struct tomoyo_condition_element) 665 + e.numbers_count * sizeof(struct tomoyo_number_union) 666 + e.names_count * sizeof(struct tomoyo_name_union) 667 + e.argc * sizeof(struct tomoyo_argv) 668 + e.envc * sizeof(struct tomoyo_envp); 669 entry = kzalloc(e.size, GFP_NOFS); 670 if (!entry) 671 goto out2; 672 *entry = e; 673 e.transit = NULL; 674 condp = (struct tomoyo_condition_element *) (entry + 1); 675 numbers_p = (struct tomoyo_number_union *) (condp + e.condc); 676 names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count); 677 argv = (struct tomoyo_argv *) (names_p + e.names_count); 678 envp = (struct tomoyo_envp *) (argv + e.argc); 679 { 680 bool flag = false; 681 682 for (pos = start_of_string; pos < end_of_string; pos++) { 683 if (*pos) 684 continue; 685 if (flag) /* Restore " ". */ 686 *pos = ' '; 687 else if (*(pos + 1) == '=') /* Restore "!=". */ 688 *pos = '!'; 689 else /* Restore "=". */ 690 *pos = '='; 691 flag = !flag; 692 } 693 } 694 goto rerun; 695out: 696 dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__); 697 if (entry) { 698 tomoyo_del_condition(&entry->head.list); 699 kfree(entry); 700 } 701out2: 702 tomoyo_put_name(e.transit); 703 return NULL; 704} 705 706/** 707 * tomoyo_get_attributes - Revalidate "struct inode". 708 * 709 * @obj: Pointer to "struct tomoyo_obj_info". 710 * 711 * Returns nothing. 712 */ 713void tomoyo_get_attributes(struct tomoyo_obj_info *obj) 714{ 715 u8 i; 716 struct dentry *dentry = NULL; 717 718 for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) { 719 struct inode *inode; 720 721 switch (i) { 722 case TOMOYO_PATH1: 723 dentry = obj->path1.dentry; 724 if (!dentry) 725 continue; 726 break; 727 case TOMOYO_PATH2: 728 dentry = obj->path2.dentry; 729 if (!dentry) 730 continue; 731 break; 732 default: 733 if (!dentry) 734 continue; 735 dentry = dget_parent(dentry); 736 break; 737 } 738 inode = d_backing_inode(dentry); 739 if (inode) { 740 struct tomoyo_mini_stat *stat = &obj->stat[i]; 741 742 stat->uid = inode->i_uid; 743 stat->gid = inode->i_gid; 744 stat->ino = inode->i_ino; 745 stat->mode = inode->i_mode; 746 stat->dev = inode->i_sb->s_dev; 747 stat->rdev = inode->i_rdev; 748 obj->stat_valid[i] = true; 749 } 750 if (i & 1) /* TOMOYO_PATH1_PARENT or TOMOYO_PATH2_PARENT */ 751 dput(dentry); 752 } 753} 754 755/** 756 * tomoyo_condition - Check condition part. 757 * 758 * @r: Pointer to "struct tomoyo_request_info". 759 * @cond: Pointer to "struct tomoyo_condition". Maybe NULL. 760 * 761 * Returns true on success, false otherwise. 762 * 763 * Caller holds tomoyo_read_lock(). 764 */ 765bool tomoyo_condition(struct tomoyo_request_info *r, 766 const struct tomoyo_condition *cond) 767{ 768 u32 i; 769 unsigned long min_v[2] = { 0, 0 }; 770 unsigned long max_v[2] = { 0, 0 }; 771 const struct tomoyo_condition_element *condp; 772 const struct tomoyo_number_union *numbers_p; 773 const struct tomoyo_name_union *names_p; 774 const struct tomoyo_argv *argv; 775 const struct tomoyo_envp *envp; 776 struct tomoyo_obj_info *obj; 777 u16 condc; 778 u16 argc; 779 u16 envc; 780 struct linux_binprm *bprm = NULL; 781 782 if (!cond) 783 return true; 784 condc = cond->condc; 785 argc = cond->argc; 786 envc = cond->envc; 787 obj = r->obj; 788 if (r->ee) 789 bprm = r->ee->bprm; 790 if (!bprm && (argc || envc)) 791 return false; 792 condp = (struct tomoyo_condition_element *) (cond + 1); 793 numbers_p = (const struct tomoyo_number_union *) (condp + condc); 794 names_p = (const struct tomoyo_name_union *) 795 (numbers_p + cond->numbers_count); 796 argv = (const struct tomoyo_argv *) (names_p + cond->names_count); 797 envp = (const struct tomoyo_envp *) (argv + argc); 798 for (i = 0; i < condc; i++) { 799 const bool match = condp->equals; 800 const u8 left = condp->left; 801 const u8 right = condp->right; 802 bool is_bitop[2] = { false, false }; 803 u8 j; 804 805 condp++; 806 /* Check argv[] and envp[] later. */ 807 if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY) 808 continue; 809 /* Check string expressions. */ 810 if (right == TOMOYO_NAME_UNION) { 811 const struct tomoyo_name_union *ptr = names_p++; 812 struct tomoyo_path_info *symlink; 813 struct tomoyo_execve *ee; 814 struct file *file; 815 816 switch (left) { 817 case TOMOYO_SYMLINK_TARGET: 818 symlink = obj ? obj->symlink_target : NULL; 819 if (!symlink || 820 !tomoyo_compare_name_union(symlink, ptr) 821 == match) 822 goto out; 823 break; 824 case TOMOYO_EXEC_REALPATH: 825 ee = r->ee; 826 file = ee ? ee->bprm->file : NULL; 827 if (!tomoyo_scan_exec_realpath(file, ptr, 828 match)) 829 goto out; 830 break; 831 } 832 continue; 833 } 834 /* Check numeric or bit-op expressions. */ 835 for (j = 0; j < 2; j++) { 836 const u8 index = j ? right : left; 837 unsigned long value = 0; 838 839 switch (index) { 840 case TOMOYO_TASK_UID: 841 value = from_kuid(&init_user_ns, current_uid()); 842 break; 843 case TOMOYO_TASK_EUID: 844 value = from_kuid(&init_user_ns, current_euid()); 845 break; 846 case TOMOYO_TASK_SUID: 847 value = from_kuid(&init_user_ns, current_suid()); 848 break; 849 case TOMOYO_TASK_FSUID: 850 value = from_kuid(&init_user_ns, current_fsuid()); 851 break; 852 case TOMOYO_TASK_GID: 853 value = from_kgid(&init_user_ns, current_gid()); 854 break; 855 case TOMOYO_TASK_EGID: 856 value = from_kgid(&init_user_ns, current_egid()); 857 break; 858 case TOMOYO_TASK_SGID: 859 value = from_kgid(&init_user_ns, current_sgid()); 860 break; 861 case TOMOYO_TASK_FSGID: 862 value = from_kgid(&init_user_ns, current_fsgid()); 863 break; 864 case TOMOYO_TASK_PID: 865 value = tomoyo_sys_getpid(); 866 break; 867 case TOMOYO_TASK_PPID: 868 value = tomoyo_sys_getppid(); 869 break; 870 case TOMOYO_TYPE_IS_SOCKET: 871 value = S_IFSOCK; 872 break; 873 case TOMOYO_TYPE_IS_SYMLINK: 874 value = S_IFLNK; 875 break; 876 case TOMOYO_TYPE_IS_FILE: 877 value = S_IFREG; 878 break; 879 case TOMOYO_TYPE_IS_BLOCK_DEV: 880 value = S_IFBLK; 881 break; 882 case TOMOYO_TYPE_IS_DIRECTORY: 883 value = S_IFDIR; 884 break; 885 case TOMOYO_TYPE_IS_CHAR_DEV: 886 value = S_IFCHR; 887 break; 888 case TOMOYO_TYPE_IS_FIFO: 889 value = S_IFIFO; 890 break; 891 case TOMOYO_MODE_SETUID: 892 value = S_ISUID; 893 break; 894 case TOMOYO_MODE_SETGID: 895 value = S_ISGID; 896 break; 897 case TOMOYO_MODE_STICKY: 898 value = S_ISVTX; 899 break; 900 case TOMOYO_MODE_OWNER_READ: 901 value = 0400; 902 break; 903 case TOMOYO_MODE_OWNER_WRITE: 904 value = 0200; 905 break; 906 case TOMOYO_MODE_OWNER_EXECUTE: 907 value = 0100; 908 break; 909 case TOMOYO_MODE_GROUP_READ: 910 value = 0040; 911 break; 912 case TOMOYO_MODE_GROUP_WRITE: 913 value = 0020; 914 break; 915 case TOMOYO_MODE_GROUP_EXECUTE: 916 value = 0010; 917 break; 918 case TOMOYO_MODE_OTHERS_READ: 919 value = 0004; 920 break; 921 case TOMOYO_MODE_OTHERS_WRITE: 922 value = 0002; 923 break; 924 case TOMOYO_MODE_OTHERS_EXECUTE: 925 value = 0001; 926 break; 927 case TOMOYO_EXEC_ARGC: 928 if (!bprm) 929 goto out; 930 value = bprm->argc; 931 break; 932 case TOMOYO_EXEC_ENVC: 933 if (!bprm) 934 goto out; 935 value = bprm->envc; 936 break; 937 case TOMOYO_NUMBER_UNION: 938 /* Fetch values later. */ 939 break; 940 default: 941 if (!obj) 942 goto out; 943 if (!obj->validate_done) { 944 tomoyo_get_attributes(obj); 945 obj->validate_done = true; 946 } 947 { 948 u8 stat_index; 949 struct tomoyo_mini_stat *stat; 950 951 switch (index) { 952 case TOMOYO_PATH1_UID: 953 case TOMOYO_PATH1_GID: 954 case TOMOYO_PATH1_INO: 955 case TOMOYO_PATH1_MAJOR: 956 case TOMOYO_PATH1_MINOR: 957 case TOMOYO_PATH1_TYPE: 958 case TOMOYO_PATH1_DEV_MAJOR: 959 case TOMOYO_PATH1_DEV_MINOR: 960 case TOMOYO_PATH1_PERM: 961 stat_index = TOMOYO_PATH1; 962 break; 963 case TOMOYO_PATH2_UID: 964 case TOMOYO_PATH2_GID: 965 case TOMOYO_PATH2_INO: 966 case TOMOYO_PATH2_MAJOR: 967 case TOMOYO_PATH2_MINOR: 968 case TOMOYO_PATH2_TYPE: 969 case TOMOYO_PATH2_DEV_MAJOR: 970 case TOMOYO_PATH2_DEV_MINOR: 971 case TOMOYO_PATH2_PERM: 972 stat_index = TOMOYO_PATH2; 973 break; 974 case TOMOYO_PATH1_PARENT_UID: 975 case TOMOYO_PATH1_PARENT_GID: 976 case TOMOYO_PATH1_PARENT_INO: 977 case TOMOYO_PATH1_PARENT_PERM: 978 stat_index = 979 TOMOYO_PATH1_PARENT; 980 break; 981 case TOMOYO_PATH2_PARENT_UID: 982 case TOMOYO_PATH2_PARENT_GID: 983 case TOMOYO_PATH2_PARENT_INO: 984 case TOMOYO_PATH2_PARENT_PERM: 985 stat_index = 986 TOMOYO_PATH2_PARENT; 987 break; 988 default: 989 goto out; 990 } 991 if (!obj->stat_valid[stat_index]) 992 goto out; 993 stat = &obj->stat[stat_index]; 994 switch (index) { 995 case TOMOYO_PATH1_UID: 996 case TOMOYO_PATH2_UID: 997 case TOMOYO_PATH1_PARENT_UID: 998 case TOMOYO_PATH2_PARENT_UID: 999 value = from_kuid(&init_user_ns, stat->uid); 1000 break; 1001 case TOMOYO_PATH1_GID: 1002 case TOMOYO_PATH2_GID: 1003 case TOMOYO_PATH1_PARENT_GID: 1004 case TOMOYO_PATH2_PARENT_GID: 1005 value = from_kgid(&init_user_ns, stat->gid); 1006 break; 1007 case TOMOYO_PATH1_INO: 1008 case TOMOYO_PATH2_INO: 1009 case TOMOYO_PATH1_PARENT_INO: 1010 case TOMOYO_PATH2_PARENT_INO: 1011 value = stat->ino; 1012 break; 1013 case TOMOYO_PATH1_MAJOR: 1014 case TOMOYO_PATH2_MAJOR: 1015 value = MAJOR(stat->dev); 1016 break; 1017 case TOMOYO_PATH1_MINOR: 1018 case TOMOYO_PATH2_MINOR: 1019 value = MINOR(stat->dev); 1020 break; 1021 case TOMOYO_PATH1_TYPE: 1022 case TOMOYO_PATH2_TYPE: 1023 value = stat->mode & S_IFMT; 1024 break; 1025 case TOMOYO_PATH1_DEV_MAJOR: 1026 case TOMOYO_PATH2_DEV_MAJOR: 1027 value = MAJOR(stat->rdev); 1028 break; 1029 case TOMOYO_PATH1_DEV_MINOR: 1030 case TOMOYO_PATH2_DEV_MINOR: 1031 value = MINOR(stat->rdev); 1032 break; 1033 case TOMOYO_PATH1_PERM: 1034 case TOMOYO_PATH2_PERM: 1035 case TOMOYO_PATH1_PARENT_PERM: 1036 case TOMOYO_PATH2_PARENT_PERM: 1037 value = stat->mode & S_IALLUGO; 1038 break; 1039 } 1040 } 1041 break; 1042 } 1043 max_v[j] = value; 1044 min_v[j] = value; 1045 switch (index) { 1046 case TOMOYO_MODE_SETUID: 1047 case TOMOYO_MODE_SETGID: 1048 case TOMOYO_MODE_STICKY: 1049 case TOMOYO_MODE_OWNER_READ: 1050 case TOMOYO_MODE_OWNER_WRITE: 1051 case TOMOYO_MODE_OWNER_EXECUTE: 1052 case TOMOYO_MODE_GROUP_READ: 1053 case TOMOYO_MODE_GROUP_WRITE: 1054 case TOMOYO_MODE_GROUP_EXECUTE: 1055 case TOMOYO_MODE_OTHERS_READ: 1056 case TOMOYO_MODE_OTHERS_WRITE: 1057 case TOMOYO_MODE_OTHERS_EXECUTE: 1058 is_bitop[j] = true; 1059 } 1060 } 1061 if (left == TOMOYO_NUMBER_UNION) { 1062 /* Fetch values now. */ 1063 const struct tomoyo_number_union *ptr = numbers_p++; 1064 1065 min_v[0] = ptr->values[0]; 1066 max_v[0] = ptr->values[1]; 1067 } 1068 if (right == TOMOYO_NUMBER_UNION) { 1069 /* Fetch values now. */ 1070 const struct tomoyo_number_union *ptr = numbers_p++; 1071 1072 if (ptr->group) { 1073 if (tomoyo_number_matches_group(min_v[0], 1074 max_v[0], 1075 ptr->group) 1076 == match) 1077 continue; 1078 } else { 1079 if ((min_v[0] <= ptr->values[1] && 1080 max_v[0] >= ptr->values[0]) == match) 1081 continue; 1082 } 1083 goto out; 1084 } 1085 /* 1086 * Bit operation is valid only when counterpart value 1087 * represents permission. 1088 */ 1089 if (is_bitop[0] && is_bitop[1]) { 1090 goto out; 1091 } else if (is_bitop[0]) { 1092 switch (right) { 1093 case TOMOYO_PATH1_PERM: 1094 case TOMOYO_PATH1_PARENT_PERM: 1095 case TOMOYO_PATH2_PERM: 1096 case TOMOYO_PATH2_PARENT_PERM: 1097 if (!(max_v[0] & max_v[1]) == !match) 1098 continue; 1099 } 1100 goto out; 1101 } else if (is_bitop[1]) { 1102 switch (left) { 1103 case TOMOYO_PATH1_PERM: 1104 case TOMOYO_PATH1_PARENT_PERM: 1105 case TOMOYO_PATH2_PERM: 1106 case TOMOYO_PATH2_PARENT_PERM: 1107 if (!(max_v[0] & max_v[1]) == !match) 1108 continue; 1109 } 1110 goto out; 1111 } 1112 /* Normal value range comparison. */ 1113 if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match) 1114 continue; 1115out: 1116 return false; 1117 } 1118 /* Check argv[] and envp[] now. */ 1119 if (r->ee && (argc || envc)) 1120 return tomoyo_scan_bprm(r->ee, argc, argv, envc, envp); 1121 return true; 1122}