18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * security/tomoyo/util.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2005-2011  NTT DATA CORPORATION
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/slab.h>
98c2ecf20Sopenharmony_ci#include <linux/rculist.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "common.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/* Lock for protecting policy. */
148c2ecf20Sopenharmony_ciDEFINE_MUTEX(tomoyo_policy_lock);
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/* Has /sbin/init started? */
178c2ecf20Sopenharmony_cibool tomoyo_policy_loaded;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * Mapping table from "enum tomoyo_mac_index" to
218c2ecf20Sopenharmony_ci * "enum tomoyo_mac_category_index".
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ciconst u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = {
248c2ecf20Sopenharmony_ci	/* CONFIG::file group */
258c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_EXECUTE]    = TOMOYO_MAC_CATEGORY_FILE,
268c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_OPEN]       = TOMOYO_MAC_CATEGORY_FILE,
278c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_CREATE]     = TOMOYO_MAC_CATEGORY_FILE,
288c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_UNLINK]     = TOMOYO_MAC_CATEGORY_FILE,
298c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_GETATTR]    = TOMOYO_MAC_CATEGORY_FILE,
308c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_MKDIR]      = TOMOYO_MAC_CATEGORY_FILE,
318c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_RMDIR]      = TOMOYO_MAC_CATEGORY_FILE,
328c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_MKFIFO]     = TOMOYO_MAC_CATEGORY_FILE,
338c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_MKSOCK]     = TOMOYO_MAC_CATEGORY_FILE,
348c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_TRUNCATE]   = TOMOYO_MAC_CATEGORY_FILE,
358c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_SYMLINK]    = TOMOYO_MAC_CATEGORY_FILE,
368c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_MKBLOCK]    = TOMOYO_MAC_CATEGORY_FILE,
378c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_MKCHAR]     = TOMOYO_MAC_CATEGORY_FILE,
388c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_LINK]       = TOMOYO_MAC_CATEGORY_FILE,
398c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_RENAME]     = TOMOYO_MAC_CATEGORY_FILE,
408c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_CHMOD]      = TOMOYO_MAC_CATEGORY_FILE,
418c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_CHOWN]      = TOMOYO_MAC_CATEGORY_FILE,
428c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_CHGRP]      = TOMOYO_MAC_CATEGORY_FILE,
438c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_IOCTL]      = TOMOYO_MAC_CATEGORY_FILE,
448c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_CHROOT]     = TOMOYO_MAC_CATEGORY_FILE,
458c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_MOUNT]      = TOMOYO_MAC_CATEGORY_FILE,
468c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_UMOUNT]     = TOMOYO_MAC_CATEGORY_FILE,
478c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE,
488c2ecf20Sopenharmony_ci	/* CONFIG::network group */
498c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_STREAM_BIND]       =
508c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
518c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN]     =
528c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
538c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT]    =
548c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
558c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_DGRAM_BIND]        =
568c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
578c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_DGRAM_SEND]        =
588c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
598c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_RAW_BIND]          =
608c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
618c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_RAW_SEND]          =
628c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
638c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND]       =
648c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
658c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN]     =
668c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
678c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT]    =
688c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
698c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND]        =
708c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
718c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND]        =
728c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
738c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND]    =
748c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
758c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN]  =
768c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
778c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] =
788c2ecf20Sopenharmony_ci	TOMOYO_MAC_CATEGORY_NETWORK,
798c2ecf20Sopenharmony_ci	/* CONFIG::misc group */
808c2ecf20Sopenharmony_ci	[TOMOYO_MAC_ENVIRON]         = TOMOYO_MAC_CATEGORY_MISC,
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/**
848c2ecf20Sopenharmony_ci * tomoyo_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss.
858c2ecf20Sopenharmony_ci *
868c2ecf20Sopenharmony_ci * @time:  Seconds since 1970/01/01 00:00:00.
878c2ecf20Sopenharmony_ci * @stamp: Pointer to "struct tomoyo_time".
888c2ecf20Sopenharmony_ci *
898c2ecf20Sopenharmony_ci * Returns nothing.
908c2ecf20Sopenharmony_ci */
918c2ecf20Sopenharmony_civoid tomoyo_convert_time(time64_t time64, struct tomoyo_time *stamp)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct tm tm;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	time64_to_tm(time64, 0, &tm);
968c2ecf20Sopenharmony_ci	stamp->sec = tm.tm_sec;
978c2ecf20Sopenharmony_ci	stamp->min = tm.tm_min;
988c2ecf20Sopenharmony_ci	stamp->hour = tm.tm_hour;
998c2ecf20Sopenharmony_ci	stamp->day = tm.tm_mday;
1008c2ecf20Sopenharmony_ci	stamp->month = tm.tm_mon + 1;
1018c2ecf20Sopenharmony_ci	stamp->year = tm.tm_year + 1900;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/**
1058c2ecf20Sopenharmony_ci * tomoyo_permstr - Find permission keywords.
1068c2ecf20Sopenharmony_ci *
1078c2ecf20Sopenharmony_ci * @string: String representation for permissions in foo/bar/buz format.
1088c2ecf20Sopenharmony_ci * @keyword: Keyword to find from @string/
1098c2ecf20Sopenharmony_ci *
1108c2ecf20Sopenharmony_ci * Returns true if @keyword was found in @string, false otherwise.
1118c2ecf20Sopenharmony_ci *
1128c2ecf20Sopenharmony_ci * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2.
1138c2ecf20Sopenharmony_ci */
1148c2ecf20Sopenharmony_cibool tomoyo_permstr(const char *string, const char *keyword)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	const char *cp = strstr(string, keyword);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	if (cp)
1198c2ecf20Sopenharmony_ci		return cp == string || *(cp - 1) == '/';
1208c2ecf20Sopenharmony_ci	return false;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci/**
1248c2ecf20Sopenharmony_ci * tomoyo_read_token - Read a word from a line.
1258c2ecf20Sopenharmony_ci *
1268c2ecf20Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param".
1278c2ecf20Sopenharmony_ci *
1288c2ecf20Sopenharmony_ci * Returns a word on success, "" otherwise.
1298c2ecf20Sopenharmony_ci *
1308c2ecf20Sopenharmony_ci * To allow the caller to skip NULL check, this function returns "" rather than
1318c2ecf20Sopenharmony_ci * NULL if there is no more words to read.
1328c2ecf20Sopenharmony_ci */
1338c2ecf20Sopenharmony_cichar *tomoyo_read_token(struct tomoyo_acl_param *param)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	char *pos = param->data;
1368c2ecf20Sopenharmony_ci	char *del = strchr(pos, ' ');
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	if (del)
1398c2ecf20Sopenharmony_ci		*del++ = '\0';
1408c2ecf20Sopenharmony_ci	else
1418c2ecf20Sopenharmony_ci		del = pos + strlen(pos);
1428c2ecf20Sopenharmony_ci	param->data = del;
1438c2ecf20Sopenharmony_ci	return pos;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic bool tomoyo_correct_path2(const char *filename, const size_t len);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci/**
1498c2ecf20Sopenharmony_ci * tomoyo_get_domainname - Read a domainname from a line.
1508c2ecf20Sopenharmony_ci *
1518c2ecf20Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param".
1528c2ecf20Sopenharmony_ci *
1538c2ecf20Sopenharmony_ci * Returns a domainname on success, NULL otherwise.
1548c2ecf20Sopenharmony_ci */
1558c2ecf20Sopenharmony_ciconst struct tomoyo_path_info *tomoyo_get_domainname
1568c2ecf20Sopenharmony_ci(struct tomoyo_acl_param *param)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	char *start = param->data;
1598c2ecf20Sopenharmony_ci	char *pos = start;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	while (*pos) {
1628c2ecf20Sopenharmony_ci		if (*pos++ != ' ' ||
1638c2ecf20Sopenharmony_ci		    tomoyo_correct_path2(pos, strchrnul(pos, ' ') - pos))
1648c2ecf20Sopenharmony_ci			continue;
1658c2ecf20Sopenharmony_ci		*(pos - 1) = '\0';
1668c2ecf20Sopenharmony_ci		break;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci	param->data = pos;
1698c2ecf20Sopenharmony_ci	if (tomoyo_correct_domain(start))
1708c2ecf20Sopenharmony_ci		return tomoyo_get_name(start);
1718c2ecf20Sopenharmony_ci	return NULL;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci/**
1758c2ecf20Sopenharmony_ci * tomoyo_parse_ulong - Parse an "unsigned long" value.
1768c2ecf20Sopenharmony_ci *
1778c2ecf20Sopenharmony_ci * @result: Pointer to "unsigned long".
1788c2ecf20Sopenharmony_ci * @str:    Pointer to string to parse.
1798c2ecf20Sopenharmony_ci *
1808c2ecf20Sopenharmony_ci * Returns one of values in "enum tomoyo_value_type".
1818c2ecf20Sopenharmony_ci *
1828c2ecf20Sopenharmony_ci * The @src is updated to point the first character after the value
1838c2ecf20Sopenharmony_ci * on success.
1848c2ecf20Sopenharmony_ci */
1858c2ecf20Sopenharmony_ciu8 tomoyo_parse_ulong(unsigned long *result, char **str)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	const char *cp = *str;
1888c2ecf20Sopenharmony_ci	char *ep;
1898c2ecf20Sopenharmony_ci	int base = 10;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	if (*cp == '0') {
1928c2ecf20Sopenharmony_ci		char c = *(cp + 1);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		if (c == 'x' || c == 'X') {
1958c2ecf20Sopenharmony_ci			base = 16;
1968c2ecf20Sopenharmony_ci			cp += 2;
1978c2ecf20Sopenharmony_ci		} else if (c >= '0' && c <= '7') {
1988c2ecf20Sopenharmony_ci			base = 8;
1998c2ecf20Sopenharmony_ci			cp++;
2008c2ecf20Sopenharmony_ci		}
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci	*result = simple_strtoul(cp, &ep, base);
2038c2ecf20Sopenharmony_ci	if (cp == ep)
2048c2ecf20Sopenharmony_ci		return TOMOYO_VALUE_TYPE_INVALID;
2058c2ecf20Sopenharmony_ci	*str = ep;
2068c2ecf20Sopenharmony_ci	switch (base) {
2078c2ecf20Sopenharmony_ci	case 16:
2088c2ecf20Sopenharmony_ci		return TOMOYO_VALUE_TYPE_HEXADECIMAL;
2098c2ecf20Sopenharmony_ci	case 8:
2108c2ecf20Sopenharmony_ci		return TOMOYO_VALUE_TYPE_OCTAL;
2118c2ecf20Sopenharmony_ci	default:
2128c2ecf20Sopenharmony_ci		return TOMOYO_VALUE_TYPE_DECIMAL;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci/**
2178c2ecf20Sopenharmony_ci * tomoyo_print_ulong - Print an "unsigned long" value.
2188c2ecf20Sopenharmony_ci *
2198c2ecf20Sopenharmony_ci * @buffer:     Pointer to buffer.
2208c2ecf20Sopenharmony_ci * @buffer_len: Size of @buffer.
2218c2ecf20Sopenharmony_ci * @value:      An "unsigned long" value.
2228c2ecf20Sopenharmony_ci * @type:       Type of @value.
2238c2ecf20Sopenharmony_ci *
2248c2ecf20Sopenharmony_ci * Returns nothing.
2258c2ecf20Sopenharmony_ci */
2268c2ecf20Sopenharmony_civoid tomoyo_print_ulong(char *buffer, const int buffer_len,
2278c2ecf20Sopenharmony_ci			const unsigned long value, const u8 type)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	if (type == TOMOYO_VALUE_TYPE_DECIMAL)
2308c2ecf20Sopenharmony_ci		snprintf(buffer, buffer_len, "%lu", value);
2318c2ecf20Sopenharmony_ci	else if (type == TOMOYO_VALUE_TYPE_OCTAL)
2328c2ecf20Sopenharmony_ci		snprintf(buffer, buffer_len, "0%lo", value);
2338c2ecf20Sopenharmony_ci	else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL)
2348c2ecf20Sopenharmony_ci		snprintf(buffer, buffer_len, "0x%lX", value);
2358c2ecf20Sopenharmony_ci	else
2368c2ecf20Sopenharmony_ci		snprintf(buffer, buffer_len, "type(%u)", type);
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci/**
2408c2ecf20Sopenharmony_ci * tomoyo_parse_name_union - Parse a tomoyo_name_union.
2418c2ecf20Sopenharmony_ci *
2428c2ecf20Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param".
2438c2ecf20Sopenharmony_ci * @ptr:   Pointer to "struct tomoyo_name_union".
2448c2ecf20Sopenharmony_ci *
2458c2ecf20Sopenharmony_ci * Returns true on success, false otherwise.
2468c2ecf20Sopenharmony_ci */
2478c2ecf20Sopenharmony_cibool tomoyo_parse_name_union(struct tomoyo_acl_param *param,
2488c2ecf20Sopenharmony_ci			     struct tomoyo_name_union *ptr)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	char *filename;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	if (param->data[0] == '@') {
2538c2ecf20Sopenharmony_ci		param->data++;
2548c2ecf20Sopenharmony_ci		ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP);
2558c2ecf20Sopenharmony_ci		return ptr->group != NULL;
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci	filename = tomoyo_read_token(param);
2588c2ecf20Sopenharmony_ci	if (!tomoyo_correct_word(filename))
2598c2ecf20Sopenharmony_ci		return false;
2608c2ecf20Sopenharmony_ci	ptr->filename = tomoyo_get_name(filename);
2618c2ecf20Sopenharmony_ci	return ptr->filename != NULL;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci/**
2658c2ecf20Sopenharmony_ci * tomoyo_parse_number_union - Parse a tomoyo_number_union.
2668c2ecf20Sopenharmony_ci *
2678c2ecf20Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param".
2688c2ecf20Sopenharmony_ci * @ptr:   Pointer to "struct tomoyo_number_union".
2698c2ecf20Sopenharmony_ci *
2708c2ecf20Sopenharmony_ci * Returns true on success, false otherwise.
2718c2ecf20Sopenharmony_ci */
2728c2ecf20Sopenharmony_cibool tomoyo_parse_number_union(struct tomoyo_acl_param *param,
2738c2ecf20Sopenharmony_ci			       struct tomoyo_number_union *ptr)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	char *data;
2768c2ecf20Sopenharmony_ci	u8 type;
2778c2ecf20Sopenharmony_ci	unsigned long v;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	memset(ptr, 0, sizeof(*ptr));
2808c2ecf20Sopenharmony_ci	if (param->data[0] == '@') {
2818c2ecf20Sopenharmony_ci		param->data++;
2828c2ecf20Sopenharmony_ci		ptr->group = tomoyo_get_group(param, TOMOYO_NUMBER_GROUP);
2838c2ecf20Sopenharmony_ci		return ptr->group != NULL;
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci	data = tomoyo_read_token(param);
2868c2ecf20Sopenharmony_ci	type = tomoyo_parse_ulong(&v, &data);
2878c2ecf20Sopenharmony_ci	if (type == TOMOYO_VALUE_TYPE_INVALID)
2888c2ecf20Sopenharmony_ci		return false;
2898c2ecf20Sopenharmony_ci	ptr->values[0] = v;
2908c2ecf20Sopenharmony_ci	ptr->value_type[0] = type;
2918c2ecf20Sopenharmony_ci	if (!*data) {
2928c2ecf20Sopenharmony_ci		ptr->values[1] = v;
2938c2ecf20Sopenharmony_ci		ptr->value_type[1] = type;
2948c2ecf20Sopenharmony_ci		return true;
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci	if (*data++ != '-')
2978c2ecf20Sopenharmony_ci		return false;
2988c2ecf20Sopenharmony_ci	type = tomoyo_parse_ulong(&v, &data);
2998c2ecf20Sopenharmony_ci	if (type == TOMOYO_VALUE_TYPE_INVALID || *data || ptr->values[0] > v)
3008c2ecf20Sopenharmony_ci		return false;
3018c2ecf20Sopenharmony_ci	ptr->values[1] = v;
3028c2ecf20Sopenharmony_ci	ptr->value_type[1] = type;
3038c2ecf20Sopenharmony_ci	return true;
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci/**
3078c2ecf20Sopenharmony_ci * tomoyo_byte_range - Check whether the string is a \ooo style octal value.
3088c2ecf20Sopenharmony_ci *
3098c2ecf20Sopenharmony_ci * @str: Pointer to the string.
3108c2ecf20Sopenharmony_ci *
3118c2ecf20Sopenharmony_ci * Returns true if @str is a \ooo style octal value, false otherwise.
3128c2ecf20Sopenharmony_ci *
3138c2ecf20Sopenharmony_ci * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
3148c2ecf20Sopenharmony_ci * This function verifies that \ooo is in valid range.
3158c2ecf20Sopenharmony_ci */
3168c2ecf20Sopenharmony_cistatic inline bool tomoyo_byte_range(const char *str)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	return *str >= '0' && *str++ <= '3' &&
3198c2ecf20Sopenharmony_ci		*str >= '0' && *str++ <= '7' &&
3208c2ecf20Sopenharmony_ci		*str >= '0' && *str <= '7';
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci/**
3248c2ecf20Sopenharmony_ci * tomoyo_alphabet_char - Check whether the character is an alphabet.
3258c2ecf20Sopenharmony_ci *
3268c2ecf20Sopenharmony_ci * @c: The character to check.
3278c2ecf20Sopenharmony_ci *
3288c2ecf20Sopenharmony_ci * Returns true if @c is an alphabet character, false otherwise.
3298c2ecf20Sopenharmony_ci */
3308c2ecf20Sopenharmony_cistatic inline bool tomoyo_alphabet_char(const char c)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci/**
3368c2ecf20Sopenharmony_ci * tomoyo_make_byte - Make byte value from three octal characters.
3378c2ecf20Sopenharmony_ci *
3388c2ecf20Sopenharmony_ci * @c1: The first character.
3398c2ecf20Sopenharmony_ci * @c2: The second character.
3408c2ecf20Sopenharmony_ci * @c3: The third character.
3418c2ecf20Sopenharmony_ci *
3428c2ecf20Sopenharmony_ci * Returns byte value.
3438c2ecf20Sopenharmony_ci */
3448c2ecf20Sopenharmony_cistatic inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci/**
3508c2ecf20Sopenharmony_ci * tomoyo_valid - Check whether the character is a valid char.
3518c2ecf20Sopenharmony_ci *
3528c2ecf20Sopenharmony_ci * @c: The character to check.
3538c2ecf20Sopenharmony_ci *
3548c2ecf20Sopenharmony_ci * Returns true if @c is a valid character, false otherwise.
3558c2ecf20Sopenharmony_ci */
3568c2ecf20Sopenharmony_cistatic inline bool tomoyo_valid(const unsigned char c)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	return c > ' ' && c < 127;
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci/**
3628c2ecf20Sopenharmony_ci * tomoyo_invalid - Check whether the character is an invalid char.
3638c2ecf20Sopenharmony_ci *
3648c2ecf20Sopenharmony_ci * @c: The character to check.
3658c2ecf20Sopenharmony_ci *
3668c2ecf20Sopenharmony_ci * Returns true if @c is an invalid character, false otherwise.
3678c2ecf20Sopenharmony_ci */
3688c2ecf20Sopenharmony_cistatic inline bool tomoyo_invalid(const unsigned char c)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	return c && (c <= ' ' || c >= 127);
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci/**
3748c2ecf20Sopenharmony_ci * tomoyo_str_starts - Check whether the given string starts with the given keyword.
3758c2ecf20Sopenharmony_ci *
3768c2ecf20Sopenharmony_ci * @src:  Pointer to pointer to the string.
3778c2ecf20Sopenharmony_ci * @find: Pointer to the keyword.
3788c2ecf20Sopenharmony_ci *
3798c2ecf20Sopenharmony_ci * Returns true if @src starts with @find, false otherwise.
3808c2ecf20Sopenharmony_ci *
3818c2ecf20Sopenharmony_ci * The @src is updated to point the first character after the @find
3828c2ecf20Sopenharmony_ci * if @src starts with @find.
3838c2ecf20Sopenharmony_ci */
3848c2ecf20Sopenharmony_cibool tomoyo_str_starts(char **src, const char *find)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	const int len = strlen(find);
3878c2ecf20Sopenharmony_ci	char *tmp = *src;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (strncmp(tmp, find, len))
3908c2ecf20Sopenharmony_ci		return false;
3918c2ecf20Sopenharmony_ci	tmp += len;
3928c2ecf20Sopenharmony_ci	*src = tmp;
3938c2ecf20Sopenharmony_ci	return true;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci/**
3978c2ecf20Sopenharmony_ci * tomoyo_normalize_line - Format string.
3988c2ecf20Sopenharmony_ci *
3998c2ecf20Sopenharmony_ci * @buffer: The line to normalize.
4008c2ecf20Sopenharmony_ci *
4018c2ecf20Sopenharmony_ci * Leading and trailing whitespaces are removed.
4028c2ecf20Sopenharmony_ci * Multiple whitespaces are packed into single space.
4038c2ecf20Sopenharmony_ci *
4048c2ecf20Sopenharmony_ci * Returns nothing.
4058c2ecf20Sopenharmony_ci */
4068c2ecf20Sopenharmony_civoid tomoyo_normalize_line(unsigned char *buffer)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	unsigned char *sp = buffer;
4098c2ecf20Sopenharmony_ci	unsigned char *dp = buffer;
4108c2ecf20Sopenharmony_ci	bool first = true;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	while (tomoyo_invalid(*sp))
4138c2ecf20Sopenharmony_ci		sp++;
4148c2ecf20Sopenharmony_ci	while (*sp) {
4158c2ecf20Sopenharmony_ci		if (!first)
4168c2ecf20Sopenharmony_ci			*dp++ = ' ';
4178c2ecf20Sopenharmony_ci		first = false;
4188c2ecf20Sopenharmony_ci		while (tomoyo_valid(*sp))
4198c2ecf20Sopenharmony_ci			*dp++ = *sp++;
4208c2ecf20Sopenharmony_ci		while (tomoyo_invalid(*sp))
4218c2ecf20Sopenharmony_ci			sp++;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci	*dp = '\0';
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci/**
4278c2ecf20Sopenharmony_ci * tomoyo_correct_word2 - Validate a string.
4288c2ecf20Sopenharmony_ci *
4298c2ecf20Sopenharmony_ci * @string: The string to check. Maybe non-'\0'-terminated.
4308c2ecf20Sopenharmony_ci * @len:    Length of @string.
4318c2ecf20Sopenharmony_ci *
4328c2ecf20Sopenharmony_ci * Check whether the given string follows the naming rules.
4338c2ecf20Sopenharmony_ci * Returns true if @string follows the naming rules, false otherwise.
4348c2ecf20Sopenharmony_ci */
4358c2ecf20Sopenharmony_cistatic bool tomoyo_correct_word2(const char *string, size_t len)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	const char *const start = string;
4388c2ecf20Sopenharmony_ci	bool in_repetition = false;
4398c2ecf20Sopenharmony_ci	unsigned char c;
4408c2ecf20Sopenharmony_ci	unsigned char d;
4418c2ecf20Sopenharmony_ci	unsigned char e;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	if (!len)
4448c2ecf20Sopenharmony_ci		goto out;
4458c2ecf20Sopenharmony_ci	while (len--) {
4468c2ecf20Sopenharmony_ci		c = *string++;
4478c2ecf20Sopenharmony_ci		if (c == '\\') {
4488c2ecf20Sopenharmony_ci			if (!len--)
4498c2ecf20Sopenharmony_ci				goto out;
4508c2ecf20Sopenharmony_ci			c = *string++;
4518c2ecf20Sopenharmony_ci			switch (c) {
4528c2ecf20Sopenharmony_ci			case '\\':  /* "\\" */
4538c2ecf20Sopenharmony_ci				continue;
4548c2ecf20Sopenharmony_ci			case '$':   /* "\$" */
4558c2ecf20Sopenharmony_ci			case '+':   /* "\+" */
4568c2ecf20Sopenharmony_ci			case '?':   /* "\?" */
4578c2ecf20Sopenharmony_ci			case '*':   /* "\*" */
4588c2ecf20Sopenharmony_ci			case '@':   /* "\@" */
4598c2ecf20Sopenharmony_ci			case 'x':   /* "\x" */
4608c2ecf20Sopenharmony_ci			case 'X':   /* "\X" */
4618c2ecf20Sopenharmony_ci			case 'a':   /* "\a" */
4628c2ecf20Sopenharmony_ci			case 'A':   /* "\A" */
4638c2ecf20Sopenharmony_ci			case '-':   /* "\-" */
4648c2ecf20Sopenharmony_ci				continue;
4658c2ecf20Sopenharmony_ci			case '{':   /* "/\{" */
4668c2ecf20Sopenharmony_ci				if (string - 3 < start || *(string - 3) != '/')
4678c2ecf20Sopenharmony_ci					break;
4688c2ecf20Sopenharmony_ci				in_repetition = true;
4698c2ecf20Sopenharmony_ci				continue;
4708c2ecf20Sopenharmony_ci			case '}':   /* "\}/" */
4718c2ecf20Sopenharmony_ci				if (*string != '/')
4728c2ecf20Sopenharmony_ci					break;
4738c2ecf20Sopenharmony_ci				if (!in_repetition)
4748c2ecf20Sopenharmony_ci					break;
4758c2ecf20Sopenharmony_ci				in_repetition = false;
4768c2ecf20Sopenharmony_ci				continue;
4778c2ecf20Sopenharmony_ci			case '0':   /* "\ooo" */
4788c2ecf20Sopenharmony_ci			case '1':
4798c2ecf20Sopenharmony_ci			case '2':
4808c2ecf20Sopenharmony_ci			case '3':
4818c2ecf20Sopenharmony_ci				if (!len-- || !len--)
4828c2ecf20Sopenharmony_ci					break;
4838c2ecf20Sopenharmony_ci				d = *string++;
4848c2ecf20Sopenharmony_ci				e = *string++;
4858c2ecf20Sopenharmony_ci				if (d < '0' || d > '7' || e < '0' || e > '7')
4868c2ecf20Sopenharmony_ci					break;
4878c2ecf20Sopenharmony_ci				c = tomoyo_make_byte(c, d, e);
4888c2ecf20Sopenharmony_ci				if (c <= ' ' || c >= 127)
4898c2ecf20Sopenharmony_ci					continue;
4908c2ecf20Sopenharmony_ci			}
4918c2ecf20Sopenharmony_ci			goto out;
4928c2ecf20Sopenharmony_ci		} else if (in_repetition && c == '/') {
4938c2ecf20Sopenharmony_ci			goto out;
4948c2ecf20Sopenharmony_ci		} else if (c <= ' ' || c >= 127) {
4958c2ecf20Sopenharmony_ci			goto out;
4968c2ecf20Sopenharmony_ci		}
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci	if (in_repetition)
4998c2ecf20Sopenharmony_ci		goto out;
5008c2ecf20Sopenharmony_ci	return true;
5018c2ecf20Sopenharmony_ci out:
5028c2ecf20Sopenharmony_ci	return false;
5038c2ecf20Sopenharmony_ci}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci/**
5068c2ecf20Sopenharmony_ci * tomoyo_correct_word - Validate a string.
5078c2ecf20Sopenharmony_ci *
5088c2ecf20Sopenharmony_ci * @string: The string to check.
5098c2ecf20Sopenharmony_ci *
5108c2ecf20Sopenharmony_ci * Check whether the given string follows the naming rules.
5118c2ecf20Sopenharmony_ci * Returns true if @string follows the naming rules, false otherwise.
5128c2ecf20Sopenharmony_ci */
5138c2ecf20Sopenharmony_cibool tomoyo_correct_word(const char *string)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	return tomoyo_correct_word2(string, strlen(string));
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci/**
5198c2ecf20Sopenharmony_ci * tomoyo_correct_path2 - Check whether the given pathname follows the naming rules.
5208c2ecf20Sopenharmony_ci *
5218c2ecf20Sopenharmony_ci * @filename: The pathname to check.
5228c2ecf20Sopenharmony_ci * @len:      Length of @filename.
5238c2ecf20Sopenharmony_ci *
5248c2ecf20Sopenharmony_ci * Returns true if @filename follows the naming rules, false otherwise.
5258c2ecf20Sopenharmony_ci */
5268c2ecf20Sopenharmony_cistatic bool tomoyo_correct_path2(const char *filename, const size_t len)
5278c2ecf20Sopenharmony_ci{
5288c2ecf20Sopenharmony_ci	const char *cp1 = memchr(filename, '/', len);
5298c2ecf20Sopenharmony_ci	const char *cp2 = memchr(filename, '.', len);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	return cp1 && (!cp2 || (cp1 < cp2)) && tomoyo_correct_word2(filename, len);
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci/**
5358c2ecf20Sopenharmony_ci * tomoyo_correct_path - Validate a pathname.
5368c2ecf20Sopenharmony_ci *
5378c2ecf20Sopenharmony_ci * @filename: The pathname to check.
5388c2ecf20Sopenharmony_ci *
5398c2ecf20Sopenharmony_ci * Check whether the given pathname follows the naming rules.
5408c2ecf20Sopenharmony_ci * Returns true if @filename follows the naming rules, false otherwise.
5418c2ecf20Sopenharmony_ci */
5428c2ecf20Sopenharmony_cibool tomoyo_correct_path(const char *filename)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	return tomoyo_correct_path2(filename, strlen(filename));
5458c2ecf20Sopenharmony_ci}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci/**
5488c2ecf20Sopenharmony_ci * tomoyo_correct_domain - Check whether the given domainname follows the naming rules.
5498c2ecf20Sopenharmony_ci *
5508c2ecf20Sopenharmony_ci * @domainname: The domainname to check.
5518c2ecf20Sopenharmony_ci *
5528c2ecf20Sopenharmony_ci * Returns true if @domainname follows the naming rules, false otherwise.
5538c2ecf20Sopenharmony_ci */
5548c2ecf20Sopenharmony_cibool tomoyo_correct_domain(const unsigned char *domainname)
5558c2ecf20Sopenharmony_ci{
5568c2ecf20Sopenharmony_ci	if (!domainname || !tomoyo_domain_def(domainname))
5578c2ecf20Sopenharmony_ci		return false;
5588c2ecf20Sopenharmony_ci	domainname = strchr(domainname, ' ');
5598c2ecf20Sopenharmony_ci	if (!domainname++)
5608c2ecf20Sopenharmony_ci		return true;
5618c2ecf20Sopenharmony_ci	while (1) {
5628c2ecf20Sopenharmony_ci		const unsigned char *cp = strchr(domainname, ' ');
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci		if (!cp)
5658c2ecf20Sopenharmony_ci			break;
5668c2ecf20Sopenharmony_ci		if (!tomoyo_correct_path2(domainname, cp - domainname))
5678c2ecf20Sopenharmony_ci			return false;
5688c2ecf20Sopenharmony_ci		domainname = cp + 1;
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ci	return tomoyo_correct_path(domainname);
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci/**
5748c2ecf20Sopenharmony_ci * tomoyo_domain_def - Check whether the given token can be a domainname.
5758c2ecf20Sopenharmony_ci *
5768c2ecf20Sopenharmony_ci * @buffer: The token to check.
5778c2ecf20Sopenharmony_ci *
5788c2ecf20Sopenharmony_ci * Returns true if @buffer possibly be a domainname, false otherwise.
5798c2ecf20Sopenharmony_ci */
5808c2ecf20Sopenharmony_cibool tomoyo_domain_def(const unsigned char *buffer)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	const unsigned char *cp;
5838c2ecf20Sopenharmony_ci	int len;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	if (*buffer != '<')
5868c2ecf20Sopenharmony_ci		return false;
5878c2ecf20Sopenharmony_ci	cp = strchr(buffer, ' ');
5888c2ecf20Sopenharmony_ci	if (!cp)
5898c2ecf20Sopenharmony_ci		len = strlen(buffer);
5908c2ecf20Sopenharmony_ci	else
5918c2ecf20Sopenharmony_ci		len = cp - buffer;
5928c2ecf20Sopenharmony_ci	if (buffer[len - 1] != '>' ||
5938c2ecf20Sopenharmony_ci	    !tomoyo_correct_word2(buffer + 1, len - 2))
5948c2ecf20Sopenharmony_ci		return false;
5958c2ecf20Sopenharmony_ci	return true;
5968c2ecf20Sopenharmony_ci}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci/**
5998c2ecf20Sopenharmony_ci * tomoyo_find_domain - Find a domain by the given name.
6008c2ecf20Sopenharmony_ci *
6018c2ecf20Sopenharmony_ci * @domainname: The domainname to find.
6028c2ecf20Sopenharmony_ci *
6038c2ecf20Sopenharmony_ci * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
6048c2ecf20Sopenharmony_ci *
6058c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
6068c2ecf20Sopenharmony_ci */
6078c2ecf20Sopenharmony_cistruct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	struct tomoyo_domain_info *domain;
6108c2ecf20Sopenharmony_ci	struct tomoyo_path_info name;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	name.name = domainname;
6138c2ecf20Sopenharmony_ci	tomoyo_fill_path_info(&name);
6148c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list,
6158c2ecf20Sopenharmony_ci				srcu_read_lock_held(&tomoyo_ss)) {
6168c2ecf20Sopenharmony_ci		if (!domain->is_deleted &&
6178c2ecf20Sopenharmony_ci		    !tomoyo_pathcmp(&name, domain->domainname))
6188c2ecf20Sopenharmony_ci			return domain;
6198c2ecf20Sopenharmony_ci	}
6208c2ecf20Sopenharmony_ci	return NULL;
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci/**
6248c2ecf20Sopenharmony_ci * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
6258c2ecf20Sopenharmony_ci *
6268c2ecf20Sopenharmony_ci * @filename: The string to evaluate.
6278c2ecf20Sopenharmony_ci *
6288c2ecf20Sopenharmony_ci * Returns the initial length without a pattern in @filename.
6298c2ecf20Sopenharmony_ci */
6308c2ecf20Sopenharmony_cistatic int tomoyo_const_part_length(const char *filename)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	char c;
6338c2ecf20Sopenharmony_ci	int len = 0;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	if (!filename)
6368c2ecf20Sopenharmony_ci		return 0;
6378c2ecf20Sopenharmony_ci	while ((c = *filename++) != '\0') {
6388c2ecf20Sopenharmony_ci		if (c != '\\') {
6398c2ecf20Sopenharmony_ci			len++;
6408c2ecf20Sopenharmony_ci			continue;
6418c2ecf20Sopenharmony_ci		}
6428c2ecf20Sopenharmony_ci		c = *filename++;
6438c2ecf20Sopenharmony_ci		switch (c) {
6448c2ecf20Sopenharmony_ci		case '\\':  /* "\\" */
6458c2ecf20Sopenharmony_ci			len += 2;
6468c2ecf20Sopenharmony_ci			continue;
6478c2ecf20Sopenharmony_ci		case '0':   /* "\ooo" */
6488c2ecf20Sopenharmony_ci		case '1':
6498c2ecf20Sopenharmony_ci		case '2':
6508c2ecf20Sopenharmony_ci		case '3':
6518c2ecf20Sopenharmony_ci			c = *filename++;
6528c2ecf20Sopenharmony_ci			if (c < '0' || c > '7')
6538c2ecf20Sopenharmony_ci				break;
6548c2ecf20Sopenharmony_ci			c = *filename++;
6558c2ecf20Sopenharmony_ci			if (c < '0' || c > '7')
6568c2ecf20Sopenharmony_ci				break;
6578c2ecf20Sopenharmony_ci			len += 4;
6588c2ecf20Sopenharmony_ci			continue;
6598c2ecf20Sopenharmony_ci		}
6608c2ecf20Sopenharmony_ci		break;
6618c2ecf20Sopenharmony_ci	}
6628c2ecf20Sopenharmony_ci	return len;
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci/**
6668c2ecf20Sopenharmony_ci * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
6678c2ecf20Sopenharmony_ci *
6688c2ecf20Sopenharmony_ci * @ptr: Pointer to "struct tomoyo_path_info" to fill in.
6698c2ecf20Sopenharmony_ci *
6708c2ecf20Sopenharmony_ci * The caller sets "struct tomoyo_path_info"->name.
6718c2ecf20Sopenharmony_ci */
6728c2ecf20Sopenharmony_civoid tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
6738c2ecf20Sopenharmony_ci{
6748c2ecf20Sopenharmony_ci	const char *name = ptr->name;
6758c2ecf20Sopenharmony_ci	const int len = strlen(name);
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	ptr->const_len = tomoyo_const_part_length(name);
6788c2ecf20Sopenharmony_ci	ptr->is_dir = len && (name[len - 1] == '/');
6798c2ecf20Sopenharmony_ci	ptr->is_patterned = (ptr->const_len < len);
6808c2ecf20Sopenharmony_ci	ptr->hash = full_name_hash(NULL, name, len);
6818c2ecf20Sopenharmony_ci}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci/**
6848c2ecf20Sopenharmony_ci * tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
6858c2ecf20Sopenharmony_ci *
6868c2ecf20Sopenharmony_ci * @filename:     The start of string to check.
6878c2ecf20Sopenharmony_ci * @filename_end: The end of string to check.
6888c2ecf20Sopenharmony_ci * @pattern:      The start of pattern to compare.
6898c2ecf20Sopenharmony_ci * @pattern_end:  The end of pattern to compare.
6908c2ecf20Sopenharmony_ci *
6918c2ecf20Sopenharmony_ci * Returns true if @filename matches @pattern, false otherwise.
6928c2ecf20Sopenharmony_ci */
6938c2ecf20Sopenharmony_cistatic bool tomoyo_file_matches_pattern2(const char *filename,
6948c2ecf20Sopenharmony_ci					 const char *filename_end,
6958c2ecf20Sopenharmony_ci					 const char *pattern,
6968c2ecf20Sopenharmony_ci					 const char *pattern_end)
6978c2ecf20Sopenharmony_ci{
6988c2ecf20Sopenharmony_ci	while (filename < filename_end && pattern < pattern_end) {
6998c2ecf20Sopenharmony_ci		char c;
7008c2ecf20Sopenharmony_ci		int i;
7018c2ecf20Sopenharmony_ci		int j;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci		if (*pattern != '\\') {
7048c2ecf20Sopenharmony_ci			if (*filename++ != *pattern++)
7058c2ecf20Sopenharmony_ci				return false;
7068c2ecf20Sopenharmony_ci			continue;
7078c2ecf20Sopenharmony_ci		}
7088c2ecf20Sopenharmony_ci		c = *filename;
7098c2ecf20Sopenharmony_ci		pattern++;
7108c2ecf20Sopenharmony_ci		switch (*pattern) {
7118c2ecf20Sopenharmony_ci		case '?':
7128c2ecf20Sopenharmony_ci			if (c == '/') {
7138c2ecf20Sopenharmony_ci				return false;
7148c2ecf20Sopenharmony_ci			} else if (c == '\\') {
7158c2ecf20Sopenharmony_ci				if (filename[1] == '\\')
7168c2ecf20Sopenharmony_ci					filename++;
7178c2ecf20Sopenharmony_ci				else if (tomoyo_byte_range(filename + 1))
7188c2ecf20Sopenharmony_ci					filename += 3;
7198c2ecf20Sopenharmony_ci				else
7208c2ecf20Sopenharmony_ci					return false;
7218c2ecf20Sopenharmony_ci			}
7228c2ecf20Sopenharmony_ci			break;
7238c2ecf20Sopenharmony_ci		case '\\':
7248c2ecf20Sopenharmony_ci			if (c != '\\')
7258c2ecf20Sopenharmony_ci				return false;
7268c2ecf20Sopenharmony_ci			if (*++filename != '\\')
7278c2ecf20Sopenharmony_ci				return false;
7288c2ecf20Sopenharmony_ci			break;
7298c2ecf20Sopenharmony_ci		case '+':
7308c2ecf20Sopenharmony_ci			if (!isdigit(c))
7318c2ecf20Sopenharmony_ci				return false;
7328c2ecf20Sopenharmony_ci			break;
7338c2ecf20Sopenharmony_ci		case 'x':
7348c2ecf20Sopenharmony_ci			if (!isxdigit(c))
7358c2ecf20Sopenharmony_ci				return false;
7368c2ecf20Sopenharmony_ci			break;
7378c2ecf20Sopenharmony_ci		case 'a':
7388c2ecf20Sopenharmony_ci			if (!tomoyo_alphabet_char(c))
7398c2ecf20Sopenharmony_ci				return false;
7408c2ecf20Sopenharmony_ci			break;
7418c2ecf20Sopenharmony_ci		case '0':
7428c2ecf20Sopenharmony_ci		case '1':
7438c2ecf20Sopenharmony_ci		case '2':
7448c2ecf20Sopenharmony_ci		case '3':
7458c2ecf20Sopenharmony_ci			if (c == '\\' && tomoyo_byte_range(filename + 1)
7468c2ecf20Sopenharmony_ci			    && strncmp(filename + 1, pattern, 3) == 0) {
7478c2ecf20Sopenharmony_ci				filename += 3;
7488c2ecf20Sopenharmony_ci				pattern += 2;
7498c2ecf20Sopenharmony_ci				break;
7508c2ecf20Sopenharmony_ci			}
7518c2ecf20Sopenharmony_ci			return false; /* Not matched. */
7528c2ecf20Sopenharmony_ci		case '*':
7538c2ecf20Sopenharmony_ci		case '@':
7548c2ecf20Sopenharmony_ci			for (i = 0; i <= filename_end - filename; i++) {
7558c2ecf20Sopenharmony_ci				if (tomoyo_file_matches_pattern2(
7568c2ecf20Sopenharmony_ci						    filename + i, filename_end,
7578c2ecf20Sopenharmony_ci						    pattern + 1, pattern_end))
7588c2ecf20Sopenharmony_ci					return true;
7598c2ecf20Sopenharmony_ci				c = filename[i];
7608c2ecf20Sopenharmony_ci				if (c == '.' && *pattern == '@')
7618c2ecf20Sopenharmony_ci					break;
7628c2ecf20Sopenharmony_ci				if (c != '\\')
7638c2ecf20Sopenharmony_ci					continue;
7648c2ecf20Sopenharmony_ci				if (filename[i + 1] == '\\')
7658c2ecf20Sopenharmony_ci					i++;
7668c2ecf20Sopenharmony_ci				else if (tomoyo_byte_range(filename + i + 1))
7678c2ecf20Sopenharmony_ci					i += 3;
7688c2ecf20Sopenharmony_ci				else
7698c2ecf20Sopenharmony_ci					break; /* Bad pattern. */
7708c2ecf20Sopenharmony_ci			}
7718c2ecf20Sopenharmony_ci			return false; /* Not matched. */
7728c2ecf20Sopenharmony_ci		default:
7738c2ecf20Sopenharmony_ci			j = 0;
7748c2ecf20Sopenharmony_ci			c = *pattern;
7758c2ecf20Sopenharmony_ci			if (c == '$') {
7768c2ecf20Sopenharmony_ci				while (isdigit(filename[j]))
7778c2ecf20Sopenharmony_ci					j++;
7788c2ecf20Sopenharmony_ci			} else if (c == 'X') {
7798c2ecf20Sopenharmony_ci				while (isxdigit(filename[j]))
7808c2ecf20Sopenharmony_ci					j++;
7818c2ecf20Sopenharmony_ci			} else if (c == 'A') {
7828c2ecf20Sopenharmony_ci				while (tomoyo_alphabet_char(filename[j]))
7838c2ecf20Sopenharmony_ci					j++;
7848c2ecf20Sopenharmony_ci			}
7858c2ecf20Sopenharmony_ci			for (i = 1; i <= j; i++) {
7868c2ecf20Sopenharmony_ci				if (tomoyo_file_matches_pattern2(
7878c2ecf20Sopenharmony_ci						    filename + i, filename_end,
7888c2ecf20Sopenharmony_ci						    pattern + 1, pattern_end))
7898c2ecf20Sopenharmony_ci					return true;
7908c2ecf20Sopenharmony_ci			}
7918c2ecf20Sopenharmony_ci			return false; /* Not matched or bad pattern. */
7928c2ecf20Sopenharmony_ci		}
7938c2ecf20Sopenharmony_ci		filename++;
7948c2ecf20Sopenharmony_ci		pattern++;
7958c2ecf20Sopenharmony_ci	}
7968c2ecf20Sopenharmony_ci	while (*pattern == '\\' &&
7978c2ecf20Sopenharmony_ci	       (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
7988c2ecf20Sopenharmony_ci		pattern += 2;
7998c2ecf20Sopenharmony_ci	return filename == filename_end && pattern == pattern_end;
8008c2ecf20Sopenharmony_ci}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci/**
8038c2ecf20Sopenharmony_ci * tomoyo_file_matches_pattern - Pattern matching without '/' character.
8048c2ecf20Sopenharmony_ci *
8058c2ecf20Sopenharmony_ci * @filename:     The start of string to check.
8068c2ecf20Sopenharmony_ci * @filename_end: The end of string to check.
8078c2ecf20Sopenharmony_ci * @pattern:      The start of pattern to compare.
8088c2ecf20Sopenharmony_ci * @pattern_end:  The end of pattern to compare.
8098c2ecf20Sopenharmony_ci *
8108c2ecf20Sopenharmony_ci * Returns true if @filename matches @pattern, false otherwise.
8118c2ecf20Sopenharmony_ci */
8128c2ecf20Sopenharmony_cistatic bool tomoyo_file_matches_pattern(const char *filename,
8138c2ecf20Sopenharmony_ci					const char *filename_end,
8148c2ecf20Sopenharmony_ci					const char *pattern,
8158c2ecf20Sopenharmony_ci					const char *pattern_end)
8168c2ecf20Sopenharmony_ci{
8178c2ecf20Sopenharmony_ci	const char *pattern_start = pattern;
8188c2ecf20Sopenharmony_ci	bool first = true;
8198c2ecf20Sopenharmony_ci	bool result;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	while (pattern < pattern_end - 1) {
8228c2ecf20Sopenharmony_ci		/* Split at "\-" pattern. */
8238c2ecf20Sopenharmony_ci		if (*pattern++ != '\\' || *pattern++ != '-')
8248c2ecf20Sopenharmony_ci			continue;
8258c2ecf20Sopenharmony_ci		result = tomoyo_file_matches_pattern2(filename,
8268c2ecf20Sopenharmony_ci						      filename_end,
8278c2ecf20Sopenharmony_ci						      pattern_start,
8288c2ecf20Sopenharmony_ci						      pattern - 2);
8298c2ecf20Sopenharmony_ci		if (first)
8308c2ecf20Sopenharmony_ci			result = !result;
8318c2ecf20Sopenharmony_ci		if (result)
8328c2ecf20Sopenharmony_ci			return false;
8338c2ecf20Sopenharmony_ci		first = false;
8348c2ecf20Sopenharmony_ci		pattern_start = pattern;
8358c2ecf20Sopenharmony_ci	}
8368c2ecf20Sopenharmony_ci	result = tomoyo_file_matches_pattern2(filename, filename_end,
8378c2ecf20Sopenharmony_ci					      pattern_start, pattern_end);
8388c2ecf20Sopenharmony_ci	return first ? result : !result;
8398c2ecf20Sopenharmony_ci}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci/**
8428c2ecf20Sopenharmony_ci * tomoyo_path_matches_pattern2 - Do pathname pattern matching.
8438c2ecf20Sopenharmony_ci *
8448c2ecf20Sopenharmony_ci * @f: The start of string to check.
8458c2ecf20Sopenharmony_ci * @p: The start of pattern to compare.
8468c2ecf20Sopenharmony_ci *
8478c2ecf20Sopenharmony_ci * Returns true if @f matches @p, false otherwise.
8488c2ecf20Sopenharmony_ci */
8498c2ecf20Sopenharmony_cistatic bool tomoyo_path_matches_pattern2(const char *f, const char *p)
8508c2ecf20Sopenharmony_ci{
8518c2ecf20Sopenharmony_ci	const char *f_delimiter;
8528c2ecf20Sopenharmony_ci	const char *p_delimiter;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	while (*f && *p) {
8558c2ecf20Sopenharmony_ci		f_delimiter = strchr(f, '/');
8568c2ecf20Sopenharmony_ci		if (!f_delimiter)
8578c2ecf20Sopenharmony_ci			f_delimiter = f + strlen(f);
8588c2ecf20Sopenharmony_ci		p_delimiter = strchr(p, '/');
8598c2ecf20Sopenharmony_ci		if (!p_delimiter)
8608c2ecf20Sopenharmony_ci			p_delimiter = p + strlen(p);
8618c2ecf20Sopenharmony_ci		if (*p == '\\' && *(p + 1) == '{')
8628c2ecf20Sopenharmony_ci			goto recursive;
8638c2ecf20Sopenharmony_ci		if (!tomoyo_file_matches_pattern(f, f_delimiter, p,
8648c2ecf20Sopenharmony_ci						 p_delimiter))
8658c2ecf20Sopenharmony_ci			return false;
8668c2ecf20Sopenharmony_ci		f = f_delimiter;
8678c2ecf20Sopenharmony_ci		if (*f)
8688c2ecf20Sopenharmony_ci			f++;
8698c2ecf20Sopenharmony_ci		p = p_delimiter;
8708c2ecf20Sopenharmony_ci		if (*p)
8718c2ecf20Sopenharmony_ci			p++;
8728c2ecf20Sopenharmony_ci	}
8738c2ecf20Sopenharmony_ci	/* Ignore trailing "\*" and "\@" in @pattern. */
8748c2ecf20Sopenharmony_ci	while (*p == '\\' &&
8758c2ecf20Sopenharmony_ci	       (*(p + 1) == '*' || *(p + 1) == '@'))
8768c2ecf20Sopenharmony_ci		p += 2;
8778c2ecf20Sopenharmony_ci	return !*f && !*p;
8788c2ecf20Sopenharmony_ci recursive:
8798c2ecf20Sopenharmony_ci	/*
8808c2ecf20Sopenharmony_ci	 * The "\{" pattern is permitted only after '/' character.
8818c2ecf20Sopenharmony_ci	 * This guarantees that below "*(p - 1)" is safe.
8828c2ecf20Sopenharmony_ci	 * Also, the "\}" pattern is permitted only before '/' character
8838c2ecf20Sopenharmony_ci	 * so that "\{" + "\}" pair will not break the "\-" operator.
8848c2ecf20Sopenharmony_ci	 */
8858c2ecf20Sopenharmony_ci	if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
8868c2ecf20Sopenharmony_ci	    *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
8878c2ecf20Sopenharmony_ci		return false; /* Bad pattern. */
8888c2ecf20Sopenharmony_ci	do {
8898c2ecf20Sopenharmony_ci		/* Compare current component with pattern. */
8908c2ecf20Sopenharmony_ci		if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2,
8918c2ecf20Sopenharmony_ci						 p_delimiter - 2))
8928c2ecf20Sopenharmony_ci			break;
8938c2ecf20Sopenharmony_ci		/* Proceed to next component. */
8948c2ecf20Sopenharmony_ci		f = f_delimiter;
8958c2ecf20Sopenharmony_ci		if (!*f)
8968c2ecf20Sopenharmony_ci			break;
8978c2ecf20Sopenharmony_ci		f++;
8988c2ecf20Sopenharmony_ci		/* Continue comparison. */
8998c2ecf20Sopenharmony_ci		if (tomoyo_path_matches_pattern2(f, p_delimiter + 1))
9008c2ecf20Sopenharmony_ci			return true;
9018c2ecf20Sopenharmony_ci		f_delimiter = strchr(f, '/');
9028c2ecf20Sopenharmony_ci	} while (f_delimiter);
9038c2ecf20Sopenharmony_ci	return false; /* Not matched. */
9048c2ecf20Sopenharmony_ci}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci/**
9078c2ecf20Sopenharmony_ci * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
9088c2ecf20Sopenharmony_ci *
9098c2ecf20Sopenharmony_ci * @filename: The filename to check.
9108c2ecf20Sopenharmony_ci * @pattern:  The pattern to compare.
9118c2ecf20Sopenharmony_ci *
9128c2ecf20Sopenharmony_ci * Returns true if matches, false otherwise.
9138c2ecf20Sopenharmony_ci *
9148c2ecf20Sopenharmony_ci * The following patterns are available.
9158c2ecf20Sopenharmony_ci *   \\     \ itself.
9168c2ecf20Sopenharmony_ci *   \ooo   Octal representation of a byte.
9178c2ecf20Sopenharmony_ci *   \*     Zero or more repetitions of characters other than '/'.
9188c2ecf20Sopenharmony_ci *   \@     Zero or more repetitions of characters other than '/' or '.'.
9198c2ecf20Sopenharmony_ci *   \?     1 byte character other than '/'.
9208c2ecf20Sopenharmony_ci *   \$     One or more repetitions of decimal digits.
9218c2ecf20Sopenharmony_ci *   \+     1 decimal digit.
9228c2ecf20Sopenharmony_ci *   \X     One or more repetitions of hexadecimal digits.
9238c2ecf20Sopenharmony_ci *   \x     1 hexadecimal digit.
9248c2ecf20Sopenharmony_ci *   \A     One or more repetitions of alphabet characters.
9258c2ecf20Sopenharmony_ci *   \a     1 alphabet character.
9268c2ecf20Sopenharmony_ci *
9278c2ecf20Sopenharmony_ci *   \-     Subtraction operator.
9288c2ecf20Sopenharmony_ci *
9298c2ecf20Sopenharmony_ci *   /\{dir\}/   '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
9308c2ecf20Sopenharmony_ci *               /dir/dir/dir/ ).
9318c2ecf20Sopenharmony_ci */
9328c2ecf20Sopenharmony_cibool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
9338c2ecf20Sopenharmony_ci				 const struct tomoyo_path_info *pattern)
9348c2ecf20Sopenharmony_ci{
9358c2ecf20Sopenharmony_ci	const char *f = filename->name;
9368c2ecf20Sopenharmony_ci	const char *p = pattern->name;
9378c2ecf20Sopenharmony_ci	const int len = pattern->const_len;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	/* If @pattern doesn't contain pattern, I can use strcmp(). */
9408c2ecf20Sopenharmony_ci	if (!pattern->is_patterned)
9418c2ecf20Sopenharmony_ci		return !tomoyo_pathcmp(filename, pattern);
9428c2ecf20Sopenharmony_ci	/* Don't compare directory and non-directory. */
9438c2ecf20Sopenharmony_ci	if (filename->is_dir != pattern->is_dir)
9448c2ecf20Sopenharmony_ci		return false;
9458c2ecf20Sopenharmony_ci	/* Compare the initial length without patterns. */
9468c2ecf20Sopenharmony_ci	if (strncmp(f, p, len))
9478c2ecf20Sopenharmony_ci		return false;
9488c2ecf20Sopenharmony_ci	f += len;
9498c2ecf20Sopenharmony_ci	p += len;
9508c2ecf20Sopenharmony_ci	return tomoyo_path_matches_pattern2(f, p);
9518c2ecf20Sopenharmony_ci}
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci/**
9548c2ecf20Sopenharmony_ci * tomoyo_get_exe - Get tomoyo_realpath() of current process.
9558c2ecf20Sopenharmony_ci *
9568c2ecf20Sopenharmony_ci * Returns the tomoyo_realpath() of current process on success, NULL otherwise.
9578c2ecf20Sopenharmony_ci *
9588c2ecf20Sopenharmony_ci * This function uses kzalloc(), so the caller must call kfree()
9598c2ecf20Sopenharmony_ci * if this function didn't return NULL.
9608c2ecf20Sopenharmony_ci */
9618c2ecf20Sopenharmony_ciconst char *tomoyo_get_exe(void)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	struct file *exe_file;
9648c2ecf20Sopenharmony_ci	const char *cp;
9658c2ecf20Sopenharmony_ci	struct mm_struct *mm = current->mm;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	if (!mm)
9688c2ecf20Sopenharmony_ci		return NULL;
9698c2ecf20Sopenharmony_ci	exe_file = get_mm_exe_file(mm);
9708c2ecf20Sopenharmony_ci	if (!exe_file)
9718c2ecf20Sopenharmony_ci		return NULL;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	cp = tomoyo_realpath_from_path(&exe_file->f_path);
9748c2ecf20Sopenharmony_ci	fput(exe_file);
9758c2ecf20Sopenharmony_ci	return cp;
9768c2ecf20Sopenharmony_ci}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci/**
9798c2ecf20Sopenharmony_ci * tomoyo_get_mode - Get MAC mode.
9808c2ecf20Sopenharmony_ci *
9818c2ecf20Sopenharmony_ci * @ns:      Pointer to "struct tomoyo_policy_namespace".
9828c2ecf20Sopenharmony_ci * @profile: Profile number.
9838c2ecf20Sopenharmony_ci * @index:   Index number of functionality.
9848c2ecf20Sopenharmony_ci *
9858c2ecf20Sopenharmony_ci * Returns mode.
9868c2ecf20Sopenharmony_ci */
9878c2ecf20Sopenharmony_ciint tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
9888c2ecf20Sopenharmony_ci		    const u8 index)
9898c2ecf20Sopenharmony_ci{
9908c2ecf20Sopenharmony_ci	u8 mode;
9918c2ecf20Sopenharmony_ci	struct tomoyo_profile *p;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	if (!tomoyo_policy_loaded)
9948c2ecf20Sopenharmony_ci		return TOMOYO_CONFIG_DISABLED;
9958c2ecf20Sopenharmony_ci	p = tomoyo_profile(ns, profile);
9968c2ecf20Sopenharmony_ci	mode = p->config[index];
9978c2ecf20Sopenharmony_ci	if (mode == TOMOYO_CONFIG_USE_DEFAULT)
9988c2ecf20Sopenharmony_ci		mode = p->config[tomoyo_index2category[index]
9998c2ecf20Sopenharmony_ci				 + TOMOYO_MAX_MAC_INDEX];
10008c2ecf20Sopenharmony_ci	if (mode == TOMOYO_CONFIG_USE_DEFAULT)
10018c2ecf20Sopenharmony_ci		mode = p->default_config;
10028c2ecf20Sopenharmony_ci	return mode & 3;
10038c2ecf20Sopenharmony_ci}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci/**
10068c2ecf20Sopenharmony_ci * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members.
10078c2ecf20Sopenharmony_ci *
10088c2ecf20Sopenharmony_ci * @r:      Pointer to "struct tomoyo_request_info" to initialize.
10098c2ecf20Sopenharmony_ci * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain().
10108c2ecf20Sopenharmony_ci * @index:  Index number of functionality.
10118c2ecf20Sopenharmony_ci *
10128c2ecf20Sopenharmony_ci * Returns mode.
10138c2ecf20Sopenharmony_ci */
10148c2ecf20Sopenharmony_ciint tomoyo_init_request_info(struct tomoyo_request_info *r,
10158c2ecf20Sopenharmony_ci			     struct tomoyo_domain_info *domain, const u8 index)
10168c2ecf20Sopenharmony_ci{
10178c2ecf20Sopenharmony_ci	u8 profile;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	memset(r, 0, sizeof(*r));
10208c2ecf20Sopenharmony_ci	if (!domain)
10218c2ecf20Sopenharmony_ci		domain = tomoyo_domain();
10228c2ecf20Sopenharmony_ci	r->domain = domain;
10238c2ecf20Sopenharmony_ci	profile = domain->profile;
10248c2ecf20Sopenharmony_ci	r->profile = profile;
10258c2ecf20Sopenharmony_ci	r->type = index;
10268c2ecf20Sopenharmony_ci	r->mode = tomoyo_get_mode(domain->ns, profile, index);
10278c2ecf20Sopenharmony_ci	return r->mode;
10288c2ecf20Sopenharmony_ci}
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci/**
10318c2ecf20Sopenharmony_ci * tomoyo_domain_quota_is_ok - Check for domain's quota.
10328c2ecf20Sopenharmony_ci *
10338c2ecf20Sopenharmony_ci * @r: Pointer to "struct tomoyo_request_info".
10348c2ecf20Sopenharmony_ci *
10358c2ecf20Sopenharmony_ci * Returns true if the domain is not exceeded quota, false otherwise.
10368c2ecf20Sopenharmony_ci *
10378c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
10388c2ecf20Sopenharmony_ci */
10398c2ecf20Sopenharmony_cibool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
10408c2ecf20Sopenharmony_ci{
10418c2ecf20Sopenharmony_ci	unsigned int count = 0;
10428c2ecf20Sopenharmony_ci	struct tomoyo_domain_info *domain = r->domain;
10438c2ecf20Sopenharmony_ci	struct tomoyo_acl_info *ptr;
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	if (r->mode != TOMOYO_CONFIG_LEARNING)
10468c2ecf20Sopenharmony_ci		return false;
10478c2ecf20Sopenharmony_ci	if (!domain)
10488c2ecf20Sopenharmony_ci		return true;
10498c2ecf20Sopenharmony_ci	if (READ_ONCE(domain->flags[TOMOYO_DIF_QUOTA_WARNED]))
10508c2ecf20Sopenharmony_ci		return false;
10518c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list,
10528c2ecf20Sopenharmony_ci				srcu_read_lock_held(&tomoyo_ss)) {
10538c2ecf20Sopenharmony_ci		u16 perm;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci		if (ptr->is_deleted)
10568c2ecf20Sopenharmony_ci			continue;
10578c2ecf20Sopenharmony_ci		/*
10588c2ecf20Sopenharmony_ci		 * Reading perm bitmap might race with tomoyo_merge_*() because
10598c2ecf20Sopenharmony_ci		 * caller does not hold tomoyo_policy_lock mutex. But exceeding
10608c2ecf20Sopenharmony_ci		 * max_learning_entry parameter by a few entries does not harm.
10618c2ecf20Sopenharmony_ci		 */
10628c2ecf20Sopenharmony_ci		switch (ptr->type) {
10638c2ecf20Sopenharmony_ci		case TOMOYO_TYPE_PATH_ACL:
10648c2ecf20Sopenharmony_ci			perm = data_race(container_of(ptr, struct tomoyo_path_acl, head)->perm);
10658c2ecf20Sopenharmony_ci			break;
10668c2ecf20Sopenharmony_ci		case TOMOYO_TYPE_PATH2_ACL:
10678c2ecf20Sopenharmony_ci			perm = data_race(container_of(ptr, struct tomoyo_path2_acl, head)->perm);
10688c2ecf20Sopenharmony_ci			break;
10698c2ecf20Sopenharmony_ci		case TOMOYO_TYPE_PATH_NUMBER_ACL:
10708c2ecf20Sopenharmony_ci			perm = data_race(container_of(ptr, struct tomoyo_path_number_acl, head)
10718c2ecf20Sopenharmony_ci				  ->perm);
10728c2ecf20Sopenharmony_ci			break;
10738c2ecf20Sopenharmony_ci		case TOMOYO_TYPE_MKDEV_ACL:
10748c2ecf20Sopenharmony_ci			perm = data_race(container_of(ptr, struct tomoyo_mkdev_acl, head)->perm);
10758c2ecf20Sopenharmony_ci			break;
10768c2ecf20Sopenharmony_ci		case TOMOYO_TYPE_INET_ACL:
10778c2ecf20Sopenharmony_ci			perm = data_race(container_of(ptr, struct tomoyo_inet_acl, head)->perm);
10788c2ecf20Sopenharmony_ci			break;
10798c2ecf20Sopenharmony_ci		case TOMOYO_TYPE_UNIX_ACL:
10808c2ecf20Sopenharmony_ci			perm = data_race(container_of(ptr, struct tomoyo_unix_acl, head)->perm);
10818c2ecf20Sopenharmony_ci			break;
10828c2ecf20Sopenharmony_ci		case TOMOYO_TYPE_MANUAL_TASK_ACL:
10838c2ecf20Sopenharmony_ci			perm = 0;
10848c2ecf20Sopenharmony_ci			break;
10858c2ecf20Sopenharmony_ci		default:
10868c2ecf20Sopenharmony_ci			perm = 1;
10878c2ecf20Sopenharmony_ci		}
10888c2ecf20Sopenharmony_ci		count += hweight16(perm);
10898c2ecf20Sopenharmony_ci	}
10908c2ecf20Sopenharmony_ci	if (count < tomoyo_profile(domain->ns, domain->profile)->
10918c2ecf20Sopenharmony_ci	    pref[TOMOYO_PREF_MAX_LEARNING_ENTRY])
10928c2ecf20Sopenharmony_ci		return true;
10938c2ecf20Sopenharmony_ci	WRITE_ONCE(domain->flags[TOMOYO_DIF_QUOTA_WARNED], true);
10948c2ecf20Sopenharmony_ci	/* r->granted = false; */
10958c2ecf20Sopenharmony_ci	tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]);
10968c2ecf20Sopenharmony_ci#ifndef CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING
10978c2ecf20Sopenharmony_ci	pr_warn("WARNING: Domain '%s' has too many ACLs to hold. Stopped learning mode.\n",
10988c2ecf20Sopenharmony_ci		domain->domainname->name);
10998c2ecf20Sopenharmony_ci#endif
11008c2ecf20Sopenharmony_ci	return false;
11018c2ecf20Sopenharmony_ci}
1102