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