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