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