xref: /aosp_15_r20/external/selinux/libselinux/src/mapping.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker /*
2*2d543d20SAndroid Build Coastguard Worker  * Class and permission mappings.
3*2d543d20SAndroid Build Coastguard Worker  */
4*2d543d20SAndroid Build Coastguard Worker 
5*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
6*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
7*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
8*2d543d20SAndroid Build Coastguard Worker #include <stdarg.h>
9*2d543d20SAndroid Build Coastguard Worker #include <stdbool.h>
10*2d543d20SAndroid Build Coastguard Worker #include <selinux/selinux.h>
11*2d543d20SAndroid Build Coastguard Worker #include <selinux/avc.h>
12*2d543d20SAndroid Build Coastguard Worker #include "callbacks.h"
13*2d543d20SAndroid Build Coastguard Worker #include "mapping.h"
14*2d543d20SAndroid Build Coastguard Worker #include "selinux_internal.h"
15*2d543d20SAndroid Build Coastguard Worker 
16*2d543d20SAndroid Build Coastguard Worker /*
17*2d543d20SAndroid Build Coastguard Worker  * Class and permission mappings
18*2d543d20SAndroid Build Coastguard Worker  */
19*2d543d20SAndroid Build Coastguard Worker 
20*2d543d20SAndroid Build Coastguard Worker struct selinux_mapping {
21*2d543d20SAndroid Build Coastguard Worker 	security_class_t value; /* real, kernel value */
22*2d543d20SAndroid Build Coastguard Worker 	unsigned num_perms;
23*2d543d20SAndroid Build Coastguard Worker 	access_vector_t perms[sizeof(access_vector_t) * 8];
24*2d543d20SAndroid Build Coastguard Worker };
25*2d543d20SAndroid Build Coastguard Worker 
26*2d543d20SAndroid Build Coastguard Worker static struct selinux_mapping *current_mapping = NULL;
27*2d543d20SAndroid Build Coastguard Worker static security_class_t current_mapping_size = 0;
28*2d543d20SAndroid Build Coastguard Worker 
29*2d543d20SAndroid Build Coastguard Worker /*
30*2d543d20SAndroid Build Coastguard Worker  * Mapping setting function
31*2d543d20SAndroid Build Coastguard Worker  */
32*2d543d20SAndroid Build Coastguard Worker 
33*2d543d20SAndroid Build Coastguard Worker int
selinux_set_mapping(const struct security_class_mapping * map)34*2d543d20SAndroid Build Coastguard Worker selinux_set_mapping(const struct security_class_mapping *map)
35*2d543d20SAndroid Build Coastguard Worker {
36*2d543d20SAndroid Build Coastguard Worker 	size_t size = sizeof(struct selinux_mapping);
37*2d543d20SAndroid Build Coastguard Worker 	security_class_t i, j;
38*2d543d20SAndroid Build Coastguard Worker 	unsigned k;
39*2d543d20SAndroid Build Coastguard Worker 	bool print_unknown_handle = false;
40*2d543d20SAndroid Build Coastguard Worker 	bool reject = (security_reject_unknown() == 1);
41*2d543d20SAndroid Build Coastguard Worker 	bool deny = (security_deny_unknown() == 1);
42*2d543d20SAndroid Build Coastguard Worker 
43*2d543d20SAndroid Build Coastguard Worker 	free(current_mapping);
44*2d543d20SAndroid Build Coastguard Worker 	current_mapping = NULL;
45*2d543d20SAndroid Build Coastguard Worker 	current_mapping_size = 0;
46*2d543d20SAndroid Build Coastguard Worker 
47*2d543d20SAndroid Build Coastguard Worker 	if (avc_reset() < 0)
48*2d543d20SAndroid Build Coastguard Worker 		goto err;
49*2d543d20SAndroid Build Coastguard Worker 
50*2d543d20SAndroid Build Coastguard Worker 	/* Find number of classes in the input mapping */
51*2d543d20SAndroid Build Coastguard Worker 	if (!map) {
52*2d543d20SAndroid Build Coastguard Worker 		errno = EINVAL;
53*2d543d20SAndroid Build Coastguard Worker 		goto err;
54*2d543d20SAndroid Build Coastguard Worker 	}
55*2d543d20SAndroid Build Coastguard Worker 	i = 0;
56*2d543d20SAndroid Build Coastguard Worker 	while (map[i].name)
57*2d543d20SAndroid Build Coastguard Worker 		i++;
58*2d543d20SAndroid Build Coastguard Worker 
59*2d543d20SAndroid Build Coastguard Worker 	/* Allocate space for the class records, plus one for class zero */
60*2d543d20SAndroid Build Coastguard Worker 	current_mapping = (struct selinux_mapping *)calloc(++i, size);
61*2d543d20SAndroid Build Coastguard Worker 	if (!current_mapping)
62*2d543d20SAndroid Build Coastguard Worker 		goto err;
63*2d543d20SAndroid Build Coastguard Worker 
64*2d543d20SAndroid Build Coastguard Worker 	/* Store the raw class and permission values */
65*2d543d20SAndroid Build Coastguard Worker 	j = 0;
66*2d543d20SAndroid Build Coastguard Worker 	while (map[j].name) {
67*2d543d20SAndroid Build Coastguard Worker 		const struct security_class_mapping *p_in = map + (j++);
68*2d543d20SAndroid Build Coastguard Worker 		struct selinux_mapping *p_out = current_mapping + j;
69*2d543d20SAndroid Build Coastguard Worker 
70*2d543d20SAndroid Build Coastguard Worker 		p_out->value = string_to_security_class(p_in->name);
71*2d543d20SAndroid Build Coastguard Worker 		if (!p_out->value) {
72*2d543d20SAndroid Build Coastguard Worker 			selinux_log(SELINUX_INFO,
73*2d543d20SAndroid Build Coastguard Worker 				    "SELinux: Class %s not defined in policy.\n",
74*2d543d20SAndroid Build Coastguard Worker 				    p_in->name);
75*2d543d20SAndroid Build Coastguard Worker 			if (reject)
76*2d543d20SAndroid Build Coastguard Worker 				goto err2;
77*2d543d20SAndroid Build Coastguard Worker 			p_out->num_perms = 0;
78*2d543d20SAndroid Build Coastguard Worker 			print_unknown_handle = true;
79*2d543d20SAndroid Build Coastguard Worker 			continue;
80*2d543d20SAndroid Build Coastguard Worker 		}
81*2d543d20SAndroid Build Coastguard Worker 
82*2d543d20SAndroid Build Coastguard Worker 		k = 0;
83*2d543d20SAndroid Build Coastguard Worker 		while (p_in->perms[k]) {
84*2d543d20SAndroid Build Coastguard Worker 			/* An empty permission string skips ahead */
85*2d543d20SAndroid Build Coastguard Worker 			if (!*p_in->perms[k]) {
86*2d543d20SAndroid Build Coastguard Worker 				k++;
87*2d543d20SAndroid Build Coastguard Worker 				continue;
88*2d543d20SAndroid Build Coastguard Worker 			}
89*2d543d20SAndroid Build Coastguard Worker 			p_out->perms[k] = string_to_av_perm(p_out->value,
90*2d543d20SAndroid Build Coastguard Worker 							    p_in->perms[k]);
91*2d543d20SAndroid Build Coastguard Worker 			if (!p_out->perms[k]) {
92*2d543d20SAndroid Build Coastguard Worker 				selinux_log(SELINUX_INFO,
93*2d543d20SAndroid Build Coastguard Worker 					    "SELinux:  Permission %s in class %s not defined in policy.\n",
94*2d543d20SAndroid Build Coastguard Worker 					    p_in->perms[k], p_in->name);
95*2d543d20SAndroid Build Coastguard Worker 				if (reject)
96*2d543d20SAndroid Build Coastguard Worker 					goto err2;
97*2d543d20SAndroid Build Coastguard Worker 				print_unknown_handle = true;
98*2d543d20SAndroid Build Coastguard Worker 			}
99*2d543d20SAndroid Build Coastguard Worker 			k++;
100*2d543d20SAndroid Build Coastguard Worker 		}
101*2d543d20SAndroid Build Coastguard Worker 		p_out->num_perms = k;
102*2d543d20SAndroid Build Coastguard Worker 	}
103*2d543d20SAndroid Build Coastguard Worker 
104*2d543d20SAndroid Build Coastguard Worker 	if (print_unknown_handle)
105*2d543d20SAndroid Build Coastguard Worker 		selinux_log(SELINUX_INFO,
106*2d543d20SAndroid Build Coastguard Worker 			    "SELinux: the above unknown classes and permissions will be %s\n",
107*2d543d20SAndroid Build Coastguard Worker 			    deny ? "denied" : "allowed");
108*2d543d20SAndroid Build Coastguard Worker 
109*2d543d20SAndroid Build Coastguard Worker 	/* Set the mapping size here so the above lookups are "raw" */
110*2d543d20SAndroid Build Coastguard Worker 	current_mapping_size = i;
111*2d543d20SAndroid Build Coastguard Worker 	return 0;
112*2d543d20SAndroid Build Coastguard Worker err2:
113*2d543d20SAndroid Build Coastguard Worker 	free(current_mapping);
114*2d543d20SAndroid Build Coastguard Worker 	current_mapping = NULL;
115*2d543d20SAndroid Build Coastguard Worker 	current_mapping_size = 0;
116*2d543d20SAndroid Build Coastguard Worker err:
117*2d543d20SAndroid Build Coastguard Worker 	return -1;
118*2d543d20SAndroid Build Coastguard Worker }
119*2d543d20SAndroid Build Coastguard Worker 
120*2d543d20SAndroid Build Coastguard Worker /*
121*2d543d20SAndroid Build Coastguard Worker  * Get real, kernel values from mapped values
122*2d543d20SAndroid Build Coastguard Worker  */
123*2d543d20SAndroid Build Coastguard Worker 
124*2d543d20SAndroid Build Coastguard Worker security_class_t
unmap_class(security_class_t tclass)125*2d543d20SAndroid Build Coastguard Worker unmap_class(security_class_t tclass)
126*2d543d20SAndroid Build Coastguard Worker {
127*2d543d20SAndroid Build Coastguard Worker 	if (tclass < current_mapping_size)
128*2d543d20SAndroid Build Coastguard Worker 		return current_mapping[tclass].value;
129*2d543d20SAndroid Build Coastguard Worker 
130*2d543d20SAndroid Build Coastguard Worker 	/* If here no mapping set or the class requested is not valid. */
131*2d543d20SAndroid Build Coastguard Worker 	if (current_mapping_size != 0) {
132*2d543d20SAndroid Build Coastguard Worker 		errno = EINVAL;
133*2d543d20SAndroid Build Coastguard Worker 		return 0;
134*2d543d20SAndroid Build Coastguard Worker 	}
135*2d543d20SAndroid Build Coastguard Worker 	else
136*2d543d20SAndroid Build Coastguard Worker 		return tclass;
137*2d543d20SAndroid Build Coastguard Worker }
138*2d543d20SAndroid Build Coastguard Worker 
139*2d543d20SAndroid Build Coastguard Worker access_vector_t
unmap_perm(security_class_t tclass,access_vector_t tperm)140*2d543d20SAndroid Build Coastguard Worker unmap_perm(security_class_t tclass, access_vector_t tperm)
141*2d543d20SAndroid Build Coastguard Worker {
142*2d543d20SAndroid Build Coastguard Worker 	if (tclass < current_mapping_size) {
143*2d543d20SAndroid Build Coastguard Worker 		unsigned i;
144*2d543d20SAndroid Build Coastguard Worker 		access_vector_t kperm = 0;
145*2d543d20SAndroid Build Coastguard Worker 
146*2d543d20SAndroid Build Coastguard Worker 		for (i = 0; i < current_mapping[tclass].num_perms; i++)
147*2d543d20SAndroid Build Coastguard Worker 			if (tperm & (UINT32_C(1)<<i)) {
148*2d543d20SAndroid Build Coastguard Worker 				kperm |= current_mapping[tclass].perms[i];
149*2d543d20SAndroid Build Coastguard Worker 				tperm &= ~(UINT32_C(1)<<i);
150*2d543d20SAndroid Build Coastguard Worker 			}
151*2d543d20SAndroid Build Coastguard Worker 		return kperm;
152*2d543d20SAndroid Build Coastguard Worker 	}
153*2d543d20SAndroid Build Coastguard Worker 
154*2d543d20SAndroid Build Coastguard Worker 	/* If here no mapping set or the perm requested is not valid. */
155*2d543d20SAndroid Build Coastguard Worker 	if (current_mapping_size != 0) {
156*2d543d20SAndroid Build Coastguard Worker 		errno = EINVAL;
157*2d543d20SAndroid Build Coastguard Worker 		return 0;
158*2d543d20SAndroid Build Coastguard Worker 	}
159*2d543d20SAndroid Build Coastguard Worker 	else
160*2d543d20SAndroid Build Coastguard Worker 		return tperm;
161*2d543d20SAndroid Build Coastguard Worker }
162*2d543d20SAndroid Build Coastguard Worker 
163*2d543d20SAndroid Build Coastguard Worker /*
164*2d543d20SAndroid Build Coastguard Worker  * Get mapped values from real, kernel values
165*2d543d20SAndroid Build Coastguard Worker  */
166*2d543d20SAndroid Build Coastguard Worker 
167*2d543d20SAndroid Build Coastguard Worker security_class_t
map_class(security_class_t kclass)168*2d543d20SAndroid Build Coastguard Worker map_class(security_class_t kclass)
169*2d543d20SAndroid Build Coastguard Worker {
170*2d543d20SAndroid Build Coastguard Worker 	security_class_t i;
171*2d543d20SAndroid Build Coastguard Worker 
172*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < current_mapping_size; i++)
173*2d543d20SAndroid Build Coastguard Worker 		if (current_mapping[i].value == kclass)
174*2d543d20SAndroid Build Coastguard Worker 			return i;
175*2d543d20SAndroid Build Coastguard Worker 
176*2d543d20SAndroid Build Coastguard Worker /* If here no mapping set or the class requested is not valid. */
177*2d543d20SAndroid Build Coastguard Worker 	if (current_mapping_size != 0) {
178*2d543d20SAndroid Build Coastguard Worker 		errno = EINVAL;
179*2d543d20SAndroid Build Coastguard Worker 		return 0;
180*2d543d20SAndroid Build Coastguard Worker 	}
181*2d543d20SAndroid Build Coastguard Worker 	else
182*2d543d20SAndroid Build Coastguard Worker 		return kclass;
183*2d543d20SAndroid Build Coastguard Worker }
184*2d543d20SAndroid Build Coastguard Worker 
185*2d543d20SAndroid Build Coastguard Worker access_vector_t
map_perm(security_class_t tclass,access_vector_t kperm)186*2d543d20SAndroid Build Coastguard Worker map_perm(security_class_t tclass, access_vector_t kperm)
187*2d543d20SAndroid Build Coastguard Worker {
188*2d543d20SAndroid Build Coastguard Worker 	if (tclass < current_mapping_size) {
189*2d543d20SAndroid Build Coastguard Worker 		unsigned i;
190*2d543d20SAndroid Build Coastguard Worker 		access_vector_t tperm = 0;
191*2d543d20SAndroid Build Coastguard Worker 
192*2d543d20SAndroid Build Coastguard Worker 		for (i = 0; i < current_mapping[tclass].num_perms; i++)
193*2d543d20SAndroid Build Coastguard Worker 			if (kperm & current_mapping[tclass].perms[i]) {
194*2d543d20SAndroid Build Coastguard Worker 				tperm |= UINT32_C(1)<<i;
195*2d543d20SAndroid Build Coastguard Worker 				kperm &= ~current_mapping[tclass].perms[i];
196*2d543d20SAndroid Build Coastguard Worker 			}
197*2d543d20SAndroid Build Coastguard Worker 
198*2d543d20SAndroid Build Coastguard Worker 		if (tperm == 0) {
199*2d543d20SAndroid Build Coastguard Worker 			errno = EINVAL;
200*2d543d20SAndroid Build Coastguard Worker 			return 0;
201*2d543d20SAndroid Build Coastguard Worker 		}
202*2d543d20SAndroid Build Coastguard Worker 		else
203*2d543d20SAndroid Build Coastguard Worker 			return tperm;
204*2d543d20SAndroid Build Coastguard Worker 	}
205*2d543d20SAndroid Build Coastguard Worker 	return kperm;
206*2d543d20SAndroid Build Coastguard Worker }
207*2d543d20SAndroid Build Coastguard Worker 
208*2d543d20SAndroid Build Coastguard Worker void
map_decision(security_class_t tclass,struct av_decision * avd)209*2d543d20SAndroid Build Coastguard Worker map_decision(security_class_t tclass, struct av_decision *avd)
210*2d543d20SAndroid Build Coastguard Worker {
211*2d543d20SAndroid Build Coastguard Worker 	if (tclass < current_mapping_size) {
212*2d543d20SAndroid Build Coastguard Worker 		bool allow_unknown = (security_deny_unknown() == 0);
213*2d543d20SAndroid Build Coastguard Worker 		struct selinux_mapping *mapping = &current_mapping[tclass];
214*2d543d20SAndroid Build Coastguard Worker 		unsigned int i, n = mapping->num_perms;
215*2d543d20SAndroid Build Coastguard Worker 		access_vector_t result;
216*2d543d20SAndroid Build Coastguard Worker 
217*2d543d20SAndroid Build Coastguard Worker 		for (i = 0, result = 0; i < n; i++) {
218*2d543d20SAndroid Build Coastguard Worker 			if (avd->allowed & mapping->perms[i])
219*2d543d20SAndroid Build Coastguard Worker 				result |= UINT32_C(1)<<i;
220*2d543d20SAndroid Build Coastguard Worker 			else if (allow_unknown && !mapping->perms[i])
221*2d543d20SAndroid Build Coastguard Worker 				result |= UINT32_C(1)<<i;
222*2d543d20SAndroid Build Coastguard Worker 		}
223*2d543d20SAndroid Build Coastguard Worker 		avd->allowed = result;
224*2d543d20SAndroid Build Coastguard Worker 
225*2d543d20SAndroid Build Coastguard Worker 		for (i = 0, result = 0; i < n; i++) {
226*2d543d20SAndroid Build Coastguard Worker 			if (avd->decided & mapping->perms[i])
227*2d543d20SAndroid Build Coastguard Worker 				result |= UINT32_C(1)<<i;
228*2d543d20SAndroid Build Coastguard Worker 			else if (allow_unknown && !mapping->perms[i])
229*2d543d20SAndroid Build Coastguard Worker 				result |= UINT32_C(1)<<i;
230*2d543d20SAndroid Build Coastguard Worker 		}
231*2d543d20SAndroid Build Coastguard Worker 		avd->decided = result;
232*2d543d20SAndroid Build Coastguard Worker 
233*2d543d20SAndroid Build Coastguard Worker 		for (i = 0, result = 0; i < n; i++)
234*2d543d20SAndroid Build Coastguard Worker 			if (avd->auditallow & mapping->perms[i])
235*2d543d20SAndroid Build Coastguard Worker 				result |= UINT32_C(1)<<i;
236*2d543d20SAndroid Build Coastguard Worker 		avd->auditallow = result;
237*2d543d20SAndroid Build Coastguard Worker 
238*2d543d20SAndroid Build Coastguard Worker 		for (i = 0, result = 0; i < n; i++) {
239*2d543d20SAndroid Build Coastguard Worker 			if (avd->auditdeny & mapping->perms[i])
240*2d543d20SAndroid Build Coastguard Worker 				result |= UINT32_C(1)<<i;
241*2d543d20SAndroid Build Coastguard Worker 			else if (!allow_unknown && !mapping->perms[i])
242*2d543d20SAndroid Build Coastguard Worker 				result |= UINT32_C(1)<<i;
243*2d543d20SAndroid Build Coastguard Worker 		}
244*2d543d20SAndroid Build Coastguard Worker 
245*2d543d20SAndroid Build Coastguard Worker 		/*
246*2d543d20SAndroid Build Coastguard Worker 		 * Make sure we audit denials for any permission check
247*2d543d20SAndroid Build Coastguard Worker 		 * beyond the mapping->num_perms since this indicates
248*2d543d20SAndroid Build Coastguard Worker 		 * a bug in the object manager.
249*2d543d20SAndroid Build Coastguard Worker 		 */
250*2d543d20SAndroid Build Coastguard Worker 		for (; i < (sizeof(result)*8); i++)
251*2d543d20SAndroid Build Coastguard Worker 			result |= UINT32_C(1)<<i;
252*2d543d20SAndroid Build Coastguard Worker 		avd->auditdeny = result;
253*2d543d20SAndroid Build Coastguard Worker 	}
254*2d543d20SAndroid Build Coastguard Worker }
255