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