cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

util.c (28275B)


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