162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * security/tomoyo/util.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005-2011 NTT DATA CORPORATION 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/rculist.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "common.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* Lock for protecting policy. */ 1462306a36Sopenharmony_ciDEFINE_MUTEX(tomoyo_policy_lock); 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* Has /sbin/init started? */ 1762306a36Sopenharmony_cibool tomoyo_policy_loaded; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * Mapping table from "enum tomoyo_mac_index" to 2162306a36Sopenharmony_ci * "enum tomoyo_mac_category_index". 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ciconst u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = { 2462306a36Sopenharmony_ci /* CONFIG::file group */ 2562306a36Sopenharmony_ci [TOMOYO_MAC_FILE_EXECUTE] = TOMOYO_MAC_CATEGORY_FILE, 2662306a36Sopenharmony_ci [TOMOYO_MAC_FILE_OPEN] = TOMOYO_MAC_CATEGORY_FILE, 2762306a36Sopenharmony_ci [TOMOYO_MAC_FILE_CREATE] = TOMOYO_MAC_CATEGORY_FILE, 2862306a36Sopenharmony_ci [TOMOYO_MAC_FILE_UNLINK] = TOMOYO_MAC_CATEGORY_FILE, 2962306a36Sopenharmony_ci [TOMOYO_MAC_FILE_GETATTR] = TOMOYO_MAC_CATEGORY_FILE, 3062306a36Sopenharmony_ci [TOMOYO_MAC_FILE_MKDIR] = TOMOYO_MAC_CATEGORY_FILE, 3162306a36Sopenharmony_ci [TOMOYO_MAC_FILE_RMDIR] = TOMOYO_MAC_CATEGORY_FILE, 3262306a36Sopenharmony_ci [TOMOYO_MAC_FILE_MKFIFO] = TOMOYO_MAC_CATEGORY_FILE, 3362306a36Sopenharmony_ci [TOMOYO_MAC_FILE_MKSOCK] = TOMOYO_MAC_CATEGORY_FILE, 3462306a36Sopenharmony_ci [TOMOYO_MAC_FILE_TRUNCATE] = TOMOYO_MAC_CATEGORY_FILE, 3562306a36Sopenharmony_ci [TOMOYO_MAC_FILE_SYMLINK] = TOMOYO_MAC_CATEGORY_FILE, 3662306a36Sopenharmony_ci [TOMOYO_MAC_FILE_MKBLOCK] = TOMOYO_MAC_CATEGORY_FILE, 3762306a36Sopenharmony_ci [TOMOYO_MAC_FILE_MKCHAR] = TOMOYO_MAC_CATEGORY_FILE, 3862306a36Sopenharmony_ci [TOMOYO_MAC_FILE_LINK] = TOMOYO_MAC_CATEGORY_FILE, 3962306a36Sopenharmony_ci [TOMOYO_MAC_FILE_RENAME] = TOMOYO_MAC_CATEGORY_FILE, 4062306a36Sopenharmony_ci [TOMOYO_MAC_FILE_CHMOD] = TOMOYO_MAC_CATEGORY_FILE, 4162306a36Sopenharmony_ci [TOMOYO_MAC_FILE_CHOWN] = TOMOYO_MAC_CATEGORY_FILE, 4262306a36Sopenharmony_ci [TOMOYO_MAC_FILE_CHGRP] = TOMOYO_MAC_CATEGORY_FILE, 4362306a36Sopenharmony_ci [TOMOYO_MAC_FILE_IOCTL] = TOMOYO_MAC_CATEGORY_FILE, 4462306a36Sopenharmony_ci [TOMOYO_MAC_FILE_CHROOT] = TOMOYO_MAC_CATEGORY_FILE, 4562306a36Sopenharmony_ci [TOMOYO_MAC_FILE_MOUNT] = TOMOYO_MAC_CATEGORY_FILE, 4662306a36Sopenharmony_ci [TOMOYO_MAC_FILE_UMOUNT] = TOMOYO_MAC_CATEGORY_FILE, 4762306a36Sopenharmony_ci [TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE, 4862306a36Sopenharmony_ci /* CONFIG::network group */ 4962306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_INET_STREAM_BIND] = 5062306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 5162306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN] = 5262306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 5362306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT] = 5462306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 5562306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_INET_DGRAM_BIND] = 5662306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 5762306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_INET_DGRAM_SEND] = 5862306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 5962306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_INET_RAW_BIND] = 6062306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 6162306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_INET_RAW_SEND] = 6262306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 6362306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND] = 6462306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 6562306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN] = 6662306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 6762306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT] = 6862306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 6962306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND] = 7062306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 7162306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND] = 7262306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 7362306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND] = 7462306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 7562306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = 7662306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 7762306a36Sopenharmony_ci [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = 7862306a36Sopenharmony_ci TOMOYO_MAC_CATEGORY_NETWORK, 7962306a36Sopenharmony_ci /* CONFIG::misc group */ 8062306a36Sopenharmony_ci [TOMOYO_MAC_ENVIRON] = TOMOYO_MAC_CATEGORY_MISC, 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/** 8462306a36Sopenharmony_ci * tomoyo_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss. 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * @time64: Seconds since 1970/01/01 00:00:00. 8762306a36Sopenharmony_ci * @stamp: Pointer to "struct tomoyo_time". 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * Returns nothing. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_civoid tomoyo_convert_time(time64_t time64, struct tomoyo_time *stamp) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct tm tm; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci time64_to_tm(time64, 0, &tm); 9662306a36Sopenharmony_ci stamp->sec = tm.tm_sec; 9762306a36Sopenharmony_ci stamp->min = tm.tm_min; 9862306a36Sopenharmony_ci stamp->hour = tm.tm_hour; 9962306a36Sopenharmony_ci stamp->day = tm.tm_mday; 10062306a36Sopenharmony_ci stamp->month = tm.tm_mon + 1; 10162306a36Sopenharmony_ci stamp->year = tm.tm_year + 1900; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/** 10562306a36Sopenharmony_ci * tomoyo_permstr - Find permission keywords. 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * @string: String representation for permissions in foo/bar/buz format. 10862306a36Sopenharmony_ci * @keyword: Keyword to find from @string/ 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * Returns true if @keyword was found in @string, false otherwise. 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_cibool tomoyo_permstr(const char *string, const char *keyword) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci const char *cp = strstr(string, keyword); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (cp) 11962306a36Sopenharmony_ci return cp == string || *(cp - 1) == '/'; 12062306a36Sopenharmony_ci return false; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/** 12462306a36Sopenharmony_ci * tomoyo_read_token - Read a word from a line. 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param". 12762306a36Sopenharmony_ci * 12862306a36Sopenharmony_ci * Returns a word on success, "" otherwise. 12962306a36Sopenharmony_ci * 13062306a36Sopenharmony_ci * To allow the caller to skip NULL check, this function returns "" rather than 13162306a36Sopenharmony_ci * NULL if there is no more words to read. 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_cichar *tomoyo_read_token(struct tomoyo_acl_param *param) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci char *pos = param->data; 13662306a36Sopenharmony_ci char *del = strchr(pos, ' '); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (del) 13962306a36Sopenharmony_ci *del++ = '\0'; 14062306a36Sopenharmony_ci else 14162306a36Sopenharmony_ci del = pos + strlen(pos); 14262306a36Sopenharmony_ci param->data = del; 14362306a36Sopenharmony_ci return pos; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic bool tomoyo_correct_path2(const char *filename, const size_t len); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/** 14962306a36Sopenharmony_ci * tomoyo_get_domainname - Read a domainname from a line. 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param". 15262306a36Sopenharmony_ci * 15362306a36Sopenharmony_ci * Returns a domainname on success, NULL otherwise. 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_ciconst struct tomoyo_path_info *tomoyo_get_domainname 15662306a36Sopenharmony_ci(struct tomoyo_acl_param *param) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci char *start = param->data; 15962306a36Sopenharmony_ci char *pos = start; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci while (*pos) { 16262306a36Sopenharmony_ci if (*pos++ != ' ' || 16362306a36Sopenharmony_ci tomoyo_correct_path2(pos, strchrnul(pos, ' ') - pos)) 16462306a36Sopenharmony_ci continue; 16562306a36Sopenharmony_ci *(pos - 1) = '\0'; 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci param->data = pos; 16962306a36Sopenharmony_ci if (tomoyo_correct_domain(start)) 17062306a36Sopenharmony_ci return tomoyo_get_name(start); 17162306a36Sopenharmony_ci return NULL; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/** 17562306a36Sopenharmony_ci * tomoyo_parse_ulong - Parse an "unsigned long" value. 17662306a36Sopenharmony_ci * 17762306a36Sopenharmony_ci * @result: Pointer to "unsigned long". 17862306a36Sopenharmony_ci * @str: Pointer to string to parse. 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * Returns one of values in "enum tomoyo_value_type". 18162306a36Sopenharmony_ci * 18262306a36Sopenharmony_ci * The @src is updated to point the first character after the value 18362306a36Sopenharmony_ci * on success. 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_ciu8 tomoyo_parse_ulong(unsigned long *result, char **str) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci const char *cp = *str; 18862306a36Sopenharmony_ci char *ep; 18962306a36Sopenharmony_ci int base = 10; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (*cp == '0') { 19262306a36Sopenharmony_ci char c = *(cp + 1); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (c == 'x' || c == 'X') { 19562306a36Sopenharmony_ci base = 16; 19662306a36Sopenharmony_ci cp += 2; 19762306a36Sopenharmony_ci } else if (c >= '0' && c <= '7') { 19862306a36Sopenharmony_ci base = 8; 19962306a36Sopenharmony_ci cp++; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci *result = simple_strtoul(cp, &ep, base); 20362306a36Sopenharmony_ci if (cp == ep) 20462306a36Sopenharmony_ci return TOMOYO_VALUE_TYPE_INVALID; 20562306a36Sopenharmony_ci *str = ep; 20662306a36Sopenharmony_ci switch (base) { 20762306a36Sopenharmony_ci case 16: 20862306a36Sopenharmony_ci return TOMOYO_VALUE_TYPE_HEXADECIMAL; 20962306a36Sopenharmony_ci case 8: 21062306a36Sopenharmony_ci return TOMOYO_VALUE_TYPE_OCTAL; 21162306a36Sopenharmony_ci default: 21262306a36Sopenharmony_ci return TOMOYO_VALUE_TYPE_DECIMAL; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/** 21762306a36Sopenharmony_ci * tomoyo_print_ulong - Print an "unsigned long" value. 21862306a36Sopenharmony_ci * 21962306a36Sopenharmony_ci * @buffer: Pointer to buffer. 22062306a36Sopenharmony_ci * @buffer_len: Size of @buffer. 22162306a36Sopenharmony_ci * @value: An "unsigned long" value. 22262306a36Sopenharmony_ci * @type: Type of @value. 22362306a36Sopenharmony_ci * 22462306a36Sopenharmony_ci * Returns nothing. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_civoid tomoyo_print_ulong(char *buffer, const int buffer_len, 22762306a36Sopenharmony_ci const unsigned long value, const u8 type) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci if (type == TOMOYO_VALUE_TYPE_DECIMAL) 23062306a36Sopenharmony_ci snprintf(buffer, buffer_len, "%lu", value); 23162306a36Sopenharmony_ci else if (type == TOMOYO_VALUE_TYPE_OCTAL) 23262306a36Sopenharmony_ci snprintf(buffer, buffer_len, "0%lo", value); 23362306a36Sopenharmony_ci else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL) 23462306a36Sopenharmony_ci snprintf(buffer, buffer_len, "0x%lX", value); 23562306a36Sopenharmony_ci else 23662306a36Sopenharmony_ci snprintf(buffer, buffer_len, "type(%u)", type); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/** 24062306a36Sopenharmony_ci * tomoyo_parse_name_union - Parse a tomoyo_name_union. 24162306a36Sopenharmony_ci * 24262306a36Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param". 24362306a36Sopenharmony_ci * @ptr: Pointer to "struct tomoyo_name_union". 24462306a36Sopenharmony_ci * 24562306a36Sopenharmony_ci * Returns true on success, false otherwise. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_cibool tomoyo_parse_name_union(struct tomoyo_acl_param *param, 24862306a36Sopenharmony_ci struct tomoyo_name_union *ptr) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci char *filename; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (param->data[0] == '@') { 25362306a36Sopenharmony_ci param->data++; 25462306a36Sopenharmony_ci ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP); 25562306a36Sopenharmony_ci return ptr->group != NULL; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci filename = tomoyo_read_token(param); 25862306a36Sopenharmony_ci if (!tomoyo_correct_word(filename)) 25962306a36Sopenharmony_ci return false; 26062306a36Sopenharmony_ci ptr->filename = tomoyo_get_name(filename); 26162306a36Sopenharmony_ci return ptr->filename != NULL; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/** 26562306a36Sopenharmony_ci * tomoyo_parse_number_union - Parse a tomoyo_number_union. 26662306a36Sopenharmony_ci * 26762306a36Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param". 26862306a36Sopenharmony_ci * @ptr: Pointer to "struct tomoyo_number_union". 26962306a36Sopenharmony_ci * 27062306a36Sopenharmony_ci * Returns true on success, false otherwise. 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_cibool tomoyo_parse_number_union(struct tomoyo_acl_param *param, 27362306a36Sopenharmony_ci struct tomoyo_number_union *ptr) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci char *data; 27662306a36Sopenharmony_ci u8 type; 27762306a36Sopenharmony_ci unsigned long v; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci memset(ptr, 0, sizeof(*ptr)); 28062306a36Sopenharmony_ci if (param->data[0] == '@') { 28162306a36Sopenharmony_ci param->data++; 28262306a36Sopenharmony_ci ptr->group = tomoyo_get_group(param, TOMOYO_NUMBER_GROUP); 28362306a36Sopenharmony_ci return ptr->group != NULL; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci data = tomoyo_read_token(param); 28662306a36Sopenharmony_ci type = tomoyo_parse_ulong(&v, &data); 28762306a36Sopenharmony_ci if (type == TOMOYO_VALUE_TYPE_INVALID) 28862306a36Sopenharmony_ci return false; 28962306a36Sopenharmony_ci ptr->values[0] = v; 29062306a36Sopenharmony_ci ptr->value_type[0] = type; 29162306a36Sopenharmony_ci if (!*data) { 29262306a36Sopenharmony_ci ptr->values[1] = v; 29362306a36Sopenharmony_ci ptr->value_type[1] = type; 29462306a36Sopenharmony_ci return true; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci if (*data++ != '-') 29762306a36Sopenharmony_ci return false; 29862306a36Sopenharmony_ci type = tomoyo_parse_ulong(&v, &data); 29962306a36Sopenharmony_ci if (type == TOMOYO_VALUE_TYPE_INVALID || *data || ptr->values[0] > v) 30062306a36Sopenharmony_ci return false; 30162306a36Sopenharmony_ci ptr->values[1] = v; 30262306a36Sopenharmony_ci ptr->value_type[1] = type; 30362306a36Sopenharmony_ci return true; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/** 30762306a36Sopenharmony_ci * tomoyo_byte_range - Check whether the string is a \ooo style octal value. 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * @str: Pointer to the string. 31062306a36Sopenharmony_ci * 31162306a36Sopenharmony_ci * Returns true if @str is a \ooo style octal value, false otherwise. 31262306a36Sopenharmony_ci * 31362306a36Sopenharmony_ci * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF. 31462306a36Sopenharmony_ci * This function verifies that \ooo is in valid range. 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_cistatic inline bool tomoyo_byte_range(const char *str) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci return *str >= '0' && *str++ <= '3' && 31962306a36Sopenharmony_ci *str >= '0' && *str++ <= '7' && 32062306a36Sopenharmony_ci *str >= '0' && *str <= '7'; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci/** 32462306a36Sopenharmony_ci * tomoyo_alphabet_char - Check whether the character is an alphabet. 32562306a36Sopenharmony_ci * 32662306a36Sopenharmony_ci * @c: The character to check. 32762306a36Sopenharmony_ci * 32862306a36Sopenharmony_ci * Returns true if @c is an alphabet character, false otherwise. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_cistatic inline bool tomoyo_alphabet_char(const char c) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci/** 33662306a36Sopenharmony_ci * tomoyo_make_byte - Make byte value from three octal characters. 33762306a36Sopenharmony_ci * 33862306a36Sopenharmony_ci * @c1: The first character. 33962306a36Sopenharmony_ci * @c2: The second character. 34062306a36Sopenharmony_ci * @c3: The third character. 34162306a36Sopenharmony_ci * 34262306a36Sopenharmony_ci * Returns byte value. 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_cistatic inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0'); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/** 35062306a36Sopenharmony_ci * tomoyo_valid - Check whether the character is a valid char. 35162306a36Sopenharmony_ci * 35262306a36Sopenharmony_ci * @c: The character to check. 35362306a36Sopenharmony_ci * 35462306a36Sopenharmony_ci * Returns true if @c is a valid character, false otherwise. 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_cistatic inline bool tomoyo_valid(const unsigned char c) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci return c > ' ' && c < 127; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci/** 36262306a36Sopenharmony_ci * tomoyo_invalid - Check whether the character is an invalid char. 36362306a36Sopenharmony_ci * 36462306a36Sopenharmony_ci * @c: The character to check. 36562306a36Sopenharmony_ci * 36662306a36Sopenharmony_ci * Returns true if @c is an invalid character, false otherwise. 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_cistatic inline bool tomoyo_invalid(const unsigned char c) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci return c && (c <= ' ' || c >= 127); 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci/** 37462306a36Sopenharmony_ci * tomoyo_str_starts - Check whether the given string starts with the given keyword. 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * @src: Pointer to pointer to the string. 37762306a36Sopenharmony_ci * @find: Pointer to the keyword. 37862306a36Sopenharmony_ci * 37962306a36Sopenharmony_ci * Returns true if @src starts with @find, false otherwise. 38062306a36Sopenharmony_ci * 38162306a36Sopenharmony_ci * The @src is updated to point the first character after the @find 38262306a36Sopenharmony_ci * if @src starts with @find. 38362306a36Sopenharmony_ci */ 38462306a36Sopenharmony_cibool tomoyo_str_starts(char **src, const char *find) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci const int len = strlen(find); 38762306a36Sopenharmony_ci char *tmp = *src; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (strncmp(tmp, find, len)) 39062306a36Sopenharmony_ci return false; 39162306a36Sopenharmony_ci tmp += len; 39262306a36Sopenharmony_ci *src = tmp; 39362306a36Sopenharmony_ci return true; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/** 39762306a36Sopenharmony_ci * tomoyo_normalize_line - Format string. 39862306a36Sopenharmony_ci * 39962306a36Sopenharmony_ci * @buffer: The line to normalize. 40062306a36Sopenharmony_ci * 40162306a36Sopenharmony_ci * Leading and trailing whitespaces are removed. 40262306a36Sopenharmony_ci * Multiple whitespaces are packed into single space. 40362306a36Sopenharmony_ci * 40462306a36Sopenharmony_ci * Returns nothing. 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_civoid tomoyo_normalize_line(unsigned char *buffer) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci unsigned char *sp = buffer; 40962306a36Sopenharmony_ci unsigned char *dp = buffer; 41062306a36Sopenharmony_ci bool first = true; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci while (tomoyo_invalid(*sp)) 41362306a36Sopenharmony_ci sp++; 41462306a36Sopenharmony_ci while (*sp) { 41562306a36Sopenharmony_ci if (!first) 41662306a36Sopenharmony_ci *dp++ = ' '; 41762306a36Sopenharmony_ci first = false; 41862306a36Sopenharmony_ci while (tomoyo_valid(*sp)) 41962306a36Sopenharmony_ci *dp++ = *sp++; 42062306a36Sopenharmony_ci while (tomoyo_invalid(*sp)) 42162306a36Sopenharmony_ci sp++; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci *dp = '\0'; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci/** 42762306a36Sopenharmony_ci * tomoyo_correct_word2 - Validate a string. 42862306a36Sopenharmony_ci * 42962306a36Sopenharmony_ci * @string: The string to check. Maybe non-'\0'-terminated. 43062306a36Sopenharmony_ci * @len: Length of @string. 43162306a36Sopenharmony_ci * 43262306a36Sopenharmony_ci * Check whether the given string follows the naming rules. 43362306a36Sopenharmony_ci * Returns true if @string follows the naming rules, false otherwise. 43462306a36Sopenharmony_ci */ 43562306a36Sopenharmony_cistatic bool tomoyo_correct_word2(const char *string, size_t len) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci u8 recursion = 20; 43862306a36Sopenharmony_ci const char *const start = string; 43962306a36Sopenharmony_ci bool in_repetition = false; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (!len) 44262306a36Sopenharmony_ci goto out; 44362306a36Sopenharmony_ci while (len--) { 44462306a36Sopenharmony_ci unsigned char c = *string++; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (c == '\\') { 44762306a36Sopenharmony_ci if (!len--) 44862306a36Sopenharmony_ci goto out; 44962306a36Sopenharmony_ci c = *string++; 45062306a36Sopenharmony_ci if (c >= '0' && c <= '3') { 45162306a36Sopenharmony_ci unsigned char d; 45262306a36Sopenharmony_ci unsigned char e; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (!len-- || !len--) 45562306a36Sopenharmony_ci goto out; 45662306a36Sopenharmony_ci d = *string++; 45762306a36Sopenharmony_ci e = *string++; 45862306a36Sopenharmony_ci if (d < '0' || d > '7' || e < '0' || e > '7') 45962306a36Sopenharmony_ci goto out; 46062306a36Sopenharmony_ci c = tomoyo_make_byte(c, d, e); 46162306a36Sopenharmony_ci if (c <= ' ' || c >= 127) 46262306a36Sopenharmony_ci continue; 46362306a36Sopenharmony_ci goto out; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci switch (c) { 46662306a36Sopenharmony_ci case '\\': /* "\\" */ 46762306a36Sopenharmony_ci case '+': /* "\+" */ 46862306a36Sopenharmony_ci case '?': /* "\?" */ 46962306a36Sopenharmony_ci case 'x': /* "\x" */ 47062306a36Sopenharmony_ci case 'a': /* "\a" */ 47162306a36Sopenharmony_ci case '-': /* "\-" */ 47262306a36Sopenharmony_ci continue; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci if (!recursion--) 47562306a36Sopenharmony_ci goto out; 47662306a36Sopenharmony_ci switch (c) { 47762306a36Sopenharmony_ci case '*': /* "\*" */ 47862306a36Sopenharmony_ci case '@': /* "\@" */ 47962306a36Sopenharmony_ci case '$': /* "\$" */ 48062306a36Sopenharmony_ci case 'X': /* "\X" */ 48162306a36Sopenharmony_ci case 'A': /* "\A" */ 48262306a36Sopenharmony_ci continue; 48362306a36Sopenharmony_ci case '{': /* "/\{" */ 48462306a36Sopenharmony_ci if (string - 3 < start || *(string - 3) != '/') 48562306a36Sopenharmony_ci goto out; 48662306a36Sopenharmony_ci in_repetition = true; 48762306a36Sopenharmony_ci continue; 48862306a36Sopenharmony_ci case '}': /* "\}/" */ 48962306a36Sopenharmony_ci if (*string != '/') 49062306a36Sopenharmony_ci goto out; 49162306a36Sopenharmony_ci if (!in_repetition) 49262306a36Sopenharmony_ci goto out; 49362306a36Sopenharmony_ci in_repetition = false; 49462306a36Sopenharmony_ci continue; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci goto out; 49762306a36Sopenharmony_ci } else if (in_repetition && c == '/') { 49862306a36Sopenharmony_ci goto out; 49962306a36Sopenharmony_ci } else if (c <= ' ' || c >= 127) { 50062306a36Sopenharmony_ci goto out; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci if (in_repetition) 50462306a36Sopenharmony_ci goto out; 50562306a36Sopenharmony_ci return true; 50662306a36Sopenharmony_ci out: 50762306a36Sopenharmony_ci return false; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci/** 51162306a36Sopenharmony_ci * tomoyo_correct_word - Validate a string. 51262306a36Sopenharmony_ci * 51362306a36Sopenharmony_ci * @string: The string to check. 51462306a36Sopenharmony_ci * 51562306a36Sopenharmony_ci * Check whether the given string follows the naming rules. 51662306a36Sopenharmony_ci * Returns true if @string follows the naming rules, false otherwise. 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_cibool tomoyo_correct_word(const char *string) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci return tomoyo_correct_word2(string, strlen(string)); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci/** 52462306a36Sopenharmony_ci * tomoyo_correct_path2 - Check whether the given pathname follows the naming rules. 52562306a36Sopenharmony_ci * 52662306a36Sopenharmony_ci * @filename: The pathname to check. 52762306a36Sopenharmony_ci * @len: Length of @filename. 52862306a36Sopenharmony_ci * 52962306a36Sopenharmony_ci * Returns true if @filename follows the naming rules, false otherwise. 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_cistatic bool tomoyo_correct_path2(const char *filename, const size_t len) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci const char *cp1 = memchr(filename, '/', len); 53462306a36Sopenharmony_ci const char *cp2 = memchr(filename, '.', len); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return cp1 && (!cp2 || (cp1 < cp2)) && tomoyo_correct_word2(filename, len); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci/** 54062306a36Sopenharmony_ci * tomoyo_correct_path - Validate a pathname. 54162306a36Sopenharmony_ci * 54262306a36Sopenharmony_ci * @filename: The pathname to check. 54362306a36Sopenharmony_ci * 54462306a36Sopenharmony_ci * Check whether the given pathname follows the naming rules. 54562306a36Sopenharmony_ci * Returns true if @filename follows the naming rules, false otherwise. 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_cibool tomoyo_correct_path(const char *filename) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci return tomoyo_correct_path2(filename, strlen(filename)); 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci/** 55362306a36Sopenharmony_ci * tomoyo_correct_domain - Check whether the given domainname follows the naming rules. 55462306a36Sopenharmony_ci * 55562306a36Sopenharmony_ci * @domainname: The domainname to check. 55662306a36Sopenharmony_ci * 55762306a36Sopenharmony_ci * Returns true if @domainname follows the naming rules, false otherwise. 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_cibool tomoyo_correct_domain(const unsigned char *domainname) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci if (!domainname || !tomoyo_domain_def(domainname)) 56262306a36Sopenharmony_ci return false; 56362306a36Sopenharmony_ci domainname = strchr(domainname, ' '); 56462306a36Sopenharmony_ci if (!domainname++) 56562306a36Sopenharmony_ci return true; 56662306a36Sopenharmony_ci while (1) { 56762306a36Sopenharmony_ci const unsigned char *cp = strchr(domainname, ' '); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (!cp) 57062306a36Sopenharmony_ci break; 57162306a36Sopenharmony_ci if (!tomoyo_correct_path2(domainname, cp - domainname)) 57262306a36Sopenharmony_ci return false; 57362306a36Sopenharmony_ci domainname = cp + 1; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci return tomoyo_correct_path(domainname); 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci/** 57962306a36Sopenharmony_ci * tomoyo_domain_def - Check whether the given token can be a domainname. 58062306a36Sopenharmony_ci * 58162306a36Sopenharmony_ci * @buffer: The token to check. 58262306a36Sopenharmony_ci * 58362306a36Sopenharmony_ci * Returns true if @buffer possibly be a domainname, false otherwise. 58462306a36Sopenharmony_ci */ 58562306a36Sopenharmony_cibool tomoyo_domain_def(const unsigned char *buffer) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci const unsigned char *cp; 58862306a36Sopenharmony_ci int len; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (*buffer != '<') 59162306a36Sopenharmony_ci return false; 59262306a36Sopenharmony_ci cp = strchr(buffer, ' '); 59362306a36Sopenharmony_ci if (!cp) 59462306a36Sopenharmony_ci len = strlen(buffer); 59562306a36Sopenharmony_ci else 59662306a36Sopenharmony_ci len = cp - buffer; 59762306a36Sopenharmony_ci if (buffer[len - 1] != '>' || 59862306a36Sopenharmony_ci !tomoyo_correct_word2(buffer + 1, len - 2)) 59962306a36Sopenharmony_ci return false; 60062306a36Sopenharmony_ci return true; 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci/** 60462306a36Sopenharmony_ci * tomoyo_find_domain - Find a domain by the given name. 60562306a36Sopenharmony_ci * 60662306a36Sopenharmony_ci * @domainname: The domainname to find. 60762306a36Sopenharmony_ci * 60862306a36Sopenharmony_ci * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. 60962306a36Sopenharmony_ci * 61062306a36Sopenharmony_ci * Caller holds tomoyo_read_lock(). 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_cistruct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct tomoyo_domain_info *domain; 61562306a36Sopenharmony_ci struct tomoyo_path_info name; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci name.name = domainname; 61862306a36Sopenharmony_ci tomoyo_fill_path_info(&name); 61962306a36Sopenharmony_ci list_for_each_entry_rcu(domain, &tomoyo_domain_list, list, 62062306a36Sopenharmony_ci srcu_read_lock_held(&tomoyo_ss)) { 62162306a36Sopenharmony_ci if (!domain->is_deleted && 62262306a36Sopenharmony_ci !tomoyo_pathcmp(&name, domain->domainname)) 62362306a36Sopenharmony_ci return domain; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci return NULL; 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci/** 62962306a36Sopenharmony_ci * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token. 63062306a36Sopenharmony_ci * 63162306a36Sopenharmony_ci * @filename: The string to evaluate. 63262306a36Sopenharmony_ci * 63362306a36Sopenharmony_ci * Returns the initial length without a pattern in @filename. 63462306a36Sopenharmony_ci */ 63562306a36Sopenharmony_cistatic int tomoyo_const_part_length(const char *filename) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci char c; 63862306a36Sopenharmony_ci int len = 0; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (!filename) 64162306a36Sopenharmony_ci return 0; 64262306a36Sopenharmony_ci while ((c = *filename++) != '\0') { 64362306a36Sopenharmony_ci if (c != '\\') { 64462306a36Sopenharmony_ci len++; 64562306a36Sopenharmony_ci continue; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci c = *filename++; 64862306a36Sopenharmony_ci switch (c) { 64962306a36Sopenharmony_ci case '\\': /* "\\" */ 65062306a36Sopenharmony_ci len += 2; 65162306a36Sopenharmony_ci continue; 65262306a36Sopenharmony_ci case '0': /* "\ooo" */ 65362306a36Sopenharmony_ci case '1': 65462306a36Sopenharmony_ci case '2': 65562306a36Sopenharmony_ci case '3': 65662306a36Sopenharmony_ci c = *filename++; 65762306a36Sopenharmony_ci if (c < '0' || c > '7') 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci c = *filename++; 66062306a36Sopenharmony_ci if (c < '0' || c > '7') 66162306a36Sopenharmony_ci break; 66262306a36Sopenharmony_ci len += 4; 66362306a36Sopenharmony_ci continue; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci break; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci return len; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci/** 67162306a36Sopenharmony_ci * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members. 67262306a36Sopenharmony_ci * 67362306a36Sopenharmony_ci * @ptr: Pointer to "struct tomoyo_path_info" to fill in. 67462306a36Sopenharmony_ci * 67562306a36Sopenharmony_ci * The caller sets "struct tomoyo_path_info"->name. 67662306a36Sopenharmony_ci */ 67762306a36Sopenharmony_civoid tomoyo_fill_path_info(struct tomoyo_path_info *ptr) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci const char *name = ptr->name; 68062306a36Sopenharmony_ci const int len = strlen(name); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci ptr->const_len = tomoyo_const_part_length(name); 68362306a36Sopenharmony_ci ptr->is_dir = len && (name[len - 1] == '/'); 68462306a36Sopenharmony_ci ptr->is_patterned = (ptr->const_len < len); 68562306a36Sopenharmony_ci ptr->hash = full_name_hash(NULL, name, len); 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci/** 68962306a36Sopenharmony_ci * tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern. 69062306a36Sopenharmony_ci * 69162306a36Sopenharmony_ci * @filename: The start of string to check. 69262306a36Sopenharmony_ci * @filename_end: The end of string to check. 69362306a36Sopenharmony_ci * @pattern: The start of pattern to compare. 69462306a36Sopenharmony_ci * @pattern_end: The end of pattern to compare. 69562306a36Sopenharmony_ci * 69662306a36Sopenharmony_ci * Returns true if @filename matches @pattern, false otherwise. 69762306a36Sopenharmony_ci */ 69862306a36Sopenharmony_cistatic bool tomoyo_file_matches_pattern2(const char *filename, 69962306a36Sopenharmony_ci const char *filename_end, 70062306a36Sopenharmony_ci const char *pattern, 70162306a36Sopenharmony_ci const char *pattern_end) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci while (filename < filename_end && pattern < pattern_end) { 70462306a36Sopenharmony_ci char c; 70562306a36Sopenharmony_ci int i; 70662306a36Sopenharmony_ci int j; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci if (*pattern != '\\') { 70962306a36Sopenharmony_ci if (*filename++ != *pattern++) 71062306a36Sopenharmony_ci return false; 71162306a36Sopenharmony_ci continue; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci c = *filename; 71462306a36Sopenharmony_ci pattern++; 71562306a36Sopenharmony_ci switch (*pattern) { 71662306a36Sopenharmony_ci case '?': 71762306a36Sopenharmony_ci if (c == '/') { 71862306a36Sopenharmony_ci return false; 71962306a36Sopenharmony_ci } else if (c == '\\') { 72062306a36Sopenharmony_ci if (filename[1] == '\\') 72162306a36Sopenharmony_ci filename++; 72262306a36Sopenharmony_ci else if (tomoyo_byte_range(filename + 1)) 72362306a36Sopenharmony_ci filename += 3; 72462306a36Sopenharmony_ci else 72562306a36Sopenharmony_ci return false; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci break; 72862306a36Sopenharmony_ci case '\\': 72962306a36Sopenharmony_ci if (c != '\\') 73062306a36Sopenharmony_ci return false; 73162306a36Sopenharmony_ci if (*++filename != '\\') 73262306a36Sopenharmony_ci return false; 73362306a36Sopenharmony_ci break; 73462306a36Sopenharmony_ci case '+': 73562306a36Sopenharmony_ci if (!isdigit(c)) 73662306a36Sopenharmony_ci return false; 73762306a36Sopenharmony_ci break; 73862306a36Sopenharmony_ci case 'x': 73962306a36Sopenharmony_ci if (!isxdigit(c)) 74062306a36Sopenharmony_ci return false; 74162306a36Sopenharmony_ci break; 74262306a36Sopenharmony_ci case 'a': 74362306a36Sopenharmony_ci if (!tomoyo_alphabet_char(c)) 74462306a36Sopenharmony_ci return false; 74562306a36Sopenharmony_ci break; 74662306a36Sopenharmony_ci case '0': 74762306a36Sopenharmony_ci case '1': 74862306a36Sopenharmony_ci case '2': 74962306a36Sopenharmony_ci case '3': 75062306a36Sopenharmony_ci if (c == '\\' && tomoyo_byte_range(filename + 1) 75162306a36Sopenharmony_ci && strncmp(filename + 1, pattern, 3) == 0) { 75262306a36Sopenharmony_ci filename += 3; 75362306a36Sopenharmony_ci pattern += 2; 75462306a36Sopenharmony_ci break; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci return false; /* Not matched. */ 75762306a36Sopenharmony_ci case '*': 75862306a36Sopenharmony_ci case '@': 75962306a36Sopenharmony_ci for (i = 0; i <= filename_end - filename; i++) { 76062306a36Sopenharmony_ci if (tomoyo_file_matches_pattern2( 76162306a36Sopenharmony_ci filename + i, filename_end, 76262306a36Sopenharmony_ci pattern + 1, pattern_end)) 76362306a36Sopenharmony_ci return true; 76462306a36Sopenharmony_ci c = filename[i]; 76562306a36Sopenharmony_ci if (c == '.' && *pattern == '@') 76662306a36Sopenharmony_ci break; 76762306a36Sopenharmony_ci if (c != '\\') 76862306a36Sopenharmony_ci continue; 76962306a36Sopenharmony_ci if (filename[i + 1] == '\\') 77062306a36Sopenharmony_ci i++; 77162306a36Sopenharmony_ci else if (tomoyo_byte_range(filename + i + 1)) 77262306a36Sopenharmony_ci i += 3; 77362306a36Sopenharmony_ci else 77462306a36Sopenharmony_ci break; /* Bad pattern. */ 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci return false; /* Not matched. */ 77762306a36Sopenharmony_ci default: 77862306a36Sopenharmony_ci j = 0; 77962306a36Sopenharmony_ci c = *pattern; 78062306a36Sopenharmony_ci if (c == '$') { 78162306a36Sopenharmony_ci while (isdigit(filename[j])) 78262306a36Sopenharmony_ci j++; 78362306a36Sopenharmony_ci } else if (c == 'X') { 78462306a36Sopenharmony_ci while (isxdigit(filename[j])) 78562306a36Sopenharmony_ci j++; 78662306a36Sopenharmony_ci } else if (c == 'A') { 78762306a36Sopenharmony_ci while (tomoyo_alphabet_char(filename[j])) 78862306a36Sopenharmony_ci j++; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci for (i = 1; i <= j; i++) { 79162306a36Sopenharmony_ci if (tomoyo_file_matches_pattern2( 79262306a36Sopenharmony_ci filename + i, filename_end, 79362306a36Sopenharmony_ci pattern + 1, pattern_end)) 79462306a36Sopenharmony_ci return true; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci return false; /* Not matched or bad pattern. */ 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci filename++; 79962306a36Sopenharmony_ci pattern++; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci while (*pattern == '\\' && 80262306a36Sopenharmony_ci (*(pattern + 1) == '*' || *(pattern + 1) == '@')) 80362306a36Sopenharmony_ci pattern += 2; 80462306a36Sopenharmony_ci return filename == filename_end && pattern == pattern_end; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci/** 80862306a36Sopenharmony_ci * tomoyo_file_matches_pattern - Pattern matching without '/' character. 80962306a36Sopenharmony_ci * 81062306a36Sopenharmony_ci * @filename: The start of string to check. 81162306a36Sopenharmony_ci * @filename_end: The end of string to check. 81262306a36Sopenharmony_ci * @pattern: The start of pattern to compare. 81362306a36Sopenharmony_ci * @pattern_end: The end of pattern to compare. 81462306a36Sopenharmony_ci * 81562306a36Sopenharmony_ci * Returns true if @filename matches @pattern, false otherwise. 81662306a36Sopenharmony_ci */ 81762306a36Sopenharmony_cistatic bool tomoyo_file_matches_pattern(const char *filename, 81862306a36Sopenharmony_ci const char *filename_end, 81962306a36Sopenharmony_ci const char *pattern, 82062306a36Sopenharmony_ci const char *pattern_end) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci const char *pattern_start = pattern; 82362306a36Sopenharmony_ci bool first = true; 82462306a36Sopenharmony_ci bool result; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci while (pattern < pattern_end - 1) { 82762306a36Sopenharmony_ci /* Split at "\-" pattern. */ 82862306a36Sopenharmony_ci if (*pattern++ != '\\' || *pattern++ != '-') 82962306a36Sopenharmony_ci continue; 83062306a36Sopenharmony_ci result = tomoyo_file_matches_pattern2(filename, 83162306a36Sopenharmony_ci filename_end, 83262306a36Sopenharmony_ci pattern_start, 83362306a36Sopenharmony_ci pattern - 2); 83462306a36Sopenharmony_ci if (first) 83562306a36Sopenharmony_ci result = !result; 83662306a36Sopenharmony_ci if (result) 83762306a36Sopenharmony_ci return false; 83862306a36Sopenharmony_ci first = false; 83962306a36Sopenharmony_ci pattern_start = pattern; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci result = tomoyo_file_matches_pattern2(filename, filename_end, 84262306a36Sopenharmony_ci pattern_start, pattern_end); 84362306a36Sopenharmony_ci return first ? result : !result; 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci/** 84762306a36Sopenharmony_ci * tomoyo_path_matches_pattern2 - Do pathname pattern matching. 84862306a36Sopenharmony_ci * 84962306a36Sopenharmony_ci * @f: The start of string to check. 85062306a36Sopenharmony_ci * @p: The start of pattern to compare. 85162306a36Sopenharmony_ci * 85262306a36Sopenharmony_ci * Returns true if @f matches @p, false otherwise. 85362306a36Sopenharmony_ci */ 85462306a36Sopenharmony_cistatic bool tomoyo_path_matches_pattern2(const char *f, const char *p) 85562306a36Sopenharmony_ci{ 85662306a36Sopenharmony_ci const char *f_delimiter; 85762306a36Sopenharmony_ci const char *p_delimiter; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci while (*f && *p) { 86062306a36Sopenharmony_ci f_delimiter = strchr(f, '/'); 86162306a36Sopenharmony_ci if (!f_delimiter) 86262306a36Sopenharmony_ci f_delimiter = f + strlen(f); 86362306a36Sopenharmony_ci p_delimiter = strchr(p, '/'); 86462306a36Sopenharmony_ci if (!p_delimiter) 86562306a36Sopenharmony_ci p_delimiter = p + strlen(p); 86662306a36Sopenharmony_ci if (*p == '\\' && *(p + 1) == '{') 86762306a36Sopenharmony_ci goto recursive; 86862306a36Sopenharmony_ci if (!tomoyo_file_matches_pattern(f, f_delimiter, p, 86962306a36Sopenharmony_ci p_delimiter)) 87062306a36Sopenharmony_ci return false; 87162306a36Sopenharmony_ci f = f_delimiter; 87262306a36Sopenharmony_ci if (*f) 87362306a36Sopenharmony_ci f++; 87462306a36Sopenharmony_ci p = p_delimiter; 87562306a36Sopenharmony_ci if (*p) 87662306a36Sopenharmony_ci p++; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci /* Ignore trailing "\*" and "\@" in @pattern. */ 87962306a36Sopenharmony_ci while (*p == '\\' && 88062306a36Sopenharmony_ci (*(p + 1) == '*' || *(p + 1) == '@')) 88162306a36Sopenharmony_ci p += 2; 88262306a36Sopenharmony_ci return !*f && !*p; 88362306a36Sopenharmony_ci recursive: 88462306a36Sopenharmony_ci /* 88562306a36Sopenharmony_ci * The "\{" pattern is permitted only after '/' character. 88662306a36Sopenharmony_ci * This guarantees that below "*(p - 1)" is safe. 88762306a36Sopenharmony_ci * Also, the "\}" pattern is permitted only before '/' character 88862306a36Sopenharmony_ci * so that "\{" + "\}" pair will not break the "\-" operator. 88962306a36Sopenharmony_ci */ 89062306a36Sopenharmony_ci if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' || 89162306a36Sopenharmony_ci *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\') 89262306a36Sopenharmony_ci return false; /* Bad pattern. */ 89362306a36Sopenharmony_ci do { 89462306a36Sopenharmony_ci /* Compare current component with pattern. */ 89562306a36Sopenharmony_ci if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2, 89662306a36Sopenharmony_ci p_delimiter - 2)) 89762306a36Sopenharmony_ci break; 89862306a36Sopenharmony_ci /* Proceed to next component. */ 89962306a36Sopenharmony_ci f = f_delimiter; 90062306a36Sopenharmony_ci if (!*f) 90162306a36Sopenharmony_ci break; 90262306a36Sopenharmony_ci f++; 90362306a36Sopenharmony_ci /* Continue comparison. */ 90462306a36Sopenharmony_ci if (tomoyo_path_matches_pattern2(f, p_delimiter + 1)) 90562306a36Sopenharmony_ci return true; 90662306a36Sopenharmony_ci f_delimiter = strchr(f, '/'); 90762306a36Sopenharmony_ci } while (f_delimiter); 90862306a36Sopenharmony_ci return false; /* Not matched. */ 90962306a36Sopenharmony_ci} 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci/** 91262306a36Sopenharmony_ci * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern. 91362306a36Sopenharmony_ci * 91462306a36Sopenharmony_ci * @filename: The filename to check. 91562306a36Sopenharmony_ci * @pattern: The pattern to compare. 91662306a36Sopenharmony_ci * 91762306a36Sopenharmony_ci * Returns true if matches, false otherwise. 91862306a36Sopenharmony_ci * 91962306a36Sopenharmony_ci * The following patterns are available. 92062306a36Sopenharmony_ci * \\ \ itself. 92162306a36Sopenharmony_ci * \ooo Octal representation of a byte. 92262306a36Sopenharmony_ci * \* Zero or more repetitions of characters other than '/'. 92362306a36Sopenharmony_ci * \@ Zero or more repetitions of characters other than '/' or '.'. 92462306a36Sopenharmony_ci * \? 1 byte character other than '/'. 92562306a36Sopenharmony_ci * \$ One or more repetitions of decimal digits. 92662306a36Sopenharmony_ci * \+ 1 decimal digit. 92762306a36Sopenharmony_ci * \X One or more repetitions of hexadecimal digits. 92862306a36Sopenharmony_ci * \x 1 hexadecimal digit. 92962306a36Sopenharmony_ci * \A One or more repetitions of alphabet characters. 93062306a36Sopenharmony_ci * \a 1 alphabet character. 93162306a36Sopenharmony_ci * 93262306a36Sopenharmony_ci * \- Subtraction operator. 93362306a36Sopenharmony_ci * 93462306a36Sopenharmony_ci * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/ 93562306a36Sopenharmony_ci * /dir/dir/dir/ ). 93662306a36Sopenharmony_ci */ 93762306a36Sopenharmony_cibool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, 93862306a36Sopenharmony_ci const struct tomoyo_path_info *pattern) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci const char *f = filename->name; 94162306a36Sopenharmony_ci const char *p = pattern->name; 94262306a36Sopenharmony_ci const int len = pattern->const_len; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci /* If @pattern doesn't contain pattern, I can use strcmp(). */ 94562306a36Sopenharmony_ci if (!pattern->is_patterned) 94662306a36Sopenharmony_ci return !tomoyo_pathcmp(filename, pattern); 94762306a36Sopenharmony_ci /* Don't compare directory and non-directory. */ 94862306a36Sopenharmony_ci if (filename->is_dir != pattern->is_dir) 94962306a36Sopenharmony_ci return false; 95062306a36Sopenharmony_ci /* Compare the initial length without patterns. */ 95162306a36Sopenharmony_ci if (strncmp(f, p, len)) 95262306a36Sopenharmony_ci return false; 95362306a36Sopenharmony_ci f += len; 95462306a36Sopenharmony_ci p += len; 95562306a36Sopenharmony_ci return tomoyo_path_matches_pattern2(f, p); 95662306a36Sopenharmony_ci} 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci/** 95962306a36Sopenharmony_ci * tomoyo_get_exe - Get tomoyo_realpath() of current process. 96062306a36Sopenharmony_ci * 96162306a36Sopenharmony_ci * Returns the tomoyo_realpath() of current process on success, NULL otherwise. 96262306a36Sopenharmony_ci * 96362306a36Sopenharmony_ci * This function uses kzalloc(), so the caller must call kfree() 96462306a36Sopenharmony_ci * if this function didn't return NULL. 96562306a36Sopenharmony_ci */ 96662306a36Sopenharmony_ciconst char *tomoyo_get_exe(void) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci struct file *exe_file; 96962306a36Sopenharmony_ci const char *cp; 97062306a36Sopenharmony_ci struct mm_struct *mm = current->mm; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (!mm) 97362306a36Sopenharmony_ci return NULL; 97462306a36Sopenharmony_ci exe_file = get_mm_exe_file(mm); 97562306a36Sopenharmony_ci if (!exe_file) 97662306a36Sopenharmony_ci return NULL; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci cp = tomoyo_realpath_from_path(&exe_file->f_path); 97962306a36Sopenharmony_ci fput(exe_file); 98062306a36Sopenharmony_ci return cp; 98162306a36Sopenharmony_ci} 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci/** 98462306a36Sopenharmony_ci * tomoyo_get_mode - Get MAC mode. 98562306a36Sopenharmony_ci * 98662306a36Sopenharmony_ci * @ns: Pointer to "struct tomoyo_policy_namespace". 98762306a36Sopenharmony_ci * @profile: Profile number. 98862306a36Sopenharmony_ci * @index: Index number of functionality. 98962306a36Sopenharmony_ci * 99062306a36Sopenharmony_ci * Returns mode. 99162306a36Sopenharmony_ci */ 99262306a36Sopenharmony_ciint tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile, 99362306a36Sopenharmony_ci const u8 index) 99462306a36Sopenharmony_ci{ 99562306a36Sopenharmony_ci u8 mode; 99662306a36Sopenharmony_ci struct tomoyo_profile *p; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci if (!tomoyo_policy_loaded) 99962306a36Sopenharmony_ci return TOMOYO_CONFIG_DISABLED; 100062306a36Sopenharmony_ci p = tomoyo_profile(ns, profile); 100162306a36Sopenharmony_ci mode = p->config[index]; 100262306a36Sopenharmony_ci if (mode == TOMOYO_CONFIG_USE_DEFAULT) 100362306a36Sopenharmony_ci mode = p->config[tomoyo_index2category[index] 100462306a36Sopenharmony_ci + TOMOYO_MAX_MAC_INDEX]; 100562306a36Sopenharmony_ci if (mode == TOMOYO_CONFIG_USE_DEFAULT) 100662306a36Sopenharmony_ci mode = p->default_config; 100762306a36Sopenharmony_ci return mode & 3; 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci/** 101162306a36Sopenharmony_ci * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members. 101262306a36Sopenharmony_ci * 101362306a36Sopenharmony_ci * @r: Pointer to "struct tomoyo_request_info" to initialize. 101462306a36Sopenharmony_ci * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain(). 101562306a36Sopenharmony_ci * @index: Index number of functionality. 101662306a36Sopenharmony_ci * 101762306a36Sopenharmony_ci * Returns mode. 101862306a36Sopenharmony_ci */ 101962306a36Sopenharmony_ciint tomoyo_init_request_info(struct tomoyo_request_info *r, 102062306a36Sopenharmony_ci struct tomoyo_domain_info *domain, const u8 index) 102162306a36Sopenharmony_ci{ 102262306a36Sopenharmony_ci u8 profile; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci memset(r, 0, sizeof(*r)); 102562306a36Sopenharmony_ci if (!domain) 102662306a36Sopenharmony_ci domain = tomoyo_domain(); 102762306a36Sopenharmony_ci r->domain = domain; 102862306a36Sopenharmony_ci profile = domain->profile; 102962306a36Sopenharmony_ci r->profile = profile; 103062306a36Sopenharmony_ci r->type = index; 103162306a36Sopenharmony_ci r->mode = tomoyo_get_mode(domain->ns, profile, index); 103262306a36Sopenharmony_ci return r->mode; 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci/** 103662306a36Sopenharmony_ci * tomoyo_domain_quota_is_ok - Check for domain's quota. 103762306a36Sopenharmony_ci * 103862306a36Sopenharmony_ci * @r: Pointer to "struct tomoyo_request_info". 103962306a36Sopenharmony_ci * 104062306a36Sopenharmony_ci * Returns true if the domain is not exceeded quota, false otherwise. 104162306a36Sopenharmony_ci * 104262306a36Sopenharmony_ci * Caller holds tomoyo_read_lock(). 104362306a36Sopenharmony_ci */ 104462306a36Sopenharmony_cibool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) 104562306a36Sopenharmony_ci{ 104662306a36Sopenharmony_ci unsigned int count = 0; 104762306a36Sopenharmony_ci struct tomoyo_domain_info *domain = r->domain; 104862306a36Sopenharmony_ci struct tomoyo_acl_info *ptr; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci if (r->mode != TOMOYO_CONFIG_LEARNING) 105162306a36Sopenharmony_ci return false; 105262306a36Sopenharmony_ci if (!domain) 105362306a36Sopenharmony_ci return true; 105462306a36Sopenharmony_ci if (READ_ONCE(domain->flags[TOMOYO_DIF_QUOTA_WARNED])) 105562306a36Sopenharmony_ci return false; 105662306a36Sopenharmony_ci list_for_each_entry_rcu(ptr, &domain->acl_info_list, list, 105762306a36Sopenharmony_ci srcu_read_lock_held(&tomoyo_ss)) { 105862306a36Sopenharmony_ci u16 perm; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (ptr->is_deleted) 106162306a36Sopenharmony_ci continue; 106262306a36Sopenharmony_ci /* 106362306a36Sopenharmony_ci * Reading perm bitmap might race with tomoyo_merge_*() because 106462306a36Sopenharmony_ci * caller does not hold tomoyo_policy_lock mutex. But exceeding 106562306a36Sopenharmony_ci * max_learning_entry parameter by a few entries does not harm. 106662306a36Sopenharmony_ci */ 106762306a36Sopenharmony_ci switch (ptr->type) { 106862306a36Sopenharmony_ci case TOMOYO_TYPE_PATH_ACL: 106962306a36Sopenharmony_ci perm = data_race(container_of(ptr, struct tomoyo_path_acl, head)->perm); 107062306a36Sopenharmony_ci break; 107162306a36Sopenharmony_ci case TOMOYO_TYPE_PATH2_ACL: 107262306a36Sopenharmony_ci perm = data_race(container_of(ptr, struct tomoyo_path2_acl, head)->perm); 107362306a36Sopenharmony_ci break; 107462306a36Sopenharmony_ci case TOMOYO_TYPE_PATH_NUMBER_ACL: 107562306a36Sopenharmony_ci perm = data_race(container_of(ptr, struct tomoyo_path_number_acl, head) 107662306a36Sopenharmony_ci ->perm); 107762306a36Sopenharmony_ci break; 107862306a36Sopenharmony_ci case TOMOYO_TYPE_MKDEV_ACL: 107962306a36Sopenharmony_ci perm = data_race(container_of(ptr, struct tomoyo_mkdev_acl, head)->perm); 108062306a36Sopenharmony_ci break; 108162306a36Sopenharmony_ci case TOMOYO_TYPE_INET_ACL: 108262306a36Sopenharmony_ci perm = data_race(container_of(ptr, struct tomoyo_inet_acl, head)->perm); 108362306a36Sopenharmony_ci break; 108462306a36Sopenharmony_ci case TOMOYO_TYPE_UNIX_ACL: 108562306a36Sopenharmony_ci perm = data_race(container_of(ptr, struct tomoyo_unix_acl, head)->perm); 108662306a36Sopenharmony_ci break; 108762306a36Sopenharmony_ci case TOMOYO_TYPE_MANUAL_TASK_ACL: 108862306a36Sopenharmony_ci perm = 0; 108962306a36Sopenharmony_ci break; 109062306a36Sopenharmony_ci default: 109162306a36Sopenharmony_ci perm = 1; 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci count += hweight16(perm); 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci if (count < tomoyo_profile(domain->ns, domain->profile)-> 109662306a36Sopenharmony_ci pref[TOMOYO_PREF_MAX_LEARNING_ENTRY]) 109762306a36Sopenharmony_ci return true; 109862306a36Sopenharmony_ci WRITE_ONCE(domain->flags[TOMOYO_DIF_QUOTA_WARNED], true); 109962306a36Sopenharmony_ci /* r->granted = false; */ 110062306a36Sopenharmony_ci tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]); 110162306a36Sopenharmony_ci#ifndef CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING 110262306a36Sopenharmony_ci pr_warn("WARNING: Domain '%s' has too many ACLs to hold. Stopped learning mode.\n", 110362306a36Sopenharmony_ci domain->domainname->name); 110462306a36Sopenharmony_ci#endif 110562306a36Sopenharmony_ci return false; 110662306a36Sopenharmony_ci} 1107