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