18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * security/tomoyo/group.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/** 148c2ecf20Sopenharmony_ci * tomoyo_same_path_group - Check for duplicated "struct tomoyo_path_group" entry. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * @a: Pointer to "struct tomoyo_acl_head". 178c2ecf20Sopenharmony_ci * @b: Pointer to "struct tomoyo_acl_head". 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Returns true if @a == @b, false otherwise. 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_cistatic bool tomoyo_same_path_group(const struct tomoyo_acl_head *a, 228c2ecf20Sopenharmony_ci const struct tomoyo_acl_head *b) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci return container_of(a, struct tomoyo_path_group, head)->member_name == 258c2ecf20Sopenharmony_ci container_of(b, struct tomoyo_path_group, head)->member_name; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/** 298c2ecf20Sopenharmony_ci * tomoyo_same_number_group - Check for duplicated "struct tomoyo_number_group" entry. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * @a: Pointer to "struct tomoyo_acl_head". 328c2ecf20Sopenharmony_ci * @b: Pointer to "struct tomoyo_acl_head". 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * Returns true if @a == @b, false otherwise. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_cistatic bool tomoyo_same_number_group(const struct tomoyo_acl_head *a, 378c2ecf20Sopenharmony_ci const struct tomoyo_acl_head *b) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci return !memcmp(&container_of(a, struct tomoyo_number_group, head) 408c2ecf20Sopenharmony_ci ->number, 418c2ecf20Sopenharmony_ci &container_of(b, struct tomoyo_number_group, head) 428c2ecf20Sopenharmony_ci ->number, 438c2ecf20Sopenharmony_ci sizeof(container_of(a, struct tomoyo_number_group, head) 448c2ecf20Sopenharmony_ci ->number)); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/** 488c2ecf20Sopenharmony_ci * tomoyo_same_address_group - Check for duplicated "struct tomoyo_address_group" entry. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * @a: Pointer to "struct tomoyo_acl_head". 518c2ecf20Sopenharmony_ci * @b: Pointer to "struct tomoyo_acl_head". 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * Returns true if @a == @b, false otherwise. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_cistatic bool tomoyo_same_address_group(const struct tomoyo_acl_head *a, 568c2ecf20Sopenharmony_ci const struct tomoyo_acl_head *b) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci const struct tomoyo_address_group *p1 = container_of(a, typeof(*p1), 598c2ecf20Sopenharmony_ci head); 608c2ecf20Sopenharmony_ci const struct tomoyo_address_group *p2 = container_of(b, typeof(*p2), 618c2ecf20Sopenharmony_ci head); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return tomoyo_same_ipaddr_union(&p1->address, &p2->address); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/** 678c2ecf20Sopenharmony_ci * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list. 688c2ecf20Sopenharmony_ci * 698c2ecf20Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param". 708c2ecf20Sopenharmony_ci * @type: Type of this group. 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * Returns 0 on success, negative value otherwise. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ciint tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct tomoyo_group *group = tomoyo_get_group(param, type); 778c2ecf20Sopenharmony_ci int error = -EINVAL; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (!group) 808c2ecf20Sopenharmony_ci return -ENOMEM; 818c2ecf20Sopenharmony_ci param->list = &group->member_list; 828c2ecf20Sopenharmony_ci if (type == TOMOYO_PATH_GROUP) { 838c2ecf20Sopenharmony_ci struct tomoyo_path_group e = { }; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci e.member_name = tomoyo_get_name(tomoyo_read_token(param)); 868c2ecf20Sopenharmony_ci if (!e.member_name) { 878c2ecf20Sopenharmony_ci error = -ENOMEM; 888c2ecf20Sopenharmony_ci goto out; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci error = tomoyo_update_policy(&e.head, sizeof(e), param, 918c2ecf20Sopenharmony_ci tomoyo_same_path_group); 928c2ecf20Sopenharmony_ci tomoyo_put_name(e.member_name); 938c2ecf20Sopenharmony_ci } else if (type == TOMOYO_NUMBER_GROUP) { 948c2ecf20Sopenharmony_ci struct tomoyo_number_group e = { }; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (param->data[0] == '@' || 978c2ecf20Sopenharmony_ci !tomoyo_parse_number_union(param, &e.number)) 988c2ecf20Sopenharmony_ci goto out; 998c2ecf20Sopenharmony_ci error = tomoyo_update_policy(&e.head, sizeof(e), param, 1008c2ecf20Sopenharmony_ci tomoyo_same_number_group); 1018c2ecf20Sopenharmony_ci /* 1028c2ecf20Sopenharmony_ci * tomoyo_put_number_union() is not needed because 1038c2ecf20Sopenharmony_ci * param->data[0] != '@'. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci } else { 1068c2ecf20Sopenharmony_ci struct tomoyo_address_group e = { }; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (param->data[0] == '@' || 1098c2ecf20Sopenharmony_ci !tomoyo_parse_ipaddr_union(param, &e.address)) 1108c2ecf20Sopenharmony_ci goto out; 1118c2ecf20Sopenharmony_ci error = tomoyo_update_policy(&e.head, sizeof(e), param, 1128c2ecf20Sopenharmony_ci tomoyo_same_address_group); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ciout: 1158c2ecf20Sopenharmony_ci tomoyo_put_group(group); 1168c2ecf20Sopenharmony_ci return error; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/** 1208c2ecf20Sopenharmony_ci * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group. 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * @pathname: The name of pathname. 1238c2ecf20Sopenharmony_ci * @group: Pointer to "struct tomoyo_path_group". 1248c2ecf20Sopenharmony_ci * 1258c2ecf20Sopenharmony_ci * Returns matched member's pathname if @pathname matches pathnames in @group, 1268c2ecf20Sopenharmony_ci * NULL otherwise. 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock(). 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ciconst struct tomoyo_path_info * 1318c2ecf20Sopenharmony_citomoyo_path_matches_group(const struct tomoyo_path_info *pathname, 1328c2ecf20Sopenharmony_ci const struct tomoyo_group *group) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct tomoyo_path_group *member; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci list_for_each_entry_rcu(member, &group->member_list, head.list, 1378c2ecf20Sopenharmony_ci srcu_read_lock_held(&tomoyo_ss)) { 1388c2ecf20Sopenharmony_ci if (member->head.is_deleted) 1398c2ecf20Sopenharmony_ci continue; 1408c2ecf20Sopenharmony_ci if (!tomoyo_path_matches_pattern(pathname, member->member_name)) 1418c2ecf20Sopenharmony_ci continue; 1428c2ecf20Sopenharmony_ci return member->member_name; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci return NULL; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/** 1488c2ecf20Sopenharmony_ci * tomoyo_number_matches_group - Check whether the given number matches members of the given number group. 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * @min: Min number. 1518c2ecf20Sopenharmony_ci * @max: Max number. 1528c2ecf20Sopenharmony_ci * @group: Pointer to "struct tomoyo_number_group". 1538c2ecf20Sopenharmony_ci * 1548c2ecf20Sopenharmony_ci * Returns true if @min and @max partially overlaps @group, false otherwise. 1558c2ecf20Sopenharmony_ci * 1568c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock(). 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_cibool tomoyo_number_matches_group(const unsigned long min, 1598c2ecf20Sopenharmony_ci const unsigned long max, 1608c2ecf20Sopenharmony_ci const struct tomoyo_group *group) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct tomoyo_number_group *member; 1638c2ecf20Sopenharmony_ci bool matched = false; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci list_for_each_entry_rcu(member, &group->member_list, head.list, 1668c2ecf20Sopenharmony_ci srcu_read_lock_held(&tomoyo_ss)) { 1678c2ecf20Sopenharmony_ci if (member->head.is_deleted) 1688c2ecf20Sopenharmony_ci continue; 1698c2ecf20Sopenharmony_ci if (min > member->number.values[1] || 1708c2ecf20Sopenharmony_ci max < member->number.values[0]) 1718c2ecf20Sopenharmony_ci continue; 1728c2ecf20Sopenharmony_ci matched = true; 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci return matched; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/** 1798c2ecf20Sopenharmony_ci * tomoyo_address_matches_group - Check whether the given address matches members of the given address group. 1808c2ecf20Sopenharmony_ci * 1818c2ecf20Sopenharmony_ci * @is_ipv6: True if @address is an IPv6 address. 1828c2ecf20Sopenharmony_ci * @address: An IPv4 or IPv6 address. 1838c2ecf20Sopenharmony_ci * @group: Pointer to "struct tomoyo_address_group". 1848c2ecf20Sopenharmony_ci * 1858c2ecf20Sopenharmony_ci * Returns true if @address matches addresses in @group group, false otherwise. 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock(). 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_cibool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address, 1908c2ecf20Sopenharmony_ci const struct tomoyo_group *group) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct tomoyo_address_group *member; 1938c2ecf20Sopenharmony_ci bool matched = false; 1948c2ecf20Sopenharmony_ci const u8 size = is_ipv6 ? 16 : 4; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci list_for_each_entry_rcu(member, &group->member_list, head.list, 1978c2ecf20Sopenharmony_ci srcu_read_lock_held(&tomoyo_ss)) { 1988c2ecf20Sopenharmony_ci if (member->head.is_deleted) 1998c2ecf20Sopenharmony_ci continue; 2008c2ecf20Sopenharmony_ci if (member->address.is_ipv6 != is_ipv6) 2018c2ecf20Sopenharmony_ci continue; 2028c2ecf20Sopenharmony_ci if (memcmp(&member->address.ip[0], address, size) > 0 || 2038c2ecf20Sopenharmony_ci memcmp(address, &member->address.ip[1], size) > 0) 2048c2ecf20Sopenharmony_ci continue; 2058c2ecf20Sopenharmony_ci matched = true; 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci return matched; 2098c2ecf20Sopenharmony_ci} 210