xref: /openbmc/linux/security/tomoyo/util.c (revision 80176f65)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2c3ef1500STetsuo Handa /*
3c3ef1500STetsuo Handa  * security/tomoyo/util.c
4c3ef1500STetsuo Handa  *
50f2a55d5STetsuo Handa  * Copyright (C) 2005-2011  NTT DATA CORPORATION
6c3ef1500STetsuo Handa  */
7c3ef1500STetsuo Handa 
8c3ef1500STetsuo Handa #include <linux/slab.h>
9b2d09103SIngo Molnar #include <linux/rculist.h>
10b2d09103SIngo Molnar 
11c3ef1500STetsuo Handa #include "common.h"
12c3ef1500STetsuo Handa 
13c3ef1500STetsuo Handa /* Lock for protecting policy. */
14c3ef1500STetsuo Handa DEFINE_MUTEX(tomoyo_policy_lock);
15c3ef1500STetsuo Handa 
16c3ef1500STetsuo Handa /* Has /sbin/init started? */
17c3ef1500STetsuo Handa bool tomoyo_policy_loaded;
18c3ef1500STetsuo Handa 
192c47ab93STetsuo Handa /*
202c47ab93STetsuo Handa  * Mapping table from "enum tomoyo_mac_index" to
212c47ab93STetsuo Handa  * "enum tomoyo_mac_category_index".
222c47ab93STetsuo Handa  */
232c47ab93STetsuo Handa const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = {
242c47ab93STetsuo Handa 	/* CONFIG::file group */
252c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_EXECUTE]    = TOMOYO_MAC_CATEGORY_FILE,
262c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_OPEN]       = TOMOYO_MAC_CATEGORY_FILE,
272c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_CREATE]     = TOMOYO_MAC_CATEGORY_FILE,
282c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_UNLINK]     = TOMOYO_MAC_CATEGORY_FILE,
292c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_GETATTR]    = TOMOYO_MAC_CATEGORY_FILE,
302c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_MKDIR]      = TOMOYO_MAC_CATEGORY_FILE,
312c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_RMDIR]      = TOMOYO_MAC_CATEGORY_FILE,
322c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_MKFIFO]     = TOMOYO_MAC_CATEGORY_FILE,
332c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_MKSOCK]     = TOMOYO_MAC_CATEGORY_FILE,
342c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_TRUNCATE]   = TOMOYO_MAC_CATEGORY_FILE,
352c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_SYMLINK]    = TOMOYO_MAC_CATEGORY_FILE,
362c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_MKBLOCK]    = TOMOYO_MAC_CATEGORY_FILE,
372c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_MKCHAR]     = TOMOYO_MAC_CATEGORY_FILE,
382c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_LINK]       = TOMOYO_MAC_CATEGORY_FILE,
392c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_RENAME]     = TOMOYO_MAC_CATEGORY_FILE,
402c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_CHMOD]      = TOMOYO_MAC_CATEGORY_FILE,
412c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_CHOWN]      = TOMOYO_MAC_CATEGORY_FILE,
422c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_CHGRP]      = TOMOYO_MAC_CATEGORY_FILE,
432c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_IOCTL]      = TOMOYO_MAC_CATEGORY_FILE,
442c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_CHROOT]     = TOMOYO_MAC_CATEGORY_FILE,
452c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_MOUNT]      = TOMOYO_MAC_CATEGORY_FILE,
462c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_UMOUNT]     = TOMOYO_MAC_CATEGORY_FILE,
472c47ab93STetsuo Handa 	[TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE,
48059d84dbSTetsuo Handa 	/* CONFIG::network group */
49059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_INET_STREAM_BIND]       =
50059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
51059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN]     =
52059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
53059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT]    =
54059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
55059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_INET_DGRAM_BIND]        =
56059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
57059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_INET_DGRAM_SEND]        =
58059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
59059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_INET_RAW_BIND]          =
60059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
61059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_INET_RAW_SEND]          =
62059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
63059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND]       =
64059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
65059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN]     =
66059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
67059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT]    =
68059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
69059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND]        =
70059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
71059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND]        =
72059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
73059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND]    =
74059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
75059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN]  =
76059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
77059d84dbSTetsuo Handa 	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] =
78059d84dbSTetsuo Handa 	TOMOYO_MAC_CATEGORY_NETWORK,
79d58e0da8STetsuo Handa 	/* CONFIG::misc group */
80d58e0da8STetsuo Handa 	[TOMOYO_MAC_ENVIRON]         = TOMOYO_MAC_CATEGORY_MISC,
812c47ab93STetsuo Handa };
822c47ab93STetsuo Handa 
83c3ef1500STetsuo Handa /**
84b22b8b9fSTetsuo Handa  * tomoyo_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss.
85b22b8b9fSTetsuo Handa  *
8698eaa63eSChenXiaoSong  * @time64: Seconds since 1970/01/01 00:00:00.
87b22b8b9fSTetsuo Handa  * @stamp:  Pointer to "struct tomoyo_time".
88b22b8b9fSTetsuo Handa  *
89b22b8b9fSTetsuo Handa  * Returns nothing.
90b22b8b9fSTetsuo Handa  */
tomoyo_convert_time(time64_t time64,struct tomoyo_time * stamp)9192734092SArnd Bergmann void tomoyo_convert_time(time64_t time64, struct tomoyo_time *stamp)
92b22b8b9fSTetsuo Handa {
9392734092SArnd Bergmann 	struct tm tm;
94cdcf6723STetsuo Handa 
9592734092SArnd Bergmann 	time64_to_tm(time64, 0, &tm);
9692734092SArnd Bergmann 	stamp->sec = tm.tm_sec;
9792734092SArnd Bergmann 	stamp->min = tm.tm_min;
9892734092SArnd Bergmann 	stamp->hour = tm.tm_hour;
9992734092SArnd Bergmann 	stamp->day = tm.tm_mday;
10092734092SArnd Bergmann 	stamp->month = tm.tm_mon + 1;
10192734092SArnd Bergmann 	stamp->year = tm.tm_year + 1900;
102b22b8b9fSTetsuo Handa }
103b22b8b9fSTetsuo Handa 
104b22b8b9fSTetsuo Handa /**
105a238cf5bSTetsuo Handa  * tomoyo_permstr - Find permission keywords.
106a238cf5bSTetsuo Handa  *
107a238cf5bSTetsuo Handa  * @string: String representation for permissions in foo/bar/buz format.
108a238cf5bSTetsuo Handa  * @keyword: Keyword to find from @string/
109a238cf5bSTetsuo Handa  *
110f09c296eSYangtao Li  * Returns true if @keyword was found in @string, false otherwise.
111a238cf5bSTetsuo Handa  *
112a238cf5bSTetsuo Handa  * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2.
113a238cf5bSTetsuo Handa  */
tomoyo_permstr(const char * string,const char * keyword)114a238cf5bSTetsuo Handa bool tomoyo_permstr(const char *string, const char *keyword)
115a238cf5bSTetsuo Handa {
116a238cf5bSTetsuo Handa 	const char *cp = strstr(string, keyword);
117cdcf6723STetsuo Handa 
118a238cf5bSTetsuo Handa 	if (cp)
119a238cf5bSTetsuo Handa 		return cp == string || *(cp - 1) == '/';
120a238cf5bSTetsuo Handa 	return false;
121a238cf5bSTetsuo Handa }
122a238cf5bSTetsuo Handa 
123a238cf5bSTetsuo Handa /**
124a238cf5bSTetsuo Handa  * tomoyo_read_token - Read a word from a line.
125a238cf5bSTetsuo Handa  *
126a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
127a238cf5bSTetsuo Handa  *
128a238cf5bSTetsuo Handa  * Returns a word on success, "" otherwise.
129a238cf5bSTetsuo Handa  *
130a238cf5bSTetsuo Handa  * To allow the caller to skip NULL check, this function returns "" rather than
131a238cf5bSTetsuo Handa  * NULL if there is no more words to read.
132a238cf5bSTetsuo Handa  */
tomoyo_read_token(struct tomoyo_acl_param * param)133a238cf5bSTetsuo Handa char *tomoyo_read_token(struct tomoyo_acl_param *param)
134a238cf5bSTetsuo Handa {
135a238cf5bSTetsuo Handa 	char *pos = param->data;
136a238cf5bSTetsuo Handa 	char *del = strchr(pos, ' ');
137cdcf6723STetsuo Handa 
138a238cf5bSTetsuo Handa 	if (del)
139a238cf5bSTetsuo Handa 		*del++ = '\0';
140a238cf5bSTetsuo Handa 	else
141a238cf5bSTetsuo Handa 		del = pos + strlen(pos);
142a238cf5bSTetsuo Handa 	param->data = del;
143a238cf5bSTetsuo Handa 	return pos;
144a238cf5bSTetsuo Handa }
145a238cf5bSTetsuo Handa 
146a2075167STetsuo Handa static bool tomoyo_correct_path2(const char *filename, const size_t len);
147a2075167STetsuo Handa 
148a238cf5bSTetsuo Handa /**
149731d37aaSTetsuo Handa  * tomoyo_get_domainname - Read a domainname from a line.
150731d37aaSTetsuo Handa  *
151731d37aaSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
152731d37aaSTetsuo Handa  *
153731d37aaSTetsuo Handa  * Returns a domainname on success, NULL otherwise.
154731d37aaSTetsuo Handa  */
tomoyo_get_domainname(struct tomoyo_acl_param * param)155731d37aaSTetsuo Handa const struct tomoyo_path_info *tomoyo_get_domainname
156731d37aaSTetsuo Handa (struct tomoyo_acl_param *param)
157731d37aaSTetsuo Handa {
158731d37aaSTetsuo Handa 	char *start = param->data;
159731d37aaSTetsuo Handa 	char *pos = start;
160cdcf6723STetsuo Handa 
161731d37aaSTetsuo Handa 	while (*pos) {
162a2075167STetsuo Handa 		if (*pos++ != ' ' ||
163a2075167STetsuo Handa 		    tomoyo_correct_path2(pos, strchrnul(pos, ' ') - pos))
164731d37aaSTetsuo Handa 			continue;
165a2075167STetsuo Handa 		*(pos - 1) = '\0';
166731d37aaSTetsuo Handa 		break;
167731d37aaSTetsuo Handa 	}
168731d37aaSTetsuo Handa 	param->data = pos;
169731d37aaSTetsuo Handa 	if (tomoyo_correct_domain(start))
170731d37aaSTetsuo Handa 		return tomoyo_get_name(start);
171731d37aaSTetsuo Handa 	return NULL;
172731d37aaSTetsuo Handa }
173731d37aaSTetsuo Handa 
174731d37aaSTetsuo Handa /**
175c3ef1500STetsuo Handa  * tomoyo_parse_ulong - Parse an "unsigned long" value.
176c3ef1500STetsuo Handa  *
177c3ef1500STetsuo Handa  * @result: Pointer to "unsigned long".
178c3ef1500STetsuo Handa  * @str:    Pointer to string to parse.
179c3ef1500STetsuo Handa  *
1800df7e8b8STetsuo Handa  * Returns one of values in "enum tomoyo_value_type".
181c3ef1500STetsuo Handa  *
182c3ef1500STetsuo Handa  * The @src is updated to point the first character after the value
183c3ef1500STetsuo Handa  * on success.
184c3ef1500STetsuo Handa  */
tomoyo_parse_ulong(unsigned long * result,char ** str)1852066a361STetsuo Handa u8 tomoyo_parse_ulong(unsigned long *result, char **str)
186c3ef1500STetsuo Handa {
187c3ef1500STetsuo Handa 	const char *cp = *str;
188c3ef1500STetsuo Handa 	char *ep;
189c3ef1500STetsuo Handa 	int base = 10;
190cdcf6723STetsuo Handa 
191c3ef1500STetsuo Handa 	if (*cp == '0') {
192c3ef1500STetsuo Handa 		char c = *(cp + 1);
193cdcf6723STetsuo Handa 
194c3ef1500STetsuo Handa 		if (c == 'x' || c == 'X') {
195c3ef1500STetsuo Handa 			base = 16;
196c3ef1500STetsuo Handa 			cp += 2;
197c3ef1500STetsuo Handa 		} else if (c >= '0' && c <= '7') {
198c3ef1500STetsuo Handa 			base = 8;
199c3ef1500STetsuo Handa 			cp++;
200c3ef1500STetsuo Handa 		}
201c3ef1500STetsuo Handa 	}
202c3ef1500STetsuo Handa 	*result = simple_strtoul(cp, &ep, base);
203c3ef1500STetsuo Handa 	if (cp == ep)
2040df7e8b8STetsuo Handa 		return TOMOYO_VALUE_TYPE_INVALID;
205c3ef1500STetsuo Handa 	*str = ep;
206c3ef1500STetsuo Handa 	switch (base) {
207c3ef1500STetsuo Handa 	case 16:
208c3ef1500STetsuo Handa 		return TOMOYO_VALUE_TYPE_HEXADECIMAL;
209c3ef1500STetsuo Handa 	case 8:
210c3ef1500STetsuo Handa 		return TOMOYO_VALUE_TYPE_OCTAL;
211c3ef1500STetsuo Handa 	default:
212c3ef1500STetsuo Handa 		return TOMOYO_VALUE_TYPE_DECIMAL;
213c3ef1500STetsuo Handa 	}
214c3ef1500STetsuo Handa }
215c3ef1500STetsuo Handa 
216c3ef1500STetsuo Handa /**
217c3ef1500STetsuo Handa  * tomoyo_print_ulong - Print an "unsigned long" value.
218c3ef1500STetsuo Handa  *
219c3ef1500STetsuo Handa  * @buffer:     Pointer to buffer.
220c3ef1500STetsuo Handa  * @buffer_len: Size of @buffer.
221c3ef1500STetsuo Handa  * @value:      An "unsigned long" value.
222c3ef1500STetsuo Handa  * @type:       Type of @value.
223c3ef1500STetsuo Handa  *
224c3ef1500STetsuo Handa  * Returns nothing.
225c3ef1500STetsuo Handa  */
tomoyo_print_ulong(char * buffer,const int buffer_len,const unsigned long value,const u8 type)226c3ef1500STetsuo Handa void tomoyo_print_ulong(char *buffer, const int buffer_len,
227c3ef1500STetsuo Handa 			const unsigned long value, const u8 type)
228c3ef1500STetsuo Handa {
229c3ef1500STetsuo Handa 	if (type == TOMOYO_VALUE_TYPE_DECIMAL)
230c3ef1500STetsuo Handa 		snprintf(buffer, buffer_len, "%lu", value);
231c3ef1500STetsuo Handa 	else if (type == TOMOYO_VALUE_TYPE_OCTAL)
232c3ef1500STetsuo Handa 		snprintf(buffer, buffer_len, "0%lo", value);
233c3ef1500STetsuo Handa 	else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL)
234c3ef1500STetsuo Handa 		snprintf(buffer, buffer_len, "0x%lX", value);
235c3ef1500STetsuo Handa 	else
236c3ef1500STetsuo Handa 		snprintf(buffer, buffer_len, "type(%u)", type);
237c3ef1500STetsuo Handa }
238c3ef1500STetsuo Handa 
239c3ef1500STetsuo Handa /**
240c3ef1500STetsuo Handa  * tomoyo_parse_name_union - Parse a tomoyo_name_union.
241c3ef1500STetsuo Handa  *
242a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
243c3ef1500STetsuo Handa  * @ptr:   Pointer to "struct tomoyo_name_union".
244c3ef1500STetsuo Handa  *
245c3ef1500STetsuo Handa  * Returns true on success, false otherwise.
246c3ef1500STetsuo Handa  */
tomoyo_parse_name_union(struct tomoyo_acl_param * param,struct tomoyo_name_union * ptr)247a238cf5bSTetsuo Handa bool tomoyo_parse_name_union(struct tomoyo_acl_param *param,
248c3ef1500STetsuo Handa 			     struct tomoyo_name_union *ptr)
249c3ef1500STetsuo Handa {
250a238cf5bSTetsuo Handa 	char *filename;
251cdcf6723STetsuo Handa 
252a238cf5bSTetsuo Handa 	if (param->data[0] == '@') {
253a238cf5bSTetsuo Handa 		param->data++;
254a238cf5bSTetsuo Handa 		ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP);
255c3ef1500STetsuo Handa 		return ptr->group != NULL;
256c3ef1500STetsuo Handa 	}
257a238cf5bSTetsuo Handa 	filename = tomoyo_read_token(param);
258a238cf5bSTetsuo Handa 	if (!tomoyo_correct_word(filename))
259a238cf5bSTetsuo Handa 		return false;
260c3ef1500STetsuo Handa 	ptr->filename = tomoyo_get_name(filename);
261c3ef1500STetsuo Handa 	return ptr->filename != NULL;
262c3ef1500STetsuo Handa }
263c3ef1500STetsuo Handa 
264c3ef1500STetsuo Handa /**
265c3ef1500STetsuo Handa  * tomoyo_parse_number_union - Parse a tomoyo_number_union.
266c3ef1500STetsuo Handa  *
267a238cf5bSTetsuo Handa  * @param: Pointer to "struct tomoyo_acl_param".
268c3ef1500STetsuo Handa  * @ptr:   Pointer to "struct tomoyo_number_union".
269c3ef1500STetsuo Handa  *
270c3ef1500STetsuo Handa  * Returns true on success, false otherwise.
271c3ef1500STetsuo Handa  */
tomoyo_parse_number_union(struct tomoyo_acl_param * param,struct tomoyo_number_union * ptr)272a238cf5bSTetsuo Handa bool tomoyo_parse_number_union(struct tomoyo_acl_param *param,
273a238cf5bSTetsuo Handa 			       struct tomoyo_number_union *ptr)
274c3ef1500STetsuo Handa {
275a238cf5bSTetsuo Handa 	char *data;
276c3ef1500STetsuo Handa 	u8 type;
277c3ef1500STetsuo Handa 	unsigned long v;
278cdcf6723STetsuo Handa 
279a238cf5bSTetsuo Handa 	memset(ptr, 0, sizeof(*ptr));
280a238cf5bSTetsuo Handa 	if (param->data[0] == '@') {
281a238cf5bSTetsuo Handa 		param->data++;
282a238cf5bSTetsuo Handa 		ptr->group = tomoyo_get_group(param, TOMOYO_NUMBER_GROUP);
283a238cf5bSTetsuo Handa 		return ptr->group != NULL;
284c3ef1500STetsuo Handa 	}
285a238cf5bSTetsuo Handa 	data = tomoyo_read_token(param);
286c3ef1500STetsuo Handa 	type = tomoyo_parse_ulong(&v, &data);
287a238cf5bSTetsuo Handa 	if (type == TOMOYO_VALUE_TYPE_INVALID)
288c3ef1500STetsuo Handa 		return false;
289a238cf5bSTetsuo Handa 	ptr->values[0] = v;
290a238cf5bSTetsuo Handa 	ptr->value_type[0] = type;
291c3ef1500STetsuo Handa 	if (!*data) {
292a238cf5bSTetsuo Handa 		ptr->values[1] = v;
293a238cf5bSTetsuo Handa 		ptr->value_type[1] = type;
294c3ef1500STetsuo Handa 		return true;
295c3ef1500STetsuo Handa 	}
296c3ef1500STetsuo Handa 	if (*data++ != '-')
297c3ef1500STetsuo Handa 		return false;
298c3ef1500STetsuo Handa 	type = tomoyo_parse_ulong(&v, &data);
299a238cf5bSTetsuo Handa 	if (type == TOMOYO_VALUE_TYPE_INVALID || *data || ptr->values[0] > v)
300c3ef1500STetsuo Handa 		return false;
301a238cf5bSTetsuo Handa 	ptr->values[1] = v;
302a238cf5bSTetsuo Handa 	ptr->value_type[1] = type;
303c3ef1500STetsuo Handa 	return true;
304c3ef1500STetsuo Handa }
305c3ef1500STetsuo Handa 
306c3ef1500STetsuo Handa /**
30775093152STetsuo Handa  * tomoyo_byte_range - Check whether the string is a \ooo style octal value.
308c3ef1500STetsuo Handa  *
309c3ef1500STetsuo Handa  * @str: Pointer to the string.
310c3ef1500STetsuo Handa  *
311c3ef1500STetsuo Handa  * Returns true if @str is a \ooo style octal value, false otherwise.
312c3ef1500STetsuo Handa  *
313c3ef1500STetsuo Handa  * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
314c3ef1500STetsuo Handa  * This function verifies that \ooo is in valid range.
315c3ef1500STetsuo Handa  */
tomoyo_byte_range(const char * str)31675093152STetsuo Handa static inline bool tomoyo_byte_range(const char *str)
317c3ef1500STetsuo Handa {
318c3ef1500STetsuo Handa 	return *str >= '0' && *str++ <= '3' &&
319c3ef1500STetsuo Handa 		*str >= '0' && *str++ <= '7' &&
320c3ef1500STetsuo Handa 		*str >= '0' && *str <= '7';
321c3ef1500STetsuo Handa }
322c3ef1500STetsuo Handa 
323c3ef1500STetsuo Handa /**
32475093152STetsuo Handa  * tomoyo_alphabet_char - Check whether the character is an alphabet.
325c3ef1500STetsuo Handa  *
326c3ef1500STetsuo Handa  * @c: The character to check.
327c3ef1500STetsuo Handa  *
328c3ef1500STetsuo Handa  * Returns true if @c is an alphabet character, false otherwise.
329c3ef1500STetsuo Handa  */
tomoyo_alphabet_char(const char c)33075093152STetsuo Handa static inline bool tomoyo_alphabet_char(const char c)
331c3ef1500STetsuo Handa {
332c3ef1500STetsuo Handa 	return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
333c3ef1500STetsuo Handa }
334c3ef1500STetsuo Handa 
335c3ef1500STetsuo Handa /**
336c3ef1500STetsuo Handa  * tomoyo_make_byte - Make byte value from three octal characters.
337c3ef1500STetsuo Handa  *
338c3ef1500STetsuo Handa  * @c1: The first character.
339c3ef1500STetsuo Handa  * @c2: The second character.
340c3ef1500STetsuo Handa  * @c3: The third character.
341c3ef1500STetsuo Handa  *
342c3ef1500STetsuo Handa  * Returns byte value.
343c3ef1500STetsuo Handa  */
tomoyo_make_byte(const u8 c1,const u8 c2,const u8 c3)344c3ef1500STetsuo Handa static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
345c3ef1500STetsuo Handa {
346c3ef1500STetsuo Handa 	return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
347c3ef1500STetsuo Handa }
348c3ef1500STetsuo Handa 
349c3ef1500STetsuo Handa /**
3500df7e8b8STetsuo Handa  * tomoyo_valid - Check whether the character is a valid char.
3510df7e8b8STetsuo Handa  *
3520df7e8b8STetsuo Handa  * @c: The character to check.
3530df7e8b8STetsuo Handa  *
3540df7e8b8STetsuo Handa  * Returns true if @c is a valid character, false otherwise.
3550df7e8b8STetsuo Handa  */
tomoyo_valid(const unsigned char c)3560df7e8b8STetsuo Handa static inline bool tomoyo_valid(const unsigned char c)
3570df7e8b8STetsuo Handa {
3580df7e8b8STetsuo Handa 	return c > ' ' && c < 127;
3590df7e8b8STetsuo Handa }
3600df7e8b8STetsuo Handa 
3610df7e8b8STetsuo Handa /**
3620df7e8b8STetsuo Handa  * tomoyo_invalid - Check whether the character is an invalid char.
3630df7e8b8STetsuo Handa  *
3640df7e8b8STetsuo Handa  * @c: The character to check.
3650df7e8b8STetsuo Handa  *
3660df7e8b8STetsuo Handa  * Returns true if @c is an invalid character, false otherwise.
3670df7e8b8STetsuo Handa  */
tomoyo_invalid(const unsigned char c)3680df7e8b8STetsuo Handa static inline bool tomoyo_invalid(const unsigned char c)
3690df7e8b8STetsuo Handa {
3700df7e8b8STetsuo Handa 	return c && (c <= ' ' || c >= 127);
3710df7e8b8STetsuo Handa }
3720df7e8b8STetsuo Handa 
3730df7e8b8STetsuo Handa /**
374c3ef1500STetsuo Handa  * tomoyo_str_starts - Check whether the given string starts with the given keyword.
375c3ef1500STetsuo Handa  *
376c3ef1500STetsuo Handa  * @src:  Pointer to pointer to the string.
377c3ef1500STetsuo Handa  * @find: Pointer to the keyword.
378c3ef1500STetsuo Handa  *
379c3ef1500STetsuo Handa  * Returns true if @src starts with @find, false otherwise.
380c3ef1500STetsuo Handa  *
381c3ef1500STetsuo Handa  * The @src is updated to point the first character after the @find
382c3ef1500STetsuo Handa  * if @src starts with @find.
383c3ef1500STetsuo Handa  */
tomoyo_str_starts(char ** src,const char * find)384c3ef1500STetsuo Handa bool tomoyo_str_starts(char **src, const char *find)
385c3ef1500STetsuo Handa {
386c3ef1500STetsuo Handa 	const int len = strlen(find);
387c3ef1500STetsuo Handa 	char *tmp = *src;
388c3ef1500STetsuo Handa 
389c3ef1500STetsuo Handa 	if (strncmp(tmp, find, len))
390c3ef1500STetsuo Handa 		return false;
391c3ef1500STetsuo Handa 	tmp += len;
392c3ef1500STetsuo Handa 	*src = tmp;
393c3ef1500STetsuo Handa 	return true;
394c3ef1500STetsuo Handa }
395c3ef1500STetsuo Handa 
396c3ef1500STetsuo Handa /**
397c3ef1500STetsuo Handa  * tomoyo_normalize_line - Format string.
398c3ef1500STetsuo Handa  *
399c3ef1500STetsuo Handa  * @buffer: The line to normalize.
400c3ef1500STetsuo Handa  *
401c3ef1500STetsuo Handa  * Leading and trailing whitespaces are removed.
402c3ef1500STetsuo Handa  * Multiple whitespaces are packed into single space.
403c3ef1500STetsuo Handa  *
404c3ef1500STetsuo Handa  * Returns nothing.
405c3ef1500STetsuo Handa  */
tomoyo_normalize_line(unsigned char * buffer)406c3ef1500STetsuo Handa void tomoyo_normalize_line(unsigned char *buffer)
407c3ef1500STetsuo Handa {
408c3ef1500STetsuo Handa 	unsigned char *sp = buffer;
409c3ef1500STetsuo Handa 	unsigned char *dp = buffer;
410c3ef1500STetsuo Handa 	bool first = true;
411c3ef1500STetsuo Handa 
41275093152STetsuo Handa 	while (tomoyo_invalid(*sp))
413c3ef1500STetsuo Handa 		sp++;
414c3ef1500STetsuo Handa 	while (*sp) {
415c3ef1500STetsuo Handa 		if (!first)
416c3ef1500STetsuo Handa 			*dp++ = ' ';
417c3ef1500STetsuo Handa 		first = false;
41875093152STetsuo Handa 		while (tomoyo_valid(*sp))
419c3ef1500STetsuo Handa 			*dp++ = *sp++;
42075093152STetsuo Handa 		while (tomoyo_invalid(*sp))
421c3ef1500STetsuo Handa 			sp++;
422c3ef1500STetsuo Handa 	}
423c3ef1500STetsuo Handa 	*dp = '\0';
424c3ef1500STetsuo Handa }
425c3ef1500STetsuo Handa 
426c3ef1500STetsuo Handa /**
42775093152STetsuo Handa  * tomoyo_correct_word2 - Validate a string.
428c3ef1500STetsuo Handa  *
4293f629636STetsuo Handa  * @string: The string to check. Maybe non-'\0'-terminated.
4303f629636STetsuo Handa  * @len:    Length of @string.
431c3ef1500STetsuo Handa  *
4323f629636STetsuo Handa  * Check whether the given string follows the naming rules.
4333f629636STetsuo Handa  * Returns true if @string follows the naming rules, false otherwise.
434c3ef1500STetsuo Handa  */
tomoyo_correct_word2(const char * string,size_t len)43575093152STetsuo Handa static bool tomoyo_correct_word2(const char *string, size_t len)
436c3ef1500STetsuo Handa {
437e991a40bSTetsuo Handa 	u8 recursion = 20;
4383f629636STetsuo Handa 	const char *const start = string;
439c3ef1500STetsuo Handa 	bool in_repetition = false;
440cdcf6723STetsuo Handa 
4413f629636STetsuo Handa 	if (!len)
442c3ef1500STetsuo Handa 		goto out;
4433f629636STetsuo Handa 	while (len--) {
444e991a40bSTetsuo Handa 		unsigned char c = *string++;
445e991a40bSTetsuo Handa 
446c3ef1500STetsuo Handa 		if (c == '\\') {
4473f629636STetsuo Handa 			if (!len--)
4483f629636STetsuo Handa 				goto out;
4493f629636STetsuo Handa 			c = *string++;
450e991a40bSTetsuo Handa 			if (c >= '0' && c <= '3') {
451e991a40bSTetsuo Handa 				unsigned char d;
452e991a40bSTetsuo Handa 				unsigned char e;
453e991a40bSTetsuo Handa 
454e991a40bSTetsuo Handa 				if (!len-- || !len--)
455e991a40bSTetsuo Handa 					goto out;
456e991a40bSTetsuo Handa 				d = *string++;
457e991a40bSTetsuo Handa 				e = *string++;
458e991a40bSTetsuo Handa 				if (d < '0' || d > '7' || e < '0' || e > '7')
459e991a40bSTetsuo Handa 					goto out;
460e991a40bSTetsuo Handa 				c = tomoyo_make_byte(c, d, e);
461e991a40bSTetsuo Handa 				if (c <= ' ' || c >= 127)
462e991a40bSTetsuo Handa 					continue;
463e991a40bSTetsuo Handa 				goto out;
464e991a40bSTetsuo Handa 			}
465c3ef1500STetsuo Handa 			switch (c) {
466c3ef1500STetsuo Handa 			case '\\':  /* "\\" */
467c3ef1500STetsuo Handa 			case '+':   /* "\+" */
468c3ef1500STetsuo Handa 			case '?':   /* "\?" */
469e991a40bSTetsuo Handa 			case 'x':   /* "\x" */
470e991a40bSTetsuo Handa 			case 'a':   /* "\a" */
471e991a40bSTetsuo Handa 			case '-':   /* "\-" */
472e991a40bSTetsuo Handa 				continue;
473e991a40bSTetsuo Handa 			}
474e991a40bSTetsuo Handa 			if (!recursion--)
475e991a40bSTetsuo Handa 				goto out;
476e991a40bSTetsuo Handa 			switch (c) {
477c3ef1500STetsuo Handa 			case '*':   /* "\*" */
478c3ef1500STetsuo Handa 			case '@':   /* "\@" */
479e991a40bSTetsuo Handa 			case '$':   /* "\$" */
480c3ef1500STetsuo Handa 			case 'X':   /* "\X" */
481c3ef1500STetsuo Handa 			case 'A':   /* "\A" */
482c3ef1500STetsuo Handa 				continue;
483c3ef1500STetsuo Handa 			case '{':   /* "/\{" */
4843f629636STetsuo Handa 				if (string - 3 < start || *(string - 3) != '/')
485e991a40bSTetsuo Handa 					goto out;
486c3ef1500STetsuo Handa 				in_repetition = true;
487c3ef1500STetsuo Handa 				continue;
488c3ef1500STetsuo Handa 			case '}':   /* "\}/" */
4893f629636STetsuo Handa 				if (*string != '/')
490e991a40bSTetsuo Handa 					goto out;
491c3ef1500STetsuo Handa 				if (!in_repetition)
492e991a40bSTetsuo Handa 					goto out;
493c3ef1500STetsuo Handa 				in_repetition = false;
494c3ef1500STetsuo Handa 				continue;
495c3ef1500STetsuo Handa 			}
496c3ef1500STetsuo Handa 			goto out;
497c3ef1500STetsuo Handa 		} else if (in_repetition && c == '/') {
498c3ef1500STetsuo Handa 			goto out;
49925add8cfSTetsuo Handa 		} else if (c <= ' ' || c >= 127) {
500c3ef1500STetsuo Handa 			goto out;
501c3ef1500STetsuo Handa 		}
502c3ef1500STetsuo Handa 	}
503c3ef1500STetsuo Handa 	if (in_repetition)
504c3ef1500STetsuo Handa 		goto out;
505c3ef1500STetsuo Handa 	return true;
506c3ef1500STetsuo Handa  out:
507c3ef1500STetsuo Handa 	return false;
508c3ef1500STetsuo Handa }
509c3ef1500STetsuo Handa 
510c3ef1500STetsuo Handa /**
51175093152STetsuo Handa  * tomoyo_correct_word - Validate a string.
5123f629636STetsuo Handa  *
5133f629636STetsuo Handa  * @string: The string to check.
5143f629636STetsuo Handa  *
5153f629636STetsuo Handa  * Check whether the given string follows the naming rules.
5163f629636STetsuo Handa  * Returns true if @string follows the naming rules, false otherwise.
5173f629636STetsuo Handa  */
tomoyo_correct_word(const char * string)51875093152STetsuo Handa bool tomoyo_correct_word(const char *string)
5193f629636STetsuo Handa {
52075093152STetsuo Handa 	return tomoyo_correct_word2(string, strlen(string));
5213f629636STetsuo Handa }
5223f629636STetsuo Handa 
5233f629636STetsuo Handa /**
524a2075167STetsuo Handa  * tomoyo_correct_path2 - Check whether the given pathname follows the naming rules.
525a2075167STetsuo Handa  *
526a2075167STetsuo Handa  * @filename: The pathname to check.
527a2075167STetsuo Handa  * @len:      Length of @filename.
528a2075167STetsuo Handa  *
529a2075167STetsuo Handa  * Returns true if @filename follows the naming rules, false otherwise.
530a2075167STetsuo Handa  */
tomoyo_correct_path2(const char * filename,const size_t len)531a2075167STetsuo Handa static bool tomoyo_correct_path2(const char *filename, const size_t len)
532a2075167STetsuo Handa {
533a2075167STetsuo Handa 	const char *cp1 = memchr(filename, '/', len);
534a2075167STetsuo Handa 	const char *cp2 = memchr(filename, '.', len);
535a2075167STetsuo Handa 
536a2075167STetsuo Handa 	return cp1 && (!cp2 || (cp1 < cp2)) && tomoyo_correct_word2(filename, len);
537a2075167STetsuo Handa }
538a2075167STetsuo Handa 
539a2075167STetsuo Handa /**
54075093152STetsuo Handa  * tomoyo_correct_path - Validate a pathname.
5413f629636STetsuo Handa  *
5423f629636STetsuo Handa  * @filename: The pathname to check.
5433f629636STetsuo Handa  *
5443f629636STetsuo Handa  * Check whether the given pathname follows the naming rules.
5453f629636STetsuo Handa  * Returns true if @filename follows the naming rules, false otherwise.
5463f629636STetsuo Handa  */
tomoyo_correct_path(const char * filename)54775093152STetsuo Handa bool tomoyo_correct_path(const char *filename)
5483f629636STetsuo Handa {
549a2075167STetsuo Handa 	return tomoyo_correct_path2(filename, strlen(filename));
5503f629636STetsuo Handa }
5513f629636STetsuo Handa 
5523f629636STetsuo Handa /**
55375093152STetsuo Handa  * tomoyo_correct_domain - Check whether the given domainname follows the naming rules.
554c3ef1500STetsuo Handa  *
555c3ef1500STetsuo Handa  * @domainname: The domainname to check.
556c3ef1500STetsuo Handa  *
557c3ef1500STetsuo Handa  * Returns true if @domainname follows the naming rules, false otherwise.
558c3ef1500STetsuo Handa  */
tomoyo_correct_domain(const unsigned char * domainname)55975093152STetsuo Handa bool tomoyo_correct_domain(const unsigned char *domainname)
560c3ef1500STetsuo Handa {
561bd03a3e4STetsuo Handa 	if (!domainname || !tomoyo_domain_def(domainname))
562bd03a3e4STetsuo Handa 		return false;
563bd03a3e4STetsuo Handa 	domainname = strchr(domainname, ' ');
564bd03a3e4STetsuo Handa 	if (!domainname++)
565c3ef1500STetsuo Handa 		return true;
5663f629636STetsuo Handa 	while (1) {
5673f629636STetsuo Handa 		const unsigned char *cp = strchr(domainname, ' ');
568cdcf6723STetsuo Handa 
5693f629636STetsuo Handa 		if (!cp)
570c3ef1500STetsuo Handa 			break;
571a2075167STetsuo Handa 		if (!tomoyo_correct_path2(domainname, cp - domainname))
572bd03a3e4STetsuo Handa 			return false;
5733f629636STetsuo Handa 		domainname = cp + 1;
574c3ef1500STetsuo Handa 	}
57575093152STetsuo Handa 	return tomoyo_correct_path(domainname);
576c3ef1500STetsuo Handa }
577c3ef1500STetsuo Handa 
578c3ef1500STetsuo Handa /**
57975093152STetsuo Handa  * tomoyo_domain_def - Check whether the given token can be a domainname.
580c3ef1500STetsuo Handa  *
581c3ef1500STetsuo Handa  * @buffer: The token to check.
582c3ef1500STetsuo Handa  *
583c3ef1500STetsuo Handa  * Returns true if @buffer possibly be a domainname, false otherwise.
584c3ef1500STetsuo Handa  */
tomoyo_domain_def(const unsigned char * buffer)58575093152STetsuo Handa bool tomoyo_domain_def(const unsigned char *buffer)
586c3ef1500STetsuo Handa {
587bd03a3e4STetsuo Handa 	const unsigned char *cp;
588bd03a3e4STetsuo Handa 	int len;
589cdcf6723STetsuo Handa 
590bd03a3e4STetsuo Handa 	if (*buffer != '<')
591bd03a3e4STetsuo Handa 		return false;
592bd03a3e4STetsuo Handa 	cp = strchr(buffer, ' ');
593bd03a3e4STetsuo Handa 	if (!cp)
594bd03a3e4STetsuo Handa 		len = strlen(buffer);
595bd03a3e4STetsuo Handa 	else
596bd03a3e4STetsuo Handa 		len = cp - buffer;
597bd03a3e4STetsuo Handa 	if (buffer[len - 1] != '>' ||
598bd03a3e4STetsuo Handa 	    !tomoyo_correct_word2(buffer + 1, len - 2))
599bd03a3e4STetsuo Handa 		return false;
600bd03a3e4STetsuo Handa 	return true;
601c3ef1500STetsuo Handa }
602c3ef1500STetsuo Handa 
603c3ef1500STetsuo Handa /**
604c3ef1500STetsuo Handa  * tomoyo_find_domain - Find a domain by the given name.
605c3ef1500STetsuo Handa  *
606c3ef1500STetsuo Handa  * @domainname: The domainname to find.
607c3ef1500STetsuo Handa  *
608c3ef1500STetsuo Handa  * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
609c3ef1500STetsuo Handa  *
610c3ef1500STetsuo Handa  * Caller holds tomoyo_read_lock().
611c3ef1500STetsuo Handa  */
tomoyo_find_domain(const char * domainname)612c3ef1500STetsuo Handa struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
613c3ef1500STetsuo Handa {
614c3ef1500STetsuo Handa 	struct tomoyo_domain_info *domain;
615c3ef1500STetsuo Handa 	struct tomoyo_path_info name;
616c3ef1500STetsuo Handa 
617c3ef1500STetsuo Handa 	name.name = domainname;
618c3ef1500STetsuo Handa 	tomoyo_fill_path_info(&name);
6196bd5ce60STetsuo Handa 	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list,
6206bd5ce60STetsuo Handa 				srcu_read_lock_held(&tomoyo_ss)) {
621c3ef1500STetsuo Handa 		if (!domain->is_deleted &&
622c3ef1500STetsuo Handa 		    !tomoyo_pathcmp(&name, domain->domainname))
623c3ef1500STetsuo Handa 			return domain;
624c3ef1500STetsuo Handa 	}
625c3ef1500STetsuo Handa 	return NULL;
626c3ef1500STetsuo Handa }
627c3ef1500STetsuo Handa 
628c3ef1500STetsuo Handa /**
629c3ef1500STetsuo Handa  * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
630c3ef1500STetsuo Handa  *
631c3ef1500STetsuo Handa  * @filename: The string to evaluate.
632c3ef1500STetsuo Handa  *
633c3ef1500STetsuo Handa  * Returns the initial length without a pattern in @filename.
634c3ef1500STetsuo Handa  */
tomoyo_const_part_length(const char * filename)635c3ef1500STetsuo Handa static int tomoyo_const_part_length(const char *filename)
636c3ef1500STetsuo Handa {
637c3ef1500STetsuo Handa 	char c;
638c3ef1500STetsuo Handa 	int len = 0;
639c3ef1500STetsuo Handa 
640c3ef1500STetsuo Handa 	if (!filename)
641c3ef1500STetsuo Handa 		return 0;
642c3ef1500STetsuo Handa 	while ((c = *filename++) != '\0') {
643c3ef1500STetsuo Handa 		if (c != '\\') {
644c3ef1500STetsuo Handa 			len++;
645c3ef1500STetsuo Handa 			continue;
646c3ef1500STetsuo Handa 		}
647c3ef1500STetsuo Handa 		c = *filename++;
648c3ef1500STetsuo Handa 		switch (c) {
649c3ef1500STetsuo Handa 		case '\\':  /* "\\" */
650c3ef1500STetsuo Handa 			len += 2;
651c3ef1500STetsuo Handa 			continue;
652c3ef1500STetsuo Handa 		case '0':   /* "\ooo" */
653c3ef1500STetsuo Handa 		case '1':
654c3ef1500STetsuo Handa 		case '2':
655c3ef1500STetsuo Handa 		case '3':
656c3ef1500STetsuo Handa 			c = *filename++;
657c3ef1500STetsuo Handa 			if (c < '0' || c > '7')
658c3ef1500STetsuo Handa 				break;
659c3ef1500STetsuo Handa 			c = *filename++;
660c3ef1500STetsuo Handa 			if (c < '0' || c > '7')
661c3ef1500STetsuo Handa 				break;
662c3ef1500STetsuo Handa 			len += 4;
663c3ef1500STetsuo Handa 			continue;
664c3ef1500STetsuo Handa 		}
665c3ef1500STetsuo Handa 		break;
666c3ef1500STetsuo Handa 	}
667c3ef1500STetsuo Handa 	return len;
668c3ef1500STetsuo Handa }
669c3ef1500STetsuo Handa 
670c3ef1500STetsuo Handa /**
671c3ef1500STetsuo Handa  * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
672c3ef1500STetsuo Handa  *
673c3ef1500STetsuo Handa  * @ptr: Pointer to "struct tomoyo_path_info" to fill in.
674c3ef1500STetsuo Handa  *
675c3ef1500STetsuo Handa  * The caller sets "struct tomoyo_path_info"->name.
676c3ef1500STetsuo Handa  */
tomoyo_fill_path_info(struct tomoyo_path_info * ptr)677c3ef1500STetsuo Handa void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
678c3ef1500STetsuo Handa {
679c3ef1500STetsuo Handa 	const char *name = ptr->name;
680c3ef1500STetsuo Handa 	const int len = strlen(name);
681c3ef1500STetsuo Handa 
682c3ef1500STetsuo Handa 	ptr->const_len = tomoyo_const_part_length(name);
683c3ef1500STetsuo Handa 	ptr->is_dir = len && (name[len - 1] == '/');
684c3ef1500STetsuo Handa 	ptr->is_patterned = (ptr->const_len < len);
6858387ff25SLinus Torvalds 	ptr->hash = full_name_hash(NULL, name, len);
686c3ef1500STetsuo Handa }
687c3ef1500STetsuo Handa 
688c3ef1500STetsuo Handa /**
689c3ef1500STetsuo Handa  * tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
690c3ef1500STetsuo Handa  *
691c3ef1500STetsuo Handa  * @filename:     The start of string to check.
692c3ef1500STetsuo Handa  * @filename_end: The end of string to check.
693c3ef1500STetsuo Handa  * @pattern:      The start of pattern to compare.
694c3ef1500STetsuo Handa  * @pattern_end:  The end of pattern to compare.
695c3ef1500STetsuo Handa  *
696c3ef1500STetsuo Handa  * Returns true if @filename matches @pattern, false otherwise.
697c3ef1500STetsuo Handa  */
tomoyo_file_matches_pattern2(const char * filename,const char * filename_end,const char * pattern,const char * pattern_end)698c3ef1500STetsuo Handa static bool tomoyo_file_matches_pattern2(const char *filename,
699c3ef1500STetsuo Handa 					 const char *filename_end,
700c3ef1500STetsuo Handa 					 const char *pattern,
701c3ef1500STetsuo Handa 					 const char *pattern_end)
702c3ef1500STetsuo Handa {
703c3ef1500STetsuo Handa 	while (filename < filename_end && pattern < pattern_end) {
704c3ef1500STetsuo Handa 		char c;
705cdcf6723STetsuo Handa 		int i;
706cdcf6723STetsuo Handa 		int j;
707cdcf6723STetsuo Handa 
708c3ef1500STetsuo Handa 		if (*pattern != '\\') {
709c3ef1500STetsuo Handa 			if (*filename++ != *pattern++)
710c3ef1500STetsuo Handa 				return false;
711c3ef1500STetsuo Handa 			continue;
712c3ef1500STetsuo Handa 		}
713c3ef1500STetsuo Handa 		c = *filename;
714c3ef1500STetsuo Handa 		pattern++;
715c3ef1500STetsuo Handa 		switch (*pattern) {
716c3ef1500STetsuo Handa 		case '?':
717c3ef1500STetsuo Handa 			if (c == '/') {
718c3ef1500STetsuo Handa 				return false;
719c3ef1500STetsuo Handa 			} else if (c == '\\') {
720c3ef1500STetsuo Handa 				if (filename[1] == '\\')
721c3ef1500STetsuo Handa 					filename++;
72275093152STetsuo Handa 				else if (tomoyo_byte_range(filename + 1))
723c3ef1500STetsuo Handa 					filename += 3;
724c3ef1500STetsuo Handa 				else
725c3ef1500STetsuo Handa 					return false;
726c3ef1500STetsuo Handa 			}
727c3ef1500STetsuo Handa 			break;
728c3ef1500STetsuo Handa 		case '\\':
729c3ef1500STetsuo Handa 			if (c != '\\')
730c3ef1500STetsuo Handa 				return false;
731c3ef1500STetsuo Handa 			if (*++filename != '\\')
732c3ef1500STetsuo Handa 				return false;
733c3ef1500STetsuo Handa 			break;
734c3ef1500STetsuo Handa 		case '+':
735c3ef1500STetsuo Handa 			if (!isdigit(c))
736c3ef1500STetsuo Handa 				return false;
737c3ef1500STetsuo Handa 			break;
738c3ef1500STetsuo Handa 		case 'x':
739c3ef1500STetsuo Handa 			if (!isxdigit(c))
740c3ef1500STetsuo Handa 				return false;
741c3ef1500STetsuo Handa 			break;
742c3ef1500STetsuo Handa 		case 'a':
74375093152STetsuo Handa 			if (!tomoyo_alphabet_char(c))
744c3ef1500STetsuo Handa 				return false;
745c3ef1500STetsuo Handa 			break;
746c3ef1500STetsuo Handa 		case '0':
747c3ef1500STetsuo Handa 		case '1':
748c3ef1500STetsuo Handa 		case '2':
749c3ef1500STetsuo Handa 		case '3':
75075093152STetsuo Handa 			if (c == '\\' && tomoyo_byte_range(filename + 1)
751c3ef1500STetsuo Handa 			    && strncmp(filename + 1, pattern, 3) == 0) {
752c3ef1500STetsuo Handa 				filename += 3;
753c3ef1500STetsuo Handa 				pattern += 2;
754c3ef1500STetsuo Handa 				break;
755c3ef1500STetsuo Handa 			}
756c3ef1500STetsuo Handa 			return false; /* Not matched. */
757c3ef1500STetsuo Handa 		case '*':
758c3ef1500STetsuo Handa 		case '@':
759c3ef1500STetsuo Handa 			for (i = 0; i <= filename_end - filename; i++) {
760c3ef1500STetsuo Handa 				if (tomoyo_file_matches_pattern2(
761c3ef1500STetsuo Handa 						    filename + i, filename_end,
762c3ef1500STetsuo Handa 						    pattern + 1, pattern_end))
763c3ef1500STetsuo Handa 					return true;
764c3ef1500STetsuo Handa 				c = filename[i];
765c3ef1500STetsuo Handa 				if (c == '.' && *pattern == '@')
766c3ef1500STetsuo Handa 					break;
767c3ef1500STetsuo Handa 				if (c != '\\')
768c3ef1500STetsuo Handa 					continue;
769c3ef1500STetsuo Handa 				if (filename[i + 1] == '\\')
770c3ef1500STetsuo Handa 					i++;
77175093152STetsuo Handa 				else if (tomoyo_byte_range(filename + i + 1))
772c3ef1500STetsuo Handa 					i += 3;
773c3ef1500STetsuo Handa 				else
774c3ef1500STetsuo Handa 					break; /* Bad pattern. */
775c3ef1500STetsuo Handa 			}
776c3ef1500STetsuo Handa 			return false; /* Not matched. */
777c3ef1500STetsuo Handa 		default:
778c3ef1500STetsuo Handa 			j = 0;
779c3ef1500STetsuo Handa 			c = *pattern;
780c3ef1500STetsuo Handa 			if (c == '$') {
781c3ef1500STetsuo Handa 				while (isdigit(filename[j]))
782c3ef1500STetsuo Handa 					j++;
783c3ef1500STetsuo Handa 			} else if (c == 'X') {
784c3ef1500STetsuo Handa 				while (isxdigit(filename[j]))
785c3ef1500STetsuo Handa 					j++;
786c3ef1500STetsuo Handa 			} else if (c == 'A') {
78775093152STetsuo Handa 				while (tomoyo_alphabet_char(filename[j]))
788c3ef1500STetsuo Handa 					j++;
789c3ef1500STetsuo Handa 			}
790c3ef1500STetsuo Handa 			for (i = 1; i <= j; i++) {
791c3ef1500STetsuo Handa 				if (tomoyo_file_matches_pattern2(
792c3ef1500STetsuo Handa 						    filename + i, filename_end,
793c3ef1500STetsuo Handa 						    pattern + 1, pattern_end))
794c3ef1500STetsuo Handa 					return true;
795c3ef1500STetsuo Handa 			}
796c3ef1500STetsuo Handa 			return false; /* Not matched or bad pattern. */
797c3ef1500STetsuo Handa 		}
798c3ef1500STetsuo Handa 		filename++;
799c3ef1500STetsuo Handa 		pattern++;
800c3ef1500STetsuo Handa 	}
801c3ef1500STetsuo Handa 	while (*pattern == '\\' &&
802c3ef1500STetsuo Handa 	       (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
803c3ef1500STetsuo Handa 		pattern += 2;
804c3ef1500STetsuo Handa 	return filename == filename_end && pattern == pattern_end;
805c3ef1500STetsuo Handa }
806c3ef1500STetsuo Handa 
807c3ef1500STetsuo Handa /**
808c3ef1500STetsuo Handa  * tomoyo_file_matches_pattern - Pattern matching without '/' character.
809c3ef1500STetsuo Handa  *
810c3ef1500STetsuo Handa  * @filename:     The start of string to check.
811c3ef1500STetsuo Handa  * @filename_end: The end of string to check.
812c3ef1500STetsuo Handa  * @pattern:      The start of pattern to compare.
813c3ef1500STetsuo Handa  * @pattern_end:  The end of pattern to compare.
814c3ef1500STetsuo Handa  *
815c3ef1500STetsuo Handa  * Returns true if @filename matches @pattern, false otherwise.
816c3ef1500STetsuo Handa  */
tomoyo_file_matches_pattern(const char * filename,const char * filename_end,const char * pattern,const char * pattern_end)817c3ef1500STetsuo Handa static bool tomoyo_file_matches_pattern(const char *filename,
818c3ef1500STetsuo Handa 					const char *filename_end,
819c3ef1500STetsuo Handa 					const char *pattern,
820c3ef1500STetsuo Handa 					const char *pattern_end)
821c3ef1500STetsuo Handa {
822c3ef1500STetsuo Handa 	const char *pattern_start = pattern;
823c3ef1500STetsuo Handa 	bool first = true;
824c3ef1500STetsuo Handa 	bool result;
825c3ef1500STetsuo Handa 
826c3ef1500STetsuo Handa 	while (pattern < pattern_end - 1) {
827c3ef1500STetsuo Handa 		/* Split at "\-" pattern. */
828c3ef1500STetsuo Handa 		if (*pattern++ != '\\' || *pattern++ != '-')
829c3ef1500STetsuo Handa 			continue;
830c3ef1500STetsuo Handa 		result = tomoyo_file_matches_pattern2(filename,
831c3ef1500STetsuo Handa 						      filename_end,
832c3ef1500STetsuo Handa 						      pattern_start,
833c3ef1500STetsuo Handa 						      pattern - 2);
834c3ef1500STetsuo Handa 		if (first)
835c3ef1500STetsuo Handa 			result = !result;
836c3ef1500STetsuo Handa 		if (result)
837c3ef1500STetsuo Handa 			return false;
838c3ef1500STetsuo Handa 		first = false;
839c3ef1500STetsuo Handa 		pattern_start = pattern;
840c3ef1500STetsuo Handa 	}
841c3ef1500STetsuo Handa 	result = tomoyo_file_matches_pattern2(filename, filename_end,
842c3ef1500STetsuo Handa 					      pattern_start, pattern_end);
843c3ef1500STetsuo Handa 	return first ? result : !result;
844c3ef1500STetsuo Handa }
845c3ef1500STetsuo Handa 
846c3ef1500STetsuo Handa /**
847c3ef1500STetsuo Handa  * tomoyo_path_matches_pattern2 - Do pathname pattern matching.
848c3ef1500STetsuo Handa  *
849c3ef1500STetsuo Handa  * @f: The start of string to check.
850c3ef1500STetsuo Handa  * @p: The start of pattern to compare.
851c3ef1500STetsuo Handa  *
852c3ef1500STetsuo Handa  * Returns true if @f matches @p, false otherwise.
853c3ef1500STetsuo Handa  */
tomoyo_path_matches_pattern2(const char * f,const char * p)854c3ef1500STetsuo Handa static bool tomoyo_path_matches_pattern2(const char *f, const char *p)
855c3ef1500STetsuo Handa {
856c3ef1500STetsuo Handa 	const char *f_delimiter;
857c3ef1500STetsuo Handa 	const char *p_delimiter;
858c3ef1500STetsuo Handa 
859c3ef1500STetsuo Handa 	while (*f && *p) {
860c3ef1500STetsuo Handa 		f_delimiter = strchr(f, '/');
861c3ef1500STetsuo Handa 		if (!f_delimiter)
862c3ef1500STetsuo Handa 			f_delimiter = f + strlen(f);
863c3ef1500STetsuo Handa 		p_delimiter = strchr(p, '/');
864c3ef1500STetsuo Handa 		if (!p_delimiter)
865c3ef1500STetsuo Handa 			p_delimiter = p + strlen(p);
866c3ef1500STetsuo Handa 		if (*p == '\\' && *(p + 1) == '{')
867c3ef1500STetsuo Handa 			goto recursive;
868c3ef1500STetsuo Handa 		if (!tomoyo_file_matches_pattern(f, f_delimiter, p,
869c3ef1500STetsuo Handa 						 p_delimiter))
870c3ef1500STetsuo Handa 			return false;
871c3ef1500STetsuo Handa 		f = f_delimiter;
872c3ef1500STetsuo Handa 		if (*f)
873c3ef1500STetsuo Handa 			f++;
874c3ef1500STetsuo Handa 		p = p_delimiter;
875c3ef1500STetsuo Handa 		if (*p)
876c3ef1500STetsuo Handa 			p++;
877c3ef1500STetsuo Handa 	}
878c3ef1500STetsuo Handa 	/* Ignore trailing "\*" and "\@" in @pattern. */
879c3ef1500STetsuo Handa 	while (*p == '\\' &&
880c3ef1500STetsuo Handa 	       (*(p + 1) == '*' || *(p + 1) == '@'))
881c3ef1500STetsuo Handa 		p += 2;
882c3ef1500STetsuo Handa 	return !*f && !*p;
883c3ef1500STetsuo Handa  recursive:
884c3ef1500STetsuo Handa 	/*
885c3ef1500STetsuo Handa 	 * The "\{" pattern is permitted only after '/' character.
886c3ef1500STetsuo Handa 	 * This guarantees that below "*(p - 1)" is safe.
887c3ef1500STetsuo Handa 	 * Also, the "\}" pattern is permitted only before '/' character
888c3ef1500STetsuo Handa 	 * so that "\{" + "\}" pair will not break the "\-" operator.
889c3ef1500STetsuo Handa 	 */
890c3ef1500STetsuo Handa 	if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
891c3ef1500STetsuo Handa 	    *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
892c3ef1500STetsuo Handa 		return false; /* Bad pattern. */
893c3ef1500STetsuo Handa 	do {
894c3ef1500STetsuo Handa 		/* Compare current component with pattern. */
895c3ef1500STetsuo Handa 		if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2,
896c3ef1500STetsuo Handa 						 p_delimiter - 2))
897c3ef1500STetsuo Handa 			break;
898c3ef1500STetsuo Handa 		/* Proceed to next component. */
899c3ef1500STetsuo Handa 		f = f_delimiter;
900c3ef1500STetsuo Handa 		if (!*f)
901c3ef1500STetsuo Handa 			break;
902c3ef1500STetsuo Handa 		f++;
903c3ef1500STetsuo Handa 		/* Continue comparison. */
904c3ef1500STetsuo Handa 		if (tomoyo_path_matches_pattern2(f, p_delimiter + 1))
905c3ef1500STetsuo Handa 			return true;
906c3ef1500STetsuo Handa 		f_delimiter = strchr(f, '/');
907c3ef1500STetsuo Handa 	} while (f_delimiter);
908c3ef1500STetsuo Handa 	return false; /* Not matched. */
909c3ef1500STetsuo Handa }
910c3ef1500STetsuo Handa 
911c3ef1500STetsuo Handa /**
912c3ef1500STetsuo Handa  * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
913c3ef1500STetsuo Handa  *
914c3ef1500STetsuo Handa  * @filename: The filename to check.
915c3ef1500STetsuo Handa  * @pattern:  The pattern to compare.
916c3ef1500STetsuo Handa  *
917c3ef1500STetsuo Handa  * Returns true if matches, false otherwise.
918c3ef1500STetsuo Handa  *
919c3ef1500STetsuo Handa  * The following patterns are available.
920c3ef1500STetsuo Handa  *   \\     \ itself.
921c3ef1500STetsuo Handa  *   \ooo   Octal representation of a byte.
922c3ef1500STetsuo Handa  *   \*     Zero or more repetitions of characters other than '/'.
923c3ef1500STetsuo Handa  *   \@     Zero or more repetitions of characters other than '/' or '.'.
924c3ef1500STetsuo Handa  *   \?     1 byte character other than '/'.
925c3ef1500STetsuo Handa  *   \$     One or more repetitions of decimal digits.
926c3ef1500STetsuo Handa  *   \+     1 decimal digit.
927c3ef1500STetsuo Handa  *   \X     One or more repetitions of hexadecimal digits.
928c3ef1500STetsuo Handa  *   \x     1 hexadecimal digit.
929c3ef1500STetsuo Handa  *   \A     One or more repetitions of alphabet characters.
930c3ef1500STetsuo Handa  *   \a     1 alphabet character.
931c3ef1500STetsuo Handa  *
932c3ef1500STetsuo Handa  *   \-     Subtraction operator.
933c3ef1500STetsuo Handa  *
934c3ef1500STetsuo Handa  *   /\{dir\}/   '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
935c3ef1500STetsuo Handa  *               /dir/dir/dir/ ).
936c3ef1500STetsuo Handa  */
tomoyo_path_matches_pattern(const struct tomoyo_path_info * filename,const struct tomoyo_path_info * pattern)937c3ef1500STetsuo Handa bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
938c3ef1500STetsuo Handa 				 const struct tomoyo_path_info *pattern)
939c3ef1500STetsuo Handa {
940c3ef1500STetsuo Handa 	const char *f = filename->name;
941c3ef1500STetsuo Handa 	const char *p = pattern->name;
942c3ef1500STetsuo Handa 	const int len = pattern->const_len;
943c3ef1500STetsuo Handa 
944c3ef1500STetsuo Handa 	/* If @pattern doesn't contain pattern, I can use strcmp(). */
945c3ef1500STetsuo Handa 	if (!pattern->is_patterned)
946c3ef1500STetsuo Handa 		return !tomoyo_pathcmp(filename, pattern);
947c3ef1500STetsuo Handa 	/* Don't compare directory and non-directory. */
948c3ef1500STetsuo Handa 	if (filename->is_dir != pattern->is_dir)
949c3ef1500STetsuo Handa 		return false;
950c3ef1500STetsuo Handa 	/* Compare the initial length without patterns. */
951c3ef1500STetsuo Handa 	if (strncmp(f, p, len))
952c3ef1500STetsuo Handa 		return false;
953c3ef1500STetsuo Handa 	f += len;
954c3ef1500STetsuo Handa 	p += len;
955c3ef1500STetsuo Handa 	return tomoyo_path_matches_pattern2(f, p);
956c3ef1500STetsuo Handa }
957c3ef1500STetsuo Handa 
958c3ef1500STetsuo Handa /**
959c3ef1500STetsuo Handa  * tomoyo_get_exe - Get tomoyo_realpath() of current process.
960c3ef1500STetsuo Handa  *
961c3ef1500STetsuo Handa  * Returns the tomoyo_realpath() of current process on success, NULL otherwise.
962c3ef1500STetsuo Handa  *
963c3ef1500STetsuo Handa  * This function uses kzalloc(), so the caller must call kfree()
964c3ef1500STetsuo Handa  * if this function didn't return NULL.
965c3ef1500STetsuo Handa  */
tomoyo_get_exe(void)966c3ef1500STetsuo Handa const char *tomoyo_get_exe(void)
967c3ef1500STetsuo Handa {
968d4144ea6SDavidlohr Bueso 	struct file *exe_file;
969d4144ea6SDavidlohr Bueso 	const char *cp;
970c3ef1500STetsuo Handa 	struct mm_struct *mm = current->mm;
971c3ef1500STetsuo Handa 
972c3ef1500STetsuo Handa 	if (!mm)
973c3ef1500STetsuo Handa 		return NULL;
974d4144ea6SDavidlohr Bueso 	exe_file = get_mm_exe_file(mm);
975d4144ea6SDavidlohr Bueso 	if (!exe_file)
976d4144ea6SDavidlohr Bueso 		return NULL;
977d4144ea6SDavidlohr Bueso 
978d4144ea6SDavidlohr Bueso 	cp = tomoyo_realpath_from_path(&exe_file->f_path);
979d4144ea6SDavidlohr Bueso 	fput(exe_file);
980c3ef1500STetsuo Handa 	return cp;
981c3ef1500STetsuo Handa }
982c3ef1500STetsuo Handa 
983c3ef1500STetsuo Handa /**
98457c2590fSTetsuo Handa  * tomoyo_get_mode - Get MAC mode.
98557c2590fSTetsuo Handa  *
986bd03a3e4STetsuo Handa  * @ns:      Pointer to "struct tomoyo_policy_namespace".
98757c2590fSTetsuo Handa  * @profile: Profile number.
98857c2590fSTetsuo Handa  * @index:   Index number of functionality.
98957c2590fSTetsuo Handa  *
99057c2590fSTetsuo Handa  * Returns mode.
99157c2590fSTetsuo Handa  */
tomoyo_get_mode(const struct tomoyo_policy_namespace * ns,const u8 profile,const u8 index)992bd03a3e4STetsuo Handa int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
993bd03a3e4STetsuo Handa 		    const u8 index)
99457c2590fSTetsuo Handa {
99557c2590fSTetsuo Handa 	u8 mode;
996d58e0da8STetsuo Handa 	struct tomoyo_profile *p;
997d58e0da8STetsuo Handa 
99857c2590fSTetsuo Handa 	if (!tomoyo_policy_loaded)
99957c2590fSTetsuo Handa 		return TOMOYO_CONFIG_DISABLED;
1000d58e0da8STetsuo Handa 	p = tomoyo_profile(ns, profile);
1001d58e0da8STetsuo Handa 	mode = p->config[index];
100257c2590fSTetsuo Handa 	if (mode == TOMOYO_CONFIG_USE_DEFAULT)
1003d58e0da8STetsuo Handa 		mode = p->config[tomoyo_index2category[index]
1004d58e0da8STetsuo Handa 				 + TOMOYO_MAX_MAC_INDEX];
100557c2590fSTetsuo Handa 	if (mode == TOMOYO_CONFIG_USE_DEFAULT)
1006d58e0da8STetsuo Handa 		mode = p->default_config;
100757c2590fSTetsuo Handa 	return mode & 3;
100857c2590fSTetsuo Handa }
100957c2590fSTetsuo Handa 
101057c2590fSTetsuo Handa /**
1011c3ef1500STetsuo Handa  * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members.
1012c3ef1500STetsuo Handa  *
1013c3ef1500STetsuo Handa  * @r:      Pointer to "struct tomoyo_request_info" to initialize.
1014c3ef1500STetsuo Handa  * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain().
101557c2590fSTetsuo Handa  * @index:  Index number of functionality.
1016c3ef1500STetsuo Handa  *
1017c3ef1500STetsuo Handa  * Returns mode.
1018c3ef1500STetsuo Handa  */
tomoyo_init_request_info(struct tomoyo_request_info * r,struct tomoyo_domain_info * domain,const u8 index)1019c3ef1500STetsuo Handa int tomoyo_init_request_info(struct tomoyo_request_info *r,
102057c2590fSTetsuo Handa 			     struct tomoyo_domain_info *domain, const u8 index)
1021c3ef1500STetsuo Handa {
102257c2590fSTetsuo Handa 	u8 profile;
1023cdcf6723STetsuo Handa 
1024c3ef1500STetsuo Handa 	memset(r, 0, sizeof(*r));
1025c3ef1500STetsuo Handa 	if (!domain)
1026c3ef1500STetsuo Handa 		domain = tomoyo_domain();
1027c3ef1500STetsuo Handa 	r->domain = domain;
102857c2590fSTetsuo Handa 	profile = domain->profile;
102957c2590fSTetsuo Handa 	r->profile = profile;
103057c2590fSTetsuo Handa 	r->type = index;
1031bd03a3e4STetsuo Handa 	r->mode = tomoyo_get_mode(domain->ns, profile, index);
1032c3ef1500STetsuo Handa 	return r->mode;
1033c3ef1500STetsuo Handa }
1034c3ef1500STetsuo Handa 
1035c3ef1500STetsuo Handa /**
1036c3ef1500STetsuo Handa  * tomoyo_domain_quota_is_ok - Check for domain's quota.
1037c3ef1500STetsuo Handa  *
1038c3ef1500STetsuo Handa  * @r: Pointer to "struct tomoyo_request_info".
1039c3ef1500STetsuo Handa  *
1040c3ef1500STetsuo Handa  * Returns true if the domain is not exceeded quota, false otherwise.
1041c3ef1500STetsuo Handa  *
1042c3ef1500STetsuo Handa  * Caller holds tomoyo_read_lock().
1043c3ef1500STetsuo Handa  */
tomoyo_domain_quota_is_ok(struct tomoyo_request_info * r)1044c3ef1500STetsuo Handa bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
1045c3ef1500STetsuo Handa {
1046c3ef1500STetsuo Handa 	unsigned int count = 0;
1047c3ef1500STetsuo Handa 	struct tomoyo_domain_info *domain = r->domain;
1048c3ef1500STetsuo Handa 	struct tomoyo_acl_info *ptr;
1049c3ef1500STetsuo Handa 
1050c3ef1500STetsuo Handa 	if (r->mode != TOMOYO_CONFIG_LEARNING)
1051c3ef1500STetsuo Handa 		return false;
1052c3ef1500STetsuo Handa 	if (!domain)
1053c3ef1500STetsuo Handa 		return true;
10543fe6a63bSDmitry Vyukov 	if (READ_ONCE(domain->flags[TOMOYO_DIF_QUOTA_WARNED]))
10553fe6a63bSDmitry Vyukov 		return false;
10566bd5ce60STetsuo Handa 	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list,
10576bd5ce60STetsuo Handa 				srcu_read_lock_held(&tomoyo_ss)) {
10587c75964fSTetsuo Handa 		u16 perm;
1059cdcf6723STetsuo Handa 
10607e3d199aSTetsuo Handa 		if (ptr->is_deleted)
1061237ab459STetsuo Handa 			continue;
10625797e861STetsuo Handa 		/*
10635797e861STetsuo Handa 		 * Reading perm bitmap might race with tomoyo_merge_*() because
10645797e861STetsuo Handa 		 * caller does not hold tomoyo_policy_lock mutex. But exceeding
10655797e861STetsuo Handa 		 * max_learning_entry parameter by a few entries does not harm.
10665797e861STetsuo Handa 		 */
1067c3ef1500STetsuo Handa 		switch (ptr->type) {
1068c3ef1500STetsuo Handa 		case TOMOYO_TYPE_PATH_ACL:
1069*80176f65STetsuo Handa 			perm = data_race(container_of(ptr, struct tomoyo_path_acl, head)->perm);
1070c3ef1500STetsuo Handa 			break;
1071c3ef1500STetsuo Handa 		case TOMOYO_TYPE_PATH2_ACL:
1072*80176f65STetsuo Handa 			perm = data_race(container_of(ptr, struct tomoyo_path2_acl, head)->perm);
1073c3ef1500STetsuo Handa 			break;
1074c3ef1500STetsuo Handa 		case TOMOYO_TYPE_PATH_NUMBER_ACL:
1075*80176f65STetsuo Handa 			perm = data_race(container_of(ptr, struct tomoyo_path_number_acl, head)
10765797e861STetsuo Handa 				  ->perm);
1077c3ef1500STetsuo Handa 			break;
107875093152STetsuo Handa 		case TOMOYO_TYPE_MKDEV_ACL:
1079*80176f65STetsuo Handa 			perm = data_race(container_of(ptr, struct tomoyo_mkdev_acl, head)->perm);
1080c3ef1500STetsuo Handa 			break;
1081545a7260STetsuo Handa 		case TOMOYO_TYPE_INET_ACL:
1082*80176f65STetsuo Handa 			perm = data_race(container_of(ptr, struct tomoyo_inet_acl, head)->perm);
1083545a7260STetsuo Handa 			break;
1084545a7260STetsuo Handa 		case TOMOYO_TYPE_UNIX_ACL:
1085*80176f65STetsuo Handa 			perm = data_race(container_of(ptr, struct tomoyo_unix_acl, head)->perm);
1086545a7260STetsuo Handa 			break;
1087545a7260STetsuo Handa 		case TOMOYO_TYPE_MANUAL_TASK_ACL:
1088545a7260STetsuo Handa 			perm = 0;
1089545a7260STetsuo Handa 			break;
1090237ab459STetsuo Handa 		default:
10917c75964fSTetsuo Handa 			perm = 1;
1092c3ef1500STetsuo Handa 		}
1093*80176f65STetsuo Handa 		count += hweight16(perm);
1094c3ef1500STetsuo Handa 	}
1095bd03a3e4STetsuo Handa 	if (count < tomoyo_profile(domain->ns, domain->profile)->
1096d5ca1725STetsuo Handa 	    pref[TOMOYO_PREF_MAX_LEARNING_ENTRY])
1097c3ef1500STetsuo Handa 		return true;
10983fe6a63bSDmitry Vyukov 	WRITE_ONCE(domain->flags[TOMOYO_DIF_QUOTA_WARNED], true);
10992c47ab93STetsuo Handa 	/* r->granted = false; */
11002c47ab93STetsuo Handa 	tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]);
11014ad98ac4STetsuo Handa #ifndef CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING
1102cdcf6723STetsuo Handa 	pr_warn("WARNING: Domain '%s' has too many ACLs to hold. Stopped learning mode.\n",
1103cdcf6723STetsuo Handa 		domain->domainname->name);
11044ad98ac4STetsuo Handa #endif
1105c3ef1500STetsuo Handa 	return false;
1106c3ef1500STetsuo Handa }
1107