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