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