xref: /linux/security/tomoyo/util.c (revision 2fe05e1139a555ae91f00a812cb9520e7d3022ab)
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 }
1091