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