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