1 /* 2 * security/tomoyo/util.c 3 * 4 * Copyright (C) 2005-2011 NTT DATA CORPORATION 5 */ 6 7 #include <linux/slab.h> 8 #include "common.h" 9 10 /* Lock for protecting policy. */ 11 DEFINE_MUTEX(tomoyo_policy_lock); 12 13 /* Has /sbin/init started? */ 14 bool tomoyo_policy_loaded; 15 16 /* 17 * Mapping table from "enum tomoyo_mac_index" to 18 * "enum tomoyo_mac_category_index". 19 */ 20 const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = { 21 /* CONFIG::file group */ 22 [TOMOYO_MAC_FILE_EXECUTE] = TOMOYO_MAC_CATEGORY_FILE, 23 [TOMOYO_MAC_FILE_OPEN] = TOMOYO_MAC_CATEGORY_FILE, 24 [TOMOYO_MAC_FILE_CREATE] = TOMOYO_MAC_CATEGORY_FILE, 25 [TOMOYO_MAC_FILE_UNLINK] = TOMOYO_MAC_CATEGORY_FILE, 26 [TOMOYO_MAC_FILE_GETATTR] = TOMOYO_MAC_CATEGORY_FILE, 27 [TOMOYO_MAC_FILE_MKDIR] = TOMOYO_MAC_CATEGORY_FILE, 28 [TOMOYO_MAC_FILE_RMDIR] = TOMOYO_MAC_CATEGORY_FILE, 29 [TOMOYO_MAC_FILE_MKFIFO] = TOMOYO_MAC_CATEGORY_FILE, 30 [TOMOYO_MAC_FILE_MKSOCK] = TOMOYO_MAC_CATEGORY_FILE, 31 [TOMOYO_MAC_FILE_TRUNCATE] = TOMOYO_MAC_CATEGORY_FILE, 32 [TOMOYO_MAC_FILE_SYMLINK] = TOMOYO_MAC_CATEGORY_FILE, 33 [TOMOYO_MAC_FILE_MKBLOCK] = TOMOYO_MAC_CATEGORY_FILE, 34 [TOMOYO_MAC_FILE_MKCHAR] = TOMOYO_MAC_CATEGORY_FILE, 35 [TOMOYO_MAC_FILE_LINK] = TOMOYO_MAC_CATEGORY_FILE, 36 [TOMOYO_MAC_FILE_RENAME] = TOMOYO_MAC_CATEGORY_FILE, 37 [TOMOYO_MAC_FILE_CHMOD] = TOMOYO_MAC_CATEGORY_FILE, 38 [TOMOYO_MAC_FILE_CHOWN] = TOMOYO_MAC_CATEGORY_FILE, 39 [TOMOYO_MAC_FILE_CHGRP] = TOMOYO_MAC_CATEGORY_FILE, 40 [TOMOYO_MAC_FILE_IOCTL] = TOMOYO_MAC_CATEGORY_FILE, 41 [TOMOYO_MAC_FILE_CHROOT] = TOMOYO_MAC_CATEGORY_FILE, 42 [TOMOYO_MAC_FILE_MOUNT] = TOMOYO_MAC_CATEGORY_FILE, 43 [TOMOYO_MAC_FILE_UMOUNT] = TOMOYO_MAC_CATEGORY_FILE, 44 [TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE, 45 }; 46 47 /** 48 * tomoyo_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss. 49 * 50 * @time: Seconds since 1970/01/01 00:00:00. 51 * @stamp: Pointer to "struct tomoyo_time". 52 * 53 * Returns nothing. 54 * 55 * This function does not handle Y2038 problem. 56 */ 57 void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp) 58 { 59 static const u16 tomoyo_eom[2][12] = { 60 { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, 61 { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } 62 }; 63 u16 y; 64 u8 m; 65 bool r; 66 stamp->sec = time % 60; 67 time /= 60; 68 stamp->min = time % 60; 69 time /= 60; 70 stamp->hour = time % 24; 71 time /= 24; 72 for (y = 1970; ; y++) { 73 const unsigned short days = (y & 3) ? 365 : 366; 74 if (time < days) 75 break; 76 time -= days; 77 } 78 r = (y & 3) == 0; 79 for (m = 0; m < 11 && time >= tomoyo_eom[r][m]; m++) 80 ; 81 if (m) 82 time -= tomoyo_eom[r][m - 1]; 83 stamp->year = y; 84 stamp->month = ++m; 85 stamp->day = ++time; 86 } 87 88 /** 89 * tomoyo_permstr - Find permission keywords. 90 * 91 * @string: String representation for permissions in foo/bar/buz format. 92 * @keyword: Keyword to find from @string/ 93 * 94 * Returns ture if @keyword was found in @string, false otherwise. 95 * 96 * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2. 97 */ 98 bool tomoyo_permstr(const char *string, const char *keyword) 99 { 100 const char *cp = strstr(string, keyword); 101 if (cp) 102 return cp == string || *(cp - 1) == '/'; 103 return false; 104 } 105 106 /** 107 * tomoyo_read_token - Read a word from a line. 108 * 109 * @param: Pointer to "struct tomoyo_acl_param". 110 * 111 * Returns a word on success, "" otherwise. 112 * 113 * To allow the caller to skip NULL check, this function returns "" rather than 114 * NULL if there is no more words to read. 115 */ 116 char *tomoyo_read_token(struct tomoyo_acl_param *param) 117 { 118 char *pos = param->data; 119 char *del = strchr(pos, ' '); 120 if (del) 121 *del++ = '\0'; 122 else 123 del = pos + strlen(pos); 124 param->data = del; 125 return pos; 126 } 127 128 /** 129 * tomoyo_parse_ulong - Parse an "unsigned long" value. 130 * 131 * @result: Pointer to "unsigned long". 132 * @str: Pointer to string to parse. 133 * 134 * Returns one of values in "enum tomoyo_value_type". 135 * 136 * The @src is updated to point the first character after the value 137 * on success. 138 */ 139 u8 tomoyo_parse_ulong(unsigned long *result, char **str) 140 { 141 const char *cp = *str; 142 char *ep; 143 int base = 10; 144 if (*cp == '0') { 145 char c = *(cp + 1); 146 if (c == 'x' || c == 'X') { 147 base = 16; 148 cp += 2; 149 } else if (c >= '0' && c <= '7') { 150 base = 8; 151 cp++; 152 } 153 } 154 *result = simple_strtoul(cp, &ep, base); 155 if (cp == ep) 156 return TOMOYO_VALUE_TYPE_INVALID; 157 *str = ep; 158 switch (base) { 159 case 16: 160 return TOMOYO_VALUE_TYPE_HEXADECIMAL; 161 case 8: 162 return TOMOYO_VALUE_TYPE_OCTAL; 163 default: 164 return TOMOYO_VALUE_TYPE_DECIMAL; 165 } 166 } 167 168 /** 169 * tomoyo_print_ulong - Print an "unsigned long" value. 170 * 171 * @buffer: Pointer to buffer. 172 * @buffer_len: Size of @buffer. 173 * @value: An "unsigned long" value. 174 * @type: Type of @value. 175 * 176 * Returns nothing. 177 */ 178 void tomoyo_print_ulong(char *buffer, const int buffer_len, 179 const unsigned long value, const u8 type) 180 { 181 if (type == TOMOYO_VALUE_TYPE_DECIMAL) 182 snprintf(buffer, buffer_len, "%lu", value); 183 else if (type == TOMOYO_VALUE_TYPE_OCTAL) 184 snprintf(buffer, buffer_len, "0%lo", value); 185 else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL) 186 snprintf(buffer, buffer_len, "0x%lX", value); 187 else 188 snprintf(buffer, buffer_len, "type(%u)", type); 189 } 190 191 /** 192 * tomoyo_parse_name_union - Parse a tomoyo_name_union. 193 * 194 * @param: Pointer to "struct tomoyo_acl_param". 195 * @ptr: Pointer to "struct tomoyo_name_union". 196 * 197 * Returns true on success, false otherwise. 198 */ 199 bool tomoyo_parse_name_union(struct tomoyo_acl_param *param, 200 struct tomoyo_name_union *ptr) 201 { 202 char *filename; 203 if (param->data[0] == '@') { 204 param->data++; 205 ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP); 206 return ptr->group != NULL; 207 } 208 filename = tomoyo_read_token(param); 209 if (!tomoyo_correct_word(filename)) 210 return false; 211 ptr->filename = tomoyo_get_name(filename); 212 return ptr->filename != NULL; 213 } 214 215 /** 216 * tomoyo_parse_number_union - Parse a tomoyo_number_union. 217 * 218 * @param: Pointer to "struct tomoyo_acl_param". 219 * @ptr: Pointer to "struct tomoyo_number_union". 220 * 221 * Returns true on success, false otherwise. 222 */ 223 bool tomoyo_parse_number_union(struct tomoyo_acl_param *param, 224 struct tomoyo_number_union *ptr) 225 { 226 char *data; 227 u8 type; 228 unsigned long v; 229 memset(ptr, 0, sizeof(*ptr)); 230 if (param->data[0] == '@') { 231 param->data++; 232 ptr->group = tomoyo_get_group(param, TOMOYO_NUMBER_GROUP); 233 return ptr->group != NULL; 234 } 235 data = tomoyo_read_token(param); 236 type = tomoyo_parse_ulong(&v, &data); 237 if (type == TOMOYO_VALUE_TYPE_INVALID) 238 return false; 239 ptr->values[0] = v; 240 ptr->value_type[0] = type; 241 if (!*data) { 242 ptr->values[1] = v; 243 ptr->value_type[1] = type; 244 return true; 245 } 246 if (*data++ != '-') 247 return false; 248 type = tomoyo_parse_ulong(&v, &data); 249 if (type == TOMOYO_VALUE_TYPE_INVALID || *data || ptr->values[0] > v) 250 return false; 251 ptr->values[1] = v; 252 ptr->value_type[1] = type; 253 return true; 254 } 255 256 /** 257 * tomoyo_byte_range - Check whether the string is a \ooo style octal value. 258 * 259 * @str: Pointer to the string. 260 * 261 * Returns true if @str is a \ooo style octal value, false otherwise. 262 * 263 * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF. 264 * This function verifies that \ooo is in valid range. 265 */ 266 static inline bool tomoyo_byte_range(const char *str) 267 { 268 return *str >= '0' && *str++ <= '3' && 269 *str >= '0' && *str++ <= '7' && 270 *str >= '0' && *str <= '7'; 271 } 272 273 /** 274 * tomoyo_alphabet_char - Check whether the character is an alphabet. 275 * 276 * @c: The character to check. 277 * 278 * Returns true if @c is an alphabet character, false otherwise. 279 */ 280 static inline bool tomoyo_alphabet_char(const char c) 281 { 282 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); 283 } 284 285 /** 286 * tomoyo_make_byte - Make byte value from three octal characters. 287 * 288 * @c1: The first character. 289 * @c2: The second character. 290 * @c3: The third character. 291 * 292 * Returns byte value. 293 */ 294 static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3) 295 { 296 return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0'); 297 } 298 299 /** 300 * tomoyo_valid - Check whether the character is a valid char. 301 * 302 * @c: The character to check. 303 * 304 * Returns true if @c is a valid character, false otherwise. 305 */ 306 static inline bool tomoyo_valid(const unsigned char c) 307 { 308 return c > ' ' && c < 127; 309 } 310 311 /** 312 * tomoyo_invalid - Check whether the character is an invalid char. 313 * 314 * @c: The character to check. 315 * 316 * Returns true if @c is an invalid character, false otherwise. 317 */ 318 static inline bool tomoyo_invalid(const unsigned char c) 319 { 320 return c && (c <= ' ' || c >= 127); 321 } 322 323 /** 324 * tomoyo_str_starts - Check whether the given string starts with the given keyword. 325 * 326 * @src: Pointer to pointer to the string. 327 * @find: Pointer to the keyword. 328 * 329 * Returns true if @src starts with @find, false otherwise. 330 * 331 * The @src is updated to point the first character after the @find 332 * if @src starts with @find. 333 */ 334 bool tomoyo_str_starts(char **src, const char *find) 335 { 336 const int len = strlen(find); 337 char *tmp = *src; 338 339 if (strncmp(tmp, find, len)) 340 return false; 341 tmp += len; 342 *src = tmp; 343 return true; 344 } 345 346 /** 347 * tomoyo_normalize_line - Format string. 348 * 349 * @buffer: The line to normalize. 350 * 351 * Leading and trailing whitespaces are removed. 352 * Multiple whitespaces are packed into single space. 353 * 354 * Returns nothing. 355 */ 356 void tomoyo_normalize_line(unsigned char *buffer) 357 { 358 unsigned char *sp = buffer; 359 unsigned char *dp = buffer; 360 bool first = true; 361 362 while (tomoyo_invalid(*sp)) 363 sp++; 364 while (*sp) { 365 if (!first) 366 *dp++ = ' '; 367 first = false; 368 while (tomoyo_valid(*sp)) 369 *dp++ = *sp++; 370 while (tomoyo_invalid(*sp)) 371 sp++; 372 } 373 *dp = '\0'; 374 } 375 376 /** 377 * tomoyo_correct_word2 - Validate a string. 378 * 379 * @string: The string to check. Maybe non-'\0'-terminated. 380 * @len: Length of @string. 381 * 382 * Check whether the given string follows the naming rules. 383 * Returns true if @string follows the naming rules, false otherwise. 384 */ 385 static bool tomoyo_correct_word2(const char *string, size_t len) 386 { 387 const char *const start = string; 388 bool in_repetition = false; 389 unsigned char c; 390 unsigned char d; 391 unsigned char e; 392 if (!len) 393 goto out; 394 while (len--) { 395 c = *string++; 396 if (c == '\\') { 397 if (!len--) 398 goto out; 399 c = *string++; 400 switch (c) { 401 case '\\': /* "\\" */ 402 continue; 403 case '$': /* "\$" */ 404 case '+': /* "\+" */ 405 case '?': /* "\?" */ 406 case '*': /* "\*" */ 407 case '@': /* "\@" */ 408 case 'x': /* "\x" */ 409 case 'X': /* "\X" */ 410 case 'a': /* "\a" */ 411 case 'A': /* "\A" */ 412 case '-': /* "\-" */ 413 continue; 414 case '{': /* "/\{" */ 415 if (string - 3 < start || *(string - 3) != '/') 416 break; 417 in_repetition = true; 418 continue; 419 case '}': /* "\}/" */ 420 if (*string != '/') 421 break; 422 if (!in_repetition) 423 break; 424 in_repetition = false; 425 continue; 426 case '0': /* "\ooo" */ 427 case '1': 428 case '2': 429 case '3': 430 if (!len-- || !len--) 431 break; 432 d = *string++; 433 e = *string++; 434 if (d < '0' || d > '7' || e < '0' || e > '7') 435 break; 436 c = tomoyo_make_byte(c, d, e); 437 if (tomoyo_invalid(c)) 438 continue; /* pattern is not \000 */ 439 } 440 goto out; 441 } else if (in_repetition && c == '/') { 442 goto out; 443 } else if (tomoyo_invalid(c)) { 444 goto out; 445 } 446 } 447 if (in_repetition) 448 goto out; 449 return true; 450 out: 451 return false; 452 } 453 454 /** 455 * tomoyo_correct_word - Validate a string. 456 * 457 * @string: The string to check. 458 * 459 * Check whether the given string follows the naming rules. 460 * Returns true if @string follows the naming rules, false otherwise. 461 */ 462 bool tomoyo_correct_word(const char *string) 463 { 464 return tomoyo_correct_word2(string, strlen(string)); 465 } 466 467 /** 468 * tomoyo_correct_path - Validate a pathname. 469 * 470 * @filename: The pathname to check. 471 * 472 * Check whether the given pathname follows the naming rules. 473 * Returns true if @filename follows the naming rules, false otherwise. 474 */ 475 bool tomoyo_correct_path(const char *filename) 476 { 477 return *filename == '/' && tomoyo_correct_word(filename); 478 } 479 480 /** 481 * tomoyo_correct_domain - Check whether the given domainname follows the naming rules. 482 * 483 * @domainname: The domainname to check. 484 * 485 * Returns true if @domainname follows the naming rules, false otherwise. 486 */ 487 bool tomoyo_correct_domain(const unsigned char *domainname) 488 { 489 if (!domainname || !tomoyo_domain_def(domainname)) 490 return false; 491 domainname = strchr(domainname, ' '); 492 if (!domainname++) 493 return true; 494 while (1) { 495 const unsigned char *cp = strchr(domainname, ' '); 496 if (!cp) 497 break; 498 if (*domainname != '/' || 499 !tomoyo_correct_word2(domainname, cp - domainname)) 500 return false; 501 domainname = cp + 1; 502 } 503 return tomoyo_correct_path(domainname); 504 } 505 506 /** 507 * tomoyo_domain_def - Check whether the given token can be a domainname. 508 * 509 * @buffer: The token to check. 510 * 511 * Returns true if @buffer possibly be a domainname, false otherwise. 512 */ 513 bool tomoyo_domain_def(const unsigned char *buffer) 514 { 515 const unsigned char *cp; 516 int len; 517 if (*buffer != '<') 518 return false; 519 cp = strchr(buffer, ' '); 520 if (!cp) 521 len = strlen(buffer); 522 else 523 len = cp - buffer; 524 if (buffer[len - 1] != '>' || 525 !tomoyo_correct_word2(buffer + 1, len - 2)) 526 return false; 527 return true; 528 } 529 530 /** 531 * tomoyo_find_domain - Find a domain by the given name. 532 * 533 * @domainname: The domainname to find. 534 * 535 * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. 536 * 537 * Caller holds tomoyo_read_lock(). 538 */ 539 struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) 540 { 541 struct tomoyo_domain_info *domain; 542 struct tomoyo_path_info name; 543 544 name.name = domainname; 545 tomoyo_fill_path_info(&name); 546 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 547 if (!domain->is_deleted && 548 !tomoyo_pathcmp(&name, domain->domainname)) 549 return domain; 550 } 551 return NULL; 552 } 553 554 /** 555 * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token. 556 * 557 * @filename: The string to evaluate. 558 * 559 * Returns the initial length without a pattern in @filename. 560 */ 561 static int tomoyo_const_part_length(const char *filename) 562 { 563 char c; 564 int len = 0; 565 566 if (!filename) 567 return 0; 568 while ((c = *filename++) != '\0') { 569 if (c != '\\') { 570 len++; 571 continue; 572 } 573 c = *filename++; 574 switch (c) { 575 case '\\': /* "\\" */ 576 len += 2; 577 continue; 578 case '0': /* "\ooo" */ 579 case '1': 580 case '2': 581 case '3': 582 c = *filename++; 583 if (c < '0' || c > '7') 584 break; 585 c = *filename++; 586 if (c < '0' || c > '7') 587 break; 588 len += 4; 589 continue; 590 } 591 break; 592 } 593 return len; 594 } 595 596 /** 597 * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members. 598 * 599 * @ptr: Pointer to "struct tomoyo_path_info" to fill in. 600 * 601 * The caller sets "struct tomoyo_path_info"->name. 602 */ 603 void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) 604 { 605 const char *name = ptr->name; 606 const int len = strlen(name); 607 608 ptr->const_len = tomoyo_const_part_length(name); 609 ptr->is_dir = len && (name[len - 1] == '/'); 610 ptr->is_patterned = (ptr->const_len < len); 611 ptr->hash = full_name_hash(name, len); 612 } 613 614 /** 615 * tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern. 616 * 617 * @filename: The start of string to check. 618 * @filename_end: The end of string to check. 619 * @pattern: The start of pattern to compare. 620 * @pattern_end: The end of pattern to compare. 621 * 622 * Returns true if @filename matches @pattern, false otherwise. 623 */ 624 static bool tomoyo_file_matches_pattern2(const char *filename, 625 const char *filename_end, 626 const char *pattern, 627 const char *pattern_end) 628 { 629 while (filename < filename_end && pattern < pattern_end) { 630 char c; 631 if (*pattern != '\\') { 632 if (*filename++ != *pattern++) 633 return false; 634 continue; 635 } 636 c = *filename; 637 pattern++; 638 switch (*pattern) { 639 int i; 640 int j; 641 case '?': 642 if (c == '/') { 643 return false; 644 } else if (c == '\\') { 645 if (filename[1] == '\\') 646 filename++; 647 else if (tomoyo_byte_range(filename + 1)) 648 filename += 3; 649 else 650 return false; 651 } 652 break; 653 case '\\': 654 if (c != '\\') 655 return false; 656 if (*++filename != '\\') 657 return false; 658 break; 659 case '+': 660 if (!isdigit(c)) 661 return false; 662 break; 663 case 'x': 664 if (!isxdigit(c)) 665 return false; 666 break; 667 case 'a': 668 if (!tomoyo_alphabet_char(c)) 669 return false; 670 break; 671 case '0': 672 case '1': 673 case '2': 674 case '3': 675 if (c == '\\' && tomoyo_byte_range(filename + 1) 676 && strncmp(filename + 1, pattern, 3) == 0) { 677 filename += 3; 678 pattern += 2; 679 break; 680 } 681 return false; /* Not matched. */ 682 case '*': 683 case '@': 684 for (i = 0; i <= filename_end - filename; i++) { 685 if (tomoyo_file_matches_pattern2( 686 filename + i, filename_end, 687 pattern + 1, pattern_end)) 688 return true; 689 c = filename[i]; 690 if (c == '.' && *pattern == '@') 691 break; 692 if (c != '\\') 693 continue; 694 if (filename[i + 1] == '\\') 695 i++; 696 else if (tomoyo_byte_range(filename + i + 1)) 697 i += 3; 698 else 699 break; /* Bad pattern. */ 700 } 701 return false; /* Not matched. */ 702 default: 703 j = 0; 704 c = *pattern; 705 if (c == '$') { 706 while (isdigit(filename[j])) 707 j++; 708 } else if (c == 'X') { 709 while (isxdigit(filename[j])) 710 j++; 711 } else if (c == 'A') { 712 while (tomoyo_alphabet_char(filename[j])) 713 j++; 714 } 715 for (i = 1; i <= j; i++) { 716 if (tomoyo_file_matches_pattern2( 717 filename + i, filename_end, 718 pattern + 1, pattern_end)) 719 return true; 720 } 721 return false; /* Not matched or bad pattern. */ 722 } 723 filename++; 724 pattern++; 725 } 726 while (*pattern == '\\' && 727 (*(pattern + 1) == '*' || *(pattern + 1) == '@')) 728 pattern += 2; 729 return filename == filename_end && pattern == pattern_end; 730 } 731 732 /** 733 * tomoyo_file_matches_pattern - Pattern matching without '/' character. 734 * 735 * @filename: The start of string to check. 736 * @filename_end: The end of string to check. 737 * @pattern: The start of pattern to compare. 738 * @pattern_end: The end of pattern to compare. 739 * 740 * Returns true if @filename matches @pattern, false otherwise. 741 */ 742 static bool tomoyo_file_matches_pattern(const char *filename, 743 const char *filename_end, 744 const char *pattern, 745 const char *pattern_end) 746 { 747 const char *pattern_start = pattern; 748 bool first = true; 749 bool result; 750 751 while (pattern < pattern_end - 1) { 752 /* Split at "\-" pattern. */ 753 if (*pattern++ != '\\' || *pattern++ != '-') 754 continue; 755 result = tomoyo_file_matches_pattern2(filename, 756 filename_end, 757 pattern_start, 758 pattern - 2); 759 if (first) 760 result = !result; 761 if (result) 762 return false; 763 first = false; 764 pattern_start = pattern; 765 } 766 result = tomoyo_file_matches_pattern2(filename, filename_end, 767 pattern_start, pattern_end); 768 return first ? result : !result; 769 } 770 771 /** 772 * tomoyo_path_matches_pattern2 - Do pathname pattern matching. 773 * 774 * @f: The start of string to check. 775 * @p: The start of pattern to compare. 776 * 777 * Returns true if @f matches @p, false otherwise. 778 */ 779 static bool tomoyo_path_matches_pattern2(const char *f, const char *p) 780 { 781 const char *f_delimiter; 782 const char *p_delimiter; 783 784 while (*f && *p) { 785 f_delimiter = strchr(f, '/'); 786 if (!f_delimiter) 787 f_delimiter = f + strlen(f); 788 p_delimiter = strchr(p, '/'); 789 if (!p_delimiter) 790 p_delimiter = p + strlen(p); 791 if (*p == '\\' && *(p + 1) == '{') 792 goto recursive; 793 if (!tomoyo_file_matches_pattern(f, f_delimiter, p, 794 p_delimiter)) 795 return false; 796 f = f_delimiter; 797 if (*f) 798 f++; 799 p = p_delimiter; 800 if (*p) 801 p++; 802 } 803 /* Ignore trailing "\*" and "\@" in @pattern. */ 804 while (*p == '\\' && 805 (*(p + 1) == '*' || *(p + 1) == '@')) 806 p += 2; 807 return !*f && !*p; 808 recursive: 809 /* 810 * The "\{" pattern is permitted only after '/' character. 811 * This guarantees that below "*(p - 1)" is safe. 812 * Also, the "\}" pattern is permitted only before '/' character 813 * so that "\{" + "\}" pair will not break the "\-" operator. 814 */ 815 if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' || 816 *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\') 817 return false; /* Bad pattern. */ 818 do { 819 /* Compare current component with pattern. */ 820 if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2, 821 p_delimiter - 2)) 822 break; 823 /* Proceed to next component. */ 824 f = f_delimiter; 825 if (!*f) 826 break; 827 f++; 828 /* Continue comparison. */ 829 if (tomoyo_path_matches_pattern2(f, p_delimiter + 1)) 830 return true; 831 f_delimiter = strchr(f, '/'); 832 } while (f_delimiter); 833 return false; /* Not matched. */ 834 } 835 836 /** 837 * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern. 838 * 839 * @filename: The filename to check. 840 * @pattern: The pattern to compare. 841 * 842 * Returns true if matches, false otherwise. 843 * 844 * The following patterns are available. 845 * \\ \ itself. 846 * \ooo Octal representation of a byte. 847 * \* Zero or more repetitions of characters other than '/'. 848 * \@ Zero or more repetitions of characters other than '/' or '.'. 849 * \? 1 byte character other than '/'. 850 * \$ One or more repetitions of decimal digits. 851 * \+ 1 decimal digit. 852 * \X One or more repetitions of hexadecimal digits. 853 * \x 1 hexadecimal digit. 854 * \A One or more repetitions of alphabet characters. 855 * \a 1 alphabet character. 856 * 857 * \- Subtraction operator. 858 * 859 * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/ 860 * /dir/dir/dir/ ). 861 */ 862 bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, 863 const struct tomoyo_path_info *pattern) 864 { 865 const char *f = filename->name; 866 const char *p = pattern->name; 867 const int len = pattern->const_len; 868 869 /* If @pattern doesn't contain pattern, I can use strcmp(). */ 870 if (!pattern->is_patterned) 871 return !tomoyo_pathcmp(filename, pattern); 872 /* Don't compare directory and non-directory. */ 873 if (filename->is_dir != pattern->is_dir) 874 return false; 875 /* Compare the initial length without patterns. */ 876 if (strncmp(f, p, len)) 877 return false; 878 f += len; 879 p += len; 880 return tomoyo_path_matches_pattern2(f, p); 881 } 882 883 /** 884 * tomoyo_get_exe - Get tomoyo_realpath() of current process. 885 * 886 * Returns the tomoyo_realpath() of current process on success, NULL otherwise. 887 * 888 * This function uses kzalloc(), so the caller must call kfree() 889 * if this function didn't return NULL. 890 */ 891 const char *tomoyo_get_exe(void) 892 { 893 struct mm_struct *mm = current->mm; 894 struct vm_area_struct *vma; 895 const char *cp = NULL; 896 897 if (!mm) 898 return NULL; 899 down_read(&mm->mmap_sem); 900 for (vma = mm->mmap; vma; vma = vma->vm_next) { 901 if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { 902 cp = tomoyo_realpath_from_path(&vma->vm_file->f_path); 903 break; 904 } 905 } 906 up_read(&mm->mmap_sem); 907 return cp; 908 } 909 910 /** 911 * tomoyo_get_mode - Get MAC mode. 912 * 913 * @ns: Pointer to "struct tomoyo_policy_namespace". 914 * @profile: Profile number. 915 * @index: Index number of functionality. 916 * 917 * Returns mode. 918 */ 919 int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, 920 const u8 index) 921 { 922 u8 mode; 923 const u8 category = TOMOYO_MAC_CATEGORY_FILE; 924 if (!tomoyo_policy_loaded) 925 return TOMOYO_CONFIG_DISABLED; 926 mode = tomoyo_profile(ns, profile)->config[index]; 927 if (mode == TOMOYO_CONFIG_USE_DEFAULT) 928 mode = tomoyo_profile(ns, profile)->config[category]; 929 if (mode == TOMOYO_CONFIG_USE_DEFAULT) 930 mode = tomoyo_profile(ns, profile)->default_config; 931 return mode & 3; 932 } 933 934 /** 935 * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members. 936 * 937 * @r: Pointer to "struct tomoyo_request_info" to initialize. 938 * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain(). 939 * @index: Index number of functionality. 940 * 941 * Returns mode. 942 */ 943 int tomoyo_init_request_info(struct tomoyo_request_info *r, 944 struct tomoyo_domain_info *domain, const u8 index) 945 { 946 u8 profile; 947 memset(r, 0, sizeof(*r)); 948 if (!domain) 949 domain = tomoyo_domain(); 950 r->domain = domain; 951 profile = domain->profile; 952 r->profile = profile; 953 r->type = index; 954 r->mode = tomoyo_get_mode(domain->ns, profile, index); 955 return r->mode; 956 } 957 958 /** 959 * tomoyo_domain_quota_is_ok - Check for domain's quota. 960 * 961 * @r: Pointer to "struct tomoyo_request_info". 962 * 963 * Returns true if the domain is not exceeded quota, false otherwise. 964 * 965 * Caller holds tomoyo_read_lock(). 966 */ 967 bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) 968 { 969 unsigned int count = 0; 970 struct tomoyo_domain_info *domain = r->domain; 971 struct tomoyo_acl_info *ptr; 972 973 if (r->mode != TOMOYO_CONFIG_LEARNING) 974 return false; 975 if (!domain) 976 return true; 977 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 978 u16 perm; 979 u8 i; 980 if (ptr->is_deleted) 981 continue; 982 switch (ptr->type) { 983 case TOMOYO_TYPE_PATH_ACL: 984 perm = container_of(ptr, struct tomoyo_path_acl, head) 985 ->perm; 986 break; 987 case TOMOYO_TYPE_PATH2_ACL: 988 perm = container_of(ptr, struct tomoyo_path2_acl, head) 989 ->perm; 990 break; 991 case TOMOYO_TYPE_PATH_NUMBER_ACL: 992 perm = container_of(ptr, struct tomoyo_path_number_acl, 993 head)->perm; 994 break; 995 case TOMOYO_TYPE_MKDEV_ACL: 996 perm = container_of(ptr, struct tomoyo_mkdev_acl, 997 head)->perm; 998 break; 999 default: 1000 perm = 1; 1001 } 1002 for (i = 0; i < 16; i++) 1003 if (perm & (1 << i)) 1004 count++; 1005 } 1006 if (count < tomoyo_profile(domain->ns, domain->profile)-> 1007 pref[TOMOYO_PREF_MAX_LEARNING_ENTRY]) 1008 return true; 1009 if (!domain->flags[TOMOYO_DIF_QUOTA_WARNED]) { 1010 domain->flags[TOMOYO_DIF_QUOTA_WARNED] = true; 1011 /* r->granted = false; */ 1012 tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]); 1013 printk(KERN_WARNING "WARNING: " 1014 "Domain '%s' has too many ACLs to hold. " 1015 "Stopped learning mode.\n", domain->domainname->name); 1016 } 1017 return false; 1018 } 1019