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