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