1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * security/tomoyo/group.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 /** 14 * tomoyo_same_path_group - Check for duplicated "struct tomoyo_path_group" entry. 15 * 16 * @a: Pointer to "struct tomoyo_acl_head". 17 * @b: Pointer to "struct tomoyo_acl_head". 18 * 19 * Returns true if @a == @b, false otherwise. 20 */ 21 static bool tomoyo_same_path_group(const struct tomoyo_acl_head *a, 22 const struct tomoyo_acl_head *b) 23 { 24 return container_of(a, struct tomoyo_path_group, head)->member_name == 25 container_of(b, struct tomoyo_path_group, head)->member_name; 26 } 27 28 /** 29 * tomoyo_same_number_group - Check for duplicated "struct tomoyo_number_group" entry. 30 * 31 * @a: Pointer to "struct tomoyo_acl_head". 32 * @b: Pointer to "struct tomoyo_acl_head". 33 * 34 * Returns true if @a == @b, false otherwise. 35 */ 36 static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a, 37 const struct tomoyo_acl_head *b) 38 { 39 return !memcmp(&container_of(a, struct tomoyo_number_group, head) 40 ->number, 41 &container_of(b, struct tomoyo_number_group, head) 42 ->number, 43 sizeof(container_of(a, struct tomoyo_number_group, head) 44 ->number)); 45 } 46 47 /** 48 * tomoyo_same_address_group - Check for duplicated "struct tomoyo_address_group" entry. 49 * 50 * @a: Pointer to "struct tomoyo_acl_head". 51 * @b: Pointer to "struct tomoyo_acl_head". 52 * 53 * Returns true if @a == @b, false otherwise. 54 */ 55 static bool tomoyo_same_address_group(const struct tomoyo_acl_head *a, 56 const struct tomoyo_acl_head *b) 57 { 58 const struct tomoyo_address_group *p1 = container_of(a, typeof(*p1), 59 head); 60 const struct tomoyo_address_group *p2 = container_of(b, typeof(*p2), 61 head); 62 63 return tomoyo_same_ipaddr_union(&p1->address, &p2->address); 64 } 65 66 /** 67 * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list. 68 * 69 * @param: Pointer to "struct tomoyo_acl_param". 70 * @type: Type of this group. 71 * 72 * Returns 0 on success, negative value otherwise. 73 */ 74 int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type) 75 { 76 struct tomoyo_group *group = tomoyo_get_group(param, type); 77 int error = -EINVAL; 78 79 if (!group) 80 return -ENOMEM; 81 param->list = &group->member_list; 82 if (type == TOMOYO_PATH_GROUP) { 83 struct tomoyo_path_group e = { }; 84 85 e.member_name = tomoyo_get_name(tomoyo_read_token(param)); 86 if (!e.member_name) { 87 error = -ENOMEM; 88 goto out; 89 } 90 error = tomoyo_update_policy(&e.head, sizeof(e), param, 91 tomoyo_same_path_group); 92 tomoyo_put_name(e.member_name); 93 } else if (type == TOMOYO_NUMBER_GROUP) { 94 struct tomoyo_number_group e = { }; 95 96 if (param->data[0] == '@' || 97 !tomoyo_parse_number_union(param, &e.number)) 98 goto out; 99 error = tomoyo_update_policy(&e.head, sizeof(e), param, 100 tomoyo_same_number_group); 101 /* 102 * tomoyo_put_number_union() is not needed because 103 * param->data[0] != '@'. 104 */ 105 } else { 106 struct tomoyo_address_group e = { }; 107 108 if (param->data[0] == '@' || 109 !tomoyo_parse_ipaddr_union(param, &e.address)) 110 goto out; 111 error = tomoyo_update_policy(&e.head, sizeof(e), param, 112 tomoyo_same_address_group); 113 } 114 out: 115 tomoyo_put_group(group); 116 return error; 117 } 118 119 /** 120 * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group. 121 * 122 * @pathname: The name of pathname. 123 * @group: Pointer to "struct tomoyo_path_group". 124 * 125 * Returns matched member's pathname if @pathname matches pathnames in @group, 126 * NULL otherwise. 127 * 128 * Caller holds tomoyo_read_lock(). 129 */ 130 const struct tomoyo_path_info * 131 tomoyo_path_matches_group(const struct tomoyo_path_info *pathname, 132 const struct tomoyo_group *group) 133 { 134 struct tomoyo_path_group *member; 135 136 list_for_each_entry_rcu(member, &group->member_list, head.list, 137 srcu_read_lock_held(&tomoyo_ss)) { 138 if (member->head.is_deleted) 139 continue; 140 if (!tomoyo_path_matches_pattern(pathname, member->member_name)) 141 continue; 142 return member->member_name; 143 } 144 return NULL; 145 } 146 147 /** 148 * tomoyo_number_matches_group - Check whether the given number matches members of the given number group. 149 * 150 * @min: Min number. 151 * @max: Max number. 152 * @group: Pointer to "struct tomoyo_number_group". 153 * 154 * Returns true if @min and @max partially overlaps @group, false otherwise. 155 * 156 * Caller holds tomoyo_read_lock(). 157 */ 158 bool tomoyo_number_matches_group(const unsigned long min, 159 const unsigned long max, 160 const struct tomoyo_group *group) 161 { 162 struct tomoyo_number_group *member; 163 bool matched = false; 164 165 list_for_each_entry_rcu(member, &group->member_list, head.list, 166 srcu_read_lock_held(&tomoyo_ss)) { 167 if (member->head.is_deleted) 168 continue; 169 if (min > member->number.values[1] || 170 max < member->number.values[0]) 171 continue; 172 matched = true; 173 break; 174 } 175 return matched; 176 } 177 178 /** 179 * tomoyo_address_matches_group - Check whether the given address matches members of the given address group. 180 * 181 * @is_ipv6: True if @address is an IPv6 address. 182 * @address: An IPv4 or IPv6 address. 183 * @group: Pointer to "struct tomoyo_address_group". 184 * 185 * Returns true if @address matches addresses in @group group, false otherwise. 186 * 187 * Caller holds tomoyo_read_lock(). 188 */ 189 bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address, 190 const struct tomoyo_group *group) 191 { 192 struct tomoyo_address_group *member; 193 bool matched = false; 194 const u8 size = is_ipv6 ? 16 : 4; 195 196 list_for_each_entry_rcu(member, &group->member_list, head.list, 197 srcu_read_lock_held(&tomoyo_ss)) { 198 if (member->head.is_deleted) 199 continue; 200 if (member->address.is_ipv6 != is_ipv6) 201 continue; 202 if (memcmp(&member->address.ip[0], address, size) > 0 || 203 memcmp(address, &member->address.ip[1], size) > 0) 204 continue; 205 matched = true; 206 break; 207 } 208 return matched; 209 } 210