guard page for stacks that grow upwards
[linux-2.6.git] / security / tomoyo / util.c
index 7b023f5..9bfc1ee 100644 (file)
@@ -26,7 +26,7 @@ bool tomoyo_policy_loaded;
  * The @src is updated to point the first character after the value
  * on success.
  */
-u8 tomoyo_parse_ulong(unsigned long *result, char **str)
+static u8 tomoyo_parse_ulong(unsigned long *result, char **str)
 {
        const char *cp = *str;
        char *ep;
@@ -89,10 +89,10 @@ void tomoyo_print_ulong(char *buffer, const int buffer_len,
 bool tomoyo_parse_name_union(const char *filename,
                             struct tomoyo_name_union *ptr)
 {
-       if (!tomoyo_is_correct_path(filename, 0, 0, 0))
+       if (!tomoyo_correct_word(filename))
                return false;
        if (filename[0] == '@') {
-               ptr->group = tomoyo_get_path_group(filename + 1);
+               ptr->group = tomoyo_get_group(filename + 1, TOMOYO_PATH_GROUP);
                ptr->is_group = true;
                return ptr->group != NULL;
        }
@@ -115,9 +115,9 @@ bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num)
        unsigned long v;
        memset(num, 0, sizeof(*num));
        if (data[0] == '@') {
-               if (!tomoyo_is_correct_path(data, 0, 0, 0))
+               if (!tomoyo_correct_word(data))
                        return false;
-               num->group = tomoyo_get_number_group(data + 1);
+               num->group = tomoyo_get_group(data + 1, TOMOYO_NUMBER_GROUP);
                num->is_group = true;
                return num->group != NULL;
        }
@@ -142,7 +142,7 @@ bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num)
 }
 
 /**
- * tomoyo_is_byte_range - Check whether the string is a \ooo style octal value.
+ * tomoyo_byte_range - Check whether the string is a \ooo style octal value.
  *
  * @str: Pointer to the string.
  *
@@ -151,7 +151,7 @@ bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num)
  * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
  * This function verifies that \ooo is in valid range.
  */
-static inline bool tomoyo_is_byte_range(const char *str)
+static inline bool tomoyo_byte_range(const char *str)
 {
        return *str >= '0' && *str++ <= '3' &&
                *str >= '0' && *str++ <= '7' &&
@@ -159,13 +159,13 @@ static inline bool tomoyo_is_byte_range(const char *str)
 }
 
 /**
- * tomoyo_is_alphabet_char - Check whether the character is an alphabet.
+ * tomoyo_alphabet_char - Check whether the character is an alphabet.
  *
  * @c: The character to check.
  *
  * Returns true if @c is an alphabet character, false otherwise.
  */
-static inline bool tomoyo_is_alphabet_char(const char c)
+static inline bool tomoyo_alphabet_char(const char c)
 {
        return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
 }
@@ -223,15 +223,15 @@ void tomoyo_normalize_line(unsigned char *buffer)
        unsigned char *dp = buffer;
        bool first = true;
 
-       while (tomoyo_is_invalid(*sp))
+       while (tomoyo_invalid(*sp))
                sp++;
        while (*sp) {
                if (!first)
                        *dp++ = ' ';
                first = false;
-               while (tomoyo_is_valid(*sp))
+               while (tomoyo_valid(*sp))
                        *dp++ = *sp++;
-               while (tomoyo_is_invalid(*sp))
+               while (tomoyo_invalid(*sp))
                        sp++;
        }
        *dp = '\0';
@@ -265,54 +265,29 @@ bool tomoyo_tokenize(char *buffer, char *w[], size_t size)
 }
 
 /**
- * tomoyo_is_correct_path - Validate a pathname.
+ * tomoyo_correct_word2 - Validate a string.
  *
- * @filename:     The pathname to check.
- * @start_type:   Should the pathname start with '/'?
- *                1 = must / -1 = must not / 0 = don't care
- * @pattern_type: Can the pathname contain a wildcard?
- *                1 = must / -1 = must not / 0 = don't care
- * @end_type:     Should the pathname end with '/'?
- *                1 = must / -1 = must not / 0 = don't care
+ * @string: The string to check. May be non-'\0'-terminated.
+ * @len:    Length of @string.
  *
- * Check whether the given filename follows the naming rules.
- * Returns true if @filename follows the naming rules, false otherwise.
+ * Check whether the given string follows the naming rules.
+ * Returns true if @string follows the naming rules, false otherwise.
  */
-bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
-                           const s8 pattern_type, const s8 end_type)
+static bool tomoyo_correct_word2(const char *string, size_t len)
 {
-       const char *const start = filename;
+       const char *const start = string;
        bool in_repetition = false;
-       bool contains_pattern = false;
        unsigned char c;
        unsigned char d;
        unsigned char e;
-
-       if (!filename)
+       if (!len)
                goto out;
-       c = *filename;
-       if (start_type == 1) { /* Must start with '/' */
-               if (c != '/')
-                       goto out;
-       } else if (start_type == -1) { /* Must not start with '/' */
-               if (c == '/')
-                       goto out;
-       }
-       if (c)
-               c = *(filename + strlen(filename) - 1);
-       if (end_type == 1) { /* Must end with '/' */
-               if (c != '/')
-                       goto out;
-       } else if (end_type == -1) { /* Must not end with '/' */
-               if (c == '/')
-                       goto out;
-       }
-       while (1) {
-               c = *filename++;
-               if (!c)
-                       break;
+       while (len--) {
+               c = *string++;
                if (c == '\\') {
-                       c = *filename++;
+                       if (!len--)
+                               goto out;
+                       c = *string++;
                        switch (c) {
                        case '\\':  /* "\\" */
                                continue;
@@ -326,21 +301,14 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
                        case 'a':   /* "\a" */
                        case 'A':   /* "\A" */
                        case '-':   /* "\-" */
-                               if (pattern_type == -1)
-                                       break; /* Must not contain pattern */
-                               contains_pattern = true;
                                continue;
                        case '{':   /* "/\{" */
-                               if (filename - 3 < start ||
-                                   *(filename - 3) != '/')
+                               if (string - 3 < start || *(string - 3) != '/')
                                        break;
-                               if (pattern_type == -1)
-                                       break; /* Must not contain pattern */
-                               contains_pattern = true;
                                in_repetition = true;
                                continue;
                        case '}':   /* "\}/" */
-                               if (*filename != '/')
+                               if (*string != '/')
                                        break;
                                if (!in_repetition)
                                        break;
@@ -350,27 +318,23 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
                        case '1':
                        case '2':
                        case '3':
-                               d = *filename++;
-                               if (d < '0' || d > '7')
+                               if (!len-- || !len--)
                                        break;
-                               e = *filename++;
-                               if (e < '0' || e > '7')
+                               d = *string++;
+                               e = *string++;
+                               if (d < '0' || d > '7' || e < '0' || e > '7')
                                        break;
                                c = tomoyo_make_byte(c, d, e);
-                               if (tomoyo_is_invalid(c))
+                               if (tomoyo_invalid(c))
                                        continue; /* pattern is not \000 */
                        }
                        goto out;
                } else if (in_repetition && c == '/') {
                        goto out;
-               } else if (tomoyo_is_invalid(c)) {
+               } else if (tomoyo_invalid(c)) {
                        goto out;
                }
        }
-       if (pattern_type == 1) { /* Must contain pattern */
-               if (!contains_pattern)
-                       goto out;
-       }
        if (in_repetition)
                goto out;
        return true;
@@ -379,70 +343,70 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
 }
 
 /**
- * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules.
+ * tomoyo_correct_word - Validate a string.
  *
- * @domainname:   The domainname to check.
+ * @string: The string to check.
  *
- * Returns true if @domainname follows the naming rules, false otherwise.
+ * Check whether the given string follows the naming rules.
+ * Returns true if @string follows the naming rules, false otherwise.
  */
-bool tomoyo_is_correct_domain(const unsigned char *domainname)
+bool tomoyo_correct_word(const char *string)
 {
-       unsigned char c;
-       unsigned char d;
-       unsigned char e;
+       return tomoyo_correct_word2(string, strlen(string));
+}
+
+/**
+ * tomoyo_correct_path - Validate a pathname.
+ *
+ * @filename: The pathname to check.
+ *
+ * Check whether the given pathname follows the naming rules.
+ * Returns true if @filename follows the naming rules, false otherwise.
+ */
+bool tomoyo_correct_path(const char *filename)
+{
+       return *filename == '/' && tomoyo_correct_word(filename);
+}
 
+/**
+ * tomoyo_correct_domain - Check whether the given domainname follows the naming rules.
+ *
+ * @domainname: The domainname to check.
+ *
+ * Returns true if @domainname follows the naming rules, false otherwise.
+ */
+bool tomoyo_correct_domain(const unsigned char *domainname)
+{
        if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
                                   TOMOYO_ROOT_NAME_LEN))
                goto out;
        domainname += TOMOYO_ROOT_NAME_LEN;
        if (!*domainname)
                return true;
