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