-       do {
-               if (*domainname++ != ' ')
-                       goto out;
-               if (*domainname++ != '/')
+       if (*domainname++ != ' ')
+               goto out;
+       while (1) {
+               const unsigned char *cp = strchr(domainname, ' ');
+               if (!cp)
+                       break;
+               if (*domainname != '/' ||
+                   !tomoyo_correct_word2(domainname, cp - domainname - 1))
                        goto out;
-               while ((c = *domainname) != '\0' && c != ' ') {
-                       domainname++;
-                       if (c == '\\') {
-                               c = *domainname++;
-                               switch ((c)) {
-                               case '\\':  /* "\\" */
-                                       continue;
-                               case '0':   /* "\ooo" */
-                               case '1':
-                               case '2':
-                               case '3':
-                                       d = *domainname++;
-                                       if (d < '0' || d > '7')
-                                               break;
-                                       e = *domainname++;
-                                       if (e < '0' || e > '7')
-                                               break;
-                                       c = tomoyo_make_byte(c, d, e);
-                                       if (tomoyo_is_invalid(c))
-                                               /* pattern is not \000 */
-                                               continue;
-                               }
-                               goto out;
-                       } else if (tomoyo_is_invalid(c)) {
-                               goto out;
-                       }
-               }
-       } while (*domainname);
-       return true;
+               domainname = cp + 1;
+       }
+       return tomoyo_correct_path(domainname);
  out:
        return false;
 }
 
 /**
- * tomoyo_is_domain_def - Check whether the given token can be a domainname.
+ * tomoyo_domain_def - Check whether the given token can be a domainname.
  *
  * @buffer: The token to check.
  *
  * Returns true if @buffer possibly be a domainname, false otherwise.
  */
-bool tomoyo_is_domain_def(const unsigned char *buffer)
+bool tomoyo_domain_def(const unsigned char *buffer)
 {
        return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN);
 }
@@ -564,7 +528,7 @@ static bool tomoyo_file_matches_pattern2(const char *filename,
                        } else if (c == '\\') {
                                if (filename[1] == '\\')
                                        filename++;
-                               else if (tomoyo_is_byte_range(filename + 1))
+                               else if (tomoyo_byte_range(filename + 1))
                                        filename += 3;
                                else
                                        return false;
@@ -585,14 +549,14 @@ static bool tomoyo_file_matches_pattern2(const char *filename,
                                return false;
                        break;
                case 'a':
-                       if (!tomoyo_is_alphabet_char(c))
+                       if (!tomoyo_alphabet_char(c))
                                return false;
                        break;
                case '0':
                case '1':
                case '2':
                case '3':
-                       if (c == '\\' && tomoyo_is_byte_range(filename + 1)
+                       if (c == '\\' && tomoyo_byte_range(filename + 1)
                            && strncmp(filename + 1, pattern, 3) == 0) {
                                filename += 3;
                                pattern += 2;
@@ -613,7 +577,7 @@ static bool tomoyo_file_matches_pattern2(const char *filename,
                                        continue;
                                if (filename[i + 1] == '\\')
                                        i++;
-                               else if (tomoyo_is_byte_range(filename + i + 1))
+                               else if (tomoyo_byte_range(filename + i + 1))
                                        i += 3;
                                else
                                        break; /* Bad pattern. */
@@ -629,7 +593,7 @@ static bool tomoyo_file_matches_pattern2(const char *filename,
                                while (isxdigit(filename[j]))
                                        j++;
                        } else if (c == 'A') {
-                               while (tomoyo_is_alphabet_char(filename[j]))
+                               while (tomoyo_alphabet_char(filename[j]))
                                        j++;
                        }
                        for (i = 1; i <= j; i++) {
@@ -828,25 +792,67 @@ const char *tomoyo_get_exe(void)
 }
 
 /**
+ * tomoyo_get_mode - Get MAC mode.
+ *
+ * @profile: Profile number.
+ * @index:   Index number of functionality.
+ *
+ * Returns mode.
+ */
+int tomoyo_get_mode(const u8 profile, const u8 index)
+{
+       u8 mode;
+       const u8 category = TOMOYO_MAC_CATEGORY_FILE;
+       if (!tomoyo_policy_loaded)
+               return TOMOYO_CONFIG_DISABLED;
+       mode = tomoyo_profile(profile)->config[index];
+       if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+               mode = tomoyo_profile(profile)->config[category];
+       if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+               mode = tomoyo_profile(profile)->default_config;
+       return mode & 3;
+}
+
+/**
  * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members.
  *
  * @r:      Pointer to "struct tomoyo_request_info" to initialize.
  * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain().
+ * @index:  Index number of functionality.
  *
  * Returns mode.
  */
 int tomoyo_init_request_info(struct tomoyo_request_info *r,
-                            struct tomoyo_domain_info *domain)
+                            struct tomoyo_domain_info *domain, const u8 index)
 {
+       u8 profile;
        memset(r, 0, sizeof(*r));
        if (!domain)
                domain = tomoyo_domain();
        r->domain = domain;
-       r->mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
+       profile = domain->profile;
+       r->profile = profile;
+       r->type = index;
+       r->mode = tomoyo_get_mode(profile, index);
        return r->mode;
 }
 
 /**
+ * tomoyo_last_word - Get last component of a line.
+ *
+ * @line: A line.
+ *
+ * Returns the last word of a line.
+ */
+const char *tomoyo_last_word(const char *name)
+{
+       const char *cp = strrchr(name, ' ');
+       if (cp)
+               return cp + 1;
+       return name;
+}
+
+/**
  * tomoyo_warn_log - Print warning or error message on console.
  *
  * @r:   Pointer to "struct tomoyo_request_info".
@@ -854,29 +860,34 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r,
  */
 void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...)
 {
-       int len = PAGE_SIZE;
        va_list args;
        char *buffer;
-       if (!tomoyo_verbose_mode(r->domain))
-               return;
-       while (1) {
-               int len2;
-               buffer = kmalloc(len, GFP_NOFS);
-               if (!buffer)
+       const struct tomoyo_domain_info * const domain = r->domain;
+       const struct tomoyo_profile *profile = tomoyo_profile(domain->profile);
+       switch (r->mode) {
+       case TOMOYO_CONFIG_ENFORCING:
+               if (!profile->enforcing->enforcing_verbose)
                        return;
-               va_start(args, fmt);
-               len2 = vsnprintf(buffer, len - 1, fmt, args);
-               va_end(args);
-               if (len2 <= len - 1) {
-                       buffer[len2] = '\0';
-                       break;
-               }
-               len = len2 + 1;
-               kfree(buffer);
+               break;
+       case TOMOYO_CONFIG_PERMISSIVE:
+               if (!profile->permissive->permissive_verbose)
+                       return;
+               break;
+       case TOMOYO_CONFIG_LEARNING:
+               if (!profile->learning->learning_verbose)
+                       return;
+               break;
        }
-       printk(KERN_WARNING "TOMOYO-%s: Access %s denied for %s\n",
-              r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING",
-              buffer, tomoyo_get_last_name(r->domain));
+       buffer = kmalloc(4096, GFP_NOFS);
+       if (!buffer)
+               return;
+       va_start(args, fmt);
+       vsnprintf(buffer, 4095, fmt, args);
+       va_end(args);
+       buffer[4095] = '\0';
+       printk(KERN_WARNING "%s: Access %s denied for %s\n",
+              r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING", buffer,
+              tomoyo_last_word(domain->domainname->name));
        kfree(buffer);
 }
 
@@ -900,6 +911,8 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
        if (!domain)
                return true;
        list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+               if (ptr->is_deleted)
+                       continue;
                switch (ptr->type) {
                        u16 perm;
                        u8 i;
@@ -926,20 +939,19 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
                                if (perm & (1 << i))
                                        count++;
                        break;
-               case TOMOYO_TYPE_PATH_NUMBER3_ACL:
-                       perm = container_of(ptr, struct tomoyo_path_number3_acl,
+               case TOMOYO_TYPE_MKDEV_ACL:
+                       perm = container_of(ptr, struct tomoyo_mkdev_acl,
                                            head)->perm;
-                       for (i = 0; i < TOMOYO_MAX_PATH_NUMBER3_OPERATION; i++)
+                       for (i = 0; i < TOMOYO_MAX_MKDEV_OPERATION; i++)
                                if (perm & (1 << i))
                                        count++;
                        break;
-               case TOMOYO_TYPE_MOUNT_ACL:
-                       if (!container_of(ptr, struct tomoyo_mount_acl, head)->
-                           is_deleted)
-                               count++;
+               default:
+                       count++;
                }
        }
-       if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
+       if (count < tomoyo_profile(domain->profile)->learning->
+           learning_max_entry)
                return true;
        if (!domain->quota_warned) {
                domain->quota_warned = true